xref: /DragonOS/kernel/src/arch/x86_64/asm/head.S (revision 59a6bcf6aee15a11a16431bdf875905c5ecf9157)
111f78b73SLoGin// 这是内核执行头程序
211f78b73SLoGin// Created by longjin.
311f78b73SLoGin// 2022/01/20
411f78b73SLoGin
511f78b73SLoGin#include "common/asm.h"
63959e94dS曾俊#include <asm/apu_boot.h>
711f78b73SLoGin
811f78b73SLoGin// 以下是来自 multiboot2 规范的定义
911f78b73SLoGin//  How many bytes from the start of the file we search for the header.
10db7c782aSLoGin#define MULTIBOOT2_SEARCH 32768
11db7c782aSLoGin#define MULTIBOOT2_HEADER_ALIGN 8
1211f78b73SLoGin
1311f78b73SLoGin//  The magic field should contain this.
1411f78b73SLoGin#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
1511f78b73SLoGin
162b7818e8SLoGin
1711f78b73SLoGin
1811f78b73SLoGin//  Alignment of multiboot modules.
19db7c782aSLoGin#define MULTIBOOT2_MOD_ALIGN 0x00001000
2011f78b73SLoGin
2111f78b73SLoGin//  Alignment of the multiboot info structure.
22db7c782aSLoGin#define MULTIBOOT2_INFO_ALIGN 0x00000008
2311f78b73SLoGin
2411f78b73SLoGin//  Flags set in the 'flags' member of the multiboot header.
2511f78b73SLoGin
26db7c782aSLoGin#define MULTIBOOT2_TAG_ALIGN 8
27db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_END 0
28db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_CMDLINE 1
29db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2
30db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_MODULE 3
31db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4
32db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_BOOTDEV 5
33db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_MMAP 6
34db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_VBE 7
35db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8
36db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9
37db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_APM 10
38db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI32 11
39db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI64 12
40db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_SMBIOS 13
41db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14
42db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15
43db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_NETWORK 16
44db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17
45db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI_BS 18
46db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI32_IH 19
47db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_EFI64_IH 20
48db7c782aSLoGin#define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21
4911f78b73SLoGin
50db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_END 0
51db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1
52db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_ADDRESS 2
53db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3
54db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4
55db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5
56db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6
57db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_EFI_BS 7
58db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
59db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
60db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10
6111f78b73SLoGin
62db7c782aSLoGin#define MULTIBOOT2_ARCHITECTURE_I386 0
63db7c782aSLoGin#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
64db7c782aSLoGin#define MULTIBOOT2_HEADER_TAG_OPTIONAL 1
6511f78b73SLoGin
66db7c782aSLoGin#define MULTIBOOT2_LOAD_PREFERENCE_NONE 0
67db7c782aSLoGin#define MULTIBOOT2_LOAD_PREFERENCE_LOW 1
68db7c782aSLoGin#define MULTIBOOT2_LOAD_PREFERENCE_HIGH 2
6911f78b73SLoGin
70db7c782aSLoGin#define MULTIBOOT2_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
71db7c782aSLoGin#define MULTIBOOT2_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
7211f78b73SLoGin
732b7818e8SLoGin//  This should be in %eax.
742b7818e8SLoGin#define MULTIBOOT_BOOTLOADER_MAGIC 0x2badb002
752b7818e8SLoGin#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
7611f78b73SLoGin
772b7818e8SLoGin// 存储到boot_entry_type的值
782b7818e8SLoGin#define BOOT_ENTRY_TYPE_MULTIBOOT 1
792b7818e8SLoGin#define BOOT_ENTRY_TYPE_MULTIBOOT2  2
802b7818e8SLoGin#define BOOT_ENTRY_TYPE_LINUX_32  3
812b7818e8SLoGin#define BOOT_ENTRY_TYPE_LINUX_64  4
82*59a6bcf6SLoGin#define BOOT_ENTRY_TYPE_LINUX_32_PVH 5
8311f78b73SLoGin
8411f78b73SLoGin// 直接用 -m64 编译出来的是 64 位代码,
8511f78b73SLoGin// 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。
8611f78b73SLoGin// 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中
8711f78b73SLoGin// 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表
8811f78b73SLoGin// See https://wiki.osdev.org/Creating_a_64-bit_kernel:
8911f78b73SLoGin// With a 32-bit bootstrap in your kernel
9011f78b73SLoGin
9111f78b73SLoGin// 这部分是从保护模式启动 long 模式的代码
9211f78b73SLoGin// 工作在 32bit
9311f78b73SLoGin// 声明这一段代码以 32 位模式编译
9411f78b73SLoGin.code32
9511f78b73SLoGin
96*59a6bcf6SLoGin/* PVH Header with pvh_start_addr = __linux32_pvh_boot */
97*59a6bcf6SLoGin
98*59a6bcf6SLoGin	.pushsection .note.dragonos, "a", @note
99*59a6bcf6SLoGin	.align 4
100*59a6bcf6SLoGin	.long 2f - 1f
101*59a6bcf6SLoGin	.long 4f - 3f
102*59a6bcf6SLoGin	.long 18
103*59a6bcf6SLoGin	1:.asciz "Xen"
104*59a6bcf6SLoGin	2:.align 4
105*59a6bcf6SLoGin	3:.long __linux32_pvh_boot
106*59a6bcf6SLoGin	4:.align 4
107*59a6bcf6SLoGin	.popsection
108*59a6bcf6SLoGin
1092b7818e8SLoGin.section ".multiboot_header", "a"
1102b7818e8SLoGin
111db7c782aSLoGin#define MB_FLAGS_FB 0x4
112db7c782aSLoGin
113db7c782aSLoGin// reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-graphics-fields
114db7c782aSLoGin#define MB_HEADER_GRAPHIC_MODE_LINEAR 0
115db7c782aSLoGin#define MB_HEADER_GRAPHIC_MODE_TEXT 1
116db7c782aSLoGin
1172b7818e8SLoGinMB_MAGIC = 0x1BADB002
118db7c782aSLoGinMB_FLAGS = MB_FLAGS_FB
1192b7818e8SLoGinMB_CHECKSUM = -(MB_MAGIC + MB_FLAGS)
1202b7818e8SLoGin
1212b7818e8SLoGin
12211f78b73SLoGin// multiboot2 文件头
12311f78b73SLoGin// 计算头长度
1242b7818e8SLoGin.SET MB2_HEADER_LENGTH, multiboot2_header_end - multiboot2_header
12511f78b73SLoGin// 计算校验和
126db7c782aSLoGin.SET MB2_CHECKSUM, -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + MB2_HEADER_LENGTH)
12711f78b73SLoGin// 8 字节对齐
1282b7818e8SLoGin.code32
1292b7818e8SLoGin.section .multiboot2_header
130db7c782aSLoGin.align MULTIBOOT2_HEADER_ALIGN
13111f78b73SLoGin// 声明所属段
13211f78b73SLoGin
1332b7818e8SLoGinmultiboot2_header:
13411f78b73SLoGin    // 魔数
13511f78b73SLoGin    .long MULTIBOOT2_HEADER_MAGIC
13611f78b73SLoGin    // 架构
137db7c782aSLoGin    .long MULTIBOOT2_ARCHITECTURE_I386
13811f78b73SLoGin    // 头长度
1392b7818e8SLoGin    .long MB2_HEADER_LENGTH
14011f78b73SLoGin    // 校验和
1412b7818e8SLoGin    .long MB2_CHECKSUM
14211f78b73SLoGin    // 添加其它内容在此,详细信息见 Multiboot2 Specification version 2.0.pdf
14311f78b73SLoGin
14411f78b73SLoGin// 设置帧缓冲区(同时在这里设置qemu的分辨率, 默认为: 1440*900, 还支持: 640*480, 等)
14511f78b73SLoGin.align 8
14611f78b73SLoGinframebuffer_tag_start:
147db7c782aSLoGin    .short MULTIBOOT2_HEADER_TAG_FRAMEBUFFER
148db7c782aSLoGin    .short MULTIBOOT2_HEADER_TAG_OPTIONAL
14911f78b73SLoGin    .long framebuffer_tag_end - framebuffer_tag_start
15011f78b73SLoGin    .long 1440   // 宽
15111f78b73SLoGin    .long 900   // 高
15211f78b73SLoGin    .long 32
15311f78b73SLoGinframebuffer_tag_end:
15411f78b73SLoGin.align 8
155db7c782aSLoGin	.short MULTIBOOT2_HEADER_TAG_END
15611f78b73SLoGin    // 结束标记
15711f78b73SLoGin    .short 0
15811f78b73SLoGin    .long 8
1592b7818e8SLoGinmultiboot2_header_end:
16011f78b73SLoGin
161*59a6bcf6SLoGin// direct_linux32_boot启动的内核入口
162*59a6bcf6SLoGin.section .bootstrap, "a"
163*59a6bcf6SLoGin.code32
164*59a6bcf6SLoGin.global __linux32_pvh_boot
165*59a6bcf6SLoGin__linux32_pvh_boot:
166*59a6bcf6SLoGin    cli
167*59a6bcf6SLoGin    cld
168*59a6bcf6SLoGin    // start info 指针
169*59a6bcf6SLoGin    mov %ebx, mb_entry_info
170*59a6bcf6SLoGin    mov $BOOT_ENTRY_TYPE_LINUX_32_PVH, %ebx
171*59a6bcf6SLoGin    mov %ebx, boot_entry_type
172*59a6bcf6SLoGin    jmp protected_mode_setup
173*59a6bcf6SLoGin
174*59a6bcf6SLoGin.code32
17511f78b73SLoGin
1762b7818e8SLoGin
17711f78b73SLoGin.global _start
17811f78b73SLoGin.type _start, @function
17911f78b73SLoGin
18011f78b73SLoGin.extern _start64
18111f78b73SLoGin.extern boot_info_addr
18211f78b73SLoGin.extern multiboot2_magic
18311f78b73SLoGinENTRY(_start)
18411f78b73SLoGin    // 关中断
18511f78b73SLoGin    cli
18611f78b73SLoGin
1872b7818e8SLoGin    // multiboot2_info/ multiboot_info 结构体指针
1882b7818e8SLoGin    mov %ebx, mb_entry_info
18911f78b73SLoGin    //mov %ebx, %e8
1902b7818e8SLoGin    // multiboot魔数
1912b7818e8SLoGin    mov %eax, mb_entry_magic
19211f78b73SLoGin
1932b7818e8SLoGin    mov $MULTIBOOT_BOOTLOADER_MAGIC, %ebx
1942b7818e8SLoGin    cmp %eax, %ebx
1952b7818e8SLoGin    je bl_magic_is_mb
1962b7818e8SLoGin    mov $MULTIBOOT2_BOOTLOADER_MAGIC, %ebx
1972b7818e8SLoGin    cmp %eax, %ebx
1982b7818e8SLoGin    je bl_magic_is_mb2
1992b7818e8SLoGin    jmp halt // unreachable
2002b7818e8SLoGin
2012b7818e8SLoGinbl_magic_is_mb:
2022b7818e8SLoGin    mov $BOOT_ENTRY_TYPE_MULTIBOOT, %ebx
2032b7818e8SLoGin    mov %ebx, boot_entry_type
2042b7818e8SLoGin    jmp protected_mode_setup
2052b7818e8SLoGinbl_magic_is_mb2:
2062b7818e8SLoGin    mov $BOOT_ENTRY_TYPE_MULTIBOOT2, %ebx
2072b7818e8SLoGin    mov %ebx, boot_entry_type
2082b7818e8SLoGin    jmp protected_mode_setup
2092b7818e8SLoGin
2102b7818e8SLoGinprotected_mode_setup:
21111f78b73SLoGin    //mov %eax, %e9
21211f78b73SLoGin    / 从保护模式跳转到长模式
21311f78b73SLoGin    // 1. 允许 PAE
21411f78b73SLoGin    mov %cr4, %eax
21511f78b73SLoGin    or $(1<<5), %eax
21611f78b73SLoGin    mov %eax, %cr4
21711f78b73SLoGin    // 2. 设置临时页表
21811f78b73SLoGin    // 最高级
21911f78b73SLoGin    mov $pml4, %eax
22011f78b73SLoGin    mov $pdpt, %ebx
22111f78b73SLoGin    or $0x3, %ebx
22211f78b73SLoGin    mov %ebx, 0(%eax)
22311f78b73SLoGin
22411f78b73SLoGin    // 次级
22511f78b73SLoGin    mov $pdpt, %eax
22611f78b73SLoGin    mov $pd, %ebx
22711f78b73SLoGin    or $0x3, %ebx
22811f78b73SLoGin    mov %ebx, 0(%eax)
22911f78b73SLoGin
23011f78b73SLoGin    // 次低级
23111f78b73SLoGin    mov $pd, %eax
23211f78b73SLoGin    mov $pt, %ebx
23311f78b73SLoGin    or $0x3, %ebx
23411f78b73SLoGin    mov %ebx, 0(%eax)
23511f78b73SLoGin
23611f78b73SLoGin    // 最低级
23711f78b73SLoGin    // 循环 512 次,填满一页
23811f78b73SLoGin    mov $512, %ecx
23911f78b73SLoGin    mov $pt, %eax
24011f78b73SLoGin    mov $0x3, %ebx
24111f78b73SLoGin.fill_pt:
24211f78b73SLoGin    mov %ebx, 0(%eax)
24311f78b73SLoGin    add $0x1000, %ebx
24411f78b73SLoGin    add $8, %eax
24511f78b73SLoGin    loop .fill_pt
24611f78b73SLoGin
24711f78b73SLoGin.global enter_head_from_ap_boot
24811f78b73SLoGinenter_head_from_ap_boot:
24911f78b73SLoGin    // 填写 CR3
25011f78b73SLoGin    mov $pml4, %eax
25111f78b73SLoGin    mov %eax, %cr3
25211f78b73SLoGin
25311f78b73SLoGin    // 3. 切换到 long 模式
25411f78b73SLoGin    mov $0xC0000080, %ecx
25511f78b73SLoGin    rdmsr
25611f78b73SLoGin    or $(1<<8), %eax
25711f78b73SLoGin    wrmsr
25811f78b73SLoGin
25911f78b73SLoGin    // 4. 开启分页
26011f78b73SLoGin    mov %cr0, %eax
26111f78b73SLoGin    or $(1<<31), %eax
26211f78b73SLoGin    mov %eax, %cr0
26311f78b73SLoGin
26411f78b73SLoGin    // 5. 重新设置 GDT
26511f78b73SLoGin    mov $gdt64_pointer, %eax
26611f78b73SLoGin    lgdt 0(%eax)
26711f78b73SLoGin
26811f78b73SLoGin    jmp $0x8, $ready_to_start_64
26911f78b73SLoGin    hlt
27011f78b73SLoGin    ret
27111f78b73SLoGin.code64
27211f78b73SLoGin.global ready_to_start_64
27311f78b73SLoGinready_to_start_64:
27411f78b73SLoGin
27511f78b73SLoGin    mov $0x10, %ax
27611f78b73SLoGin    mov %ax, %ds
27711f78b73SLoGin    mov %ax, %es
27811f78b73SLoGin    mov %ax, %fs
27911f78b73SLoGin    mov %ax, %ss
28011f78b73SLoGin    mov $0x7e00, %esp
28111f78b73SLoGin
28211f78b73SLoGin
28311f78b73SLoGin    //6. 跳转到start64
28411f78b73SLoGin    movq switch_to_start64(%rip), %rax
28511f78b73SLoGin    pushq $0x08 //段选择子
28611f78b73SLoGin    pushq %rax
28711f78b73SLoGin    lretq
28811f78b73SLoGin
28911f78b73SLoGinswitch_to_start64:
29011f78b73SLoGin    .quad _start64
29111f78b73SLoGin
29211f78b73SLoGin
29311f78b73SLoGin.code64
2942b7818e8SLoGinhalt:
2952b7818e8SLoGin    cli
29611f78b73SLoGin    hlt
2972b7818e8SLoGin    jmp halt
29811f78b73SLoGin
29911f78b73SLoGin.global _start64
30011f78b73SLoGin.type _start64, @function
30111f78b73SLoGin.extern Start_Kernel
30211f78b73SLoGinENTRY(_start64)
30311f78b73SLoGin
30411f78b73SLoGin    // 初始化寄存器
30511f78b73SLoGin    mov $0x10, %ax
30611f78b73SLoGin    mov %ax, %ds
30711f78b73SLoGin    mov %ax, %es
30811f78b73SLoGin    mov %ax, %fs
30911f78b73SLoGin    mov %ax, %ss
31011f78b73SLoGin    mov $0x7e00, %esp
31111f78b73SLoGin
31211f78b73SLoGin// === 加载GDTR ====
31311f78b73SLoGin    lgdt GDT_POINTER(%rip) //这里我没搞明白rip相对寻址, 看了文档,大概是用来实现PIC的(position independent code)
31411f78b73SLoGin    //lgdt $GDT_POINTER
31511f78b73SLoGin// === 加载IDTR ====
31611f78b73SLoGin    lidt IDT_POINTER(%rip)
31711f78b73SLoGin    //lidt $IDT_POINTER
31811f78b73SLoGin    movq GDT_POINTER(%rip), %r12
31911f78b73SLoGin
32011f78b73SLoGin    // 分支,判断是否为apu
32111f78b73SLoGin    movq	$0x1b,	%rcx		// 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
32211f78b73SLoGin	rdmsr
32311f78b73SLoGin	bt	$8,	%rax
32411f78b73SLoGin	jnc	load_apu_cr3
32511f78b73SLoGin
3263959e94dS曾俊    // BSP处理器
3273959e94dS曾俊    movq head_stack_start(%rip), %rsp
3283959e94dS曾俊
32911f78b73SLoGin    // 2. 设置临时页表
33011f78b73SLoGin    // 最高级
33111f78b73SLoGin    mov $__PML4E, %eax
33211f78b73SLoGin    mov $__PDPTE, %ebx
33311f78b73SLoGin    or $0x3, %ebx
33411f78b73SLoGin    mov %ebx, 0(%eax)
33511f78b73SLoGin
33611f78b73SLoGin    mov $__PML4E, %eax
33711f78b73SLoGin    // 加256个表项, 映射高地址
33811f78b73SLoGin    add $2048, %eax
33911f78b73SLoGin    mov %ebx, 0(%eax)
34011f78b73SLoGin
34111f78b73SLoGin    // 次级
34211f78b73SLoGin    mov $__PDPTE, %eax
34311f78b73SLoGin    mov $__PDE, %ebx
34411f78b73SLoGin    or $0x3, %ebx
34511f78b73SLoGin    mov %ebx, 0(%eax)
34611f78b73SLoGin
34711f78b73SLoGin    // 次低级
34811f78b73SLoGin    mov $__PDE, %eax
34911f78b73SLoGin    mov $50, %ecx
35011f78b73SLoGin    mov $__PT_S, %ebx
35111f78b73SLoGin    or $0x3, %ebx
35211f78b73SLoGin.fill_pde_64:
35311f78b73SLoGin    mov %ebx, 0(%eax)
35411f78b73SLoGin    add $0x1000, %ebx
35511f78b73SLoGin    add $8, %eax
35611f78b73SLoGin    loop .fill_pde_64
35711f78b73SLoGin
35811f78b73SLoGin    // 最低级
35911f78b73SLoGin    // 循环 512*25=12800 次,填满25页,共50M
36011f78b73SLoGin    mov $12800, %ecx
36111f78b73SLoGin    mov $__PT_S, %eax
36211f78b73SLoGin    mov $0x3, %ebx
36311f78b73SLoGin.fill_pt_64:
36411f78b73SLoGin    mov %ebx, 0(%eax)
36511f78b73SLoGin    add $0x1000, %ebx
36611f78b73SLoGin    add $8, %eax
36711f78b73SLoGin    loop .fill_pt_64
36811f78b73SLoGin
36911f78b73SLoGin    // 50-100M填0,共25个页表
37011f78b73SLoGin    mov $12800, %ecx
37111f78b73SLoGin.fill_pt_64_2:
37246e234aeSLoGin    movq $0, 0(%eax)
37311f78b73SLoGin    add $8, %eax
37411f78b73SLoGin    loop .fill_pt_64_2
37511f78b73SLoGin
37611f78b73SLoGin
37711f78b73SLoGin
37811f78b73SLoGin// ==== 加载CR3寄存器
37911f78b73SLoGin
38011f78b73SLoGinload_cr3:
38111f78b73SLoGin
38211f78b73SLoGin    movq $__PML4E, %rax //设置页目录基地址
38311f78b73SLoGin
38411f78b73SLoGin    movq %rax, %cr3
385*59a6bcf6SLoGin
38611f78b73SLoGin    jmp to_switch_seg
38711f78b73SLoGin
38811f78b73SLoGinload_apu_cr3:
38911f78b73SLoGin    // 由于内存管理模块重置了页表,因此ap核心初始化的时候,需要使用新的内核页表。
39011f78b73SLoGin    // 这个页表的值由smp模块设置到__APU_START_CR3变量中
39111f78b73SLoGin    // 加载__APU_START_CR3中的值
39211f78b73SLoGin    movq $__APU_START_CR3, %rax
39311f78b73SLoGin    movq 0(%rax), %rax
39411f78b73SLoGin    movq %rax, %cr3
3953959e94dS曾俊    movq _apu_boot_tmp_stack_top_addr(%rip), %rsp
39611f78b73SLoGin    jmp to_switch_seg
39711f78b73SLoGin
39811f78b73SLoGinto_switch_seg:
39911f78b73SLoGin
40011f78b73SLoGin    movq switch_seg(%rip), %rax
40111f78b73SLoGin    // 由于ljmp和lcall在GAS中不受支持,因此我们需要先伪造函数调用现场,通过lret的方式,给它跳转过去。才能更新cs寄存器
40211f78b73SLoGin    // 实在是太妙了!Amazing!
40311f78b73SLoGin    pushq $0x08 //段选择子
404*59a6bcf6SLoGin
40511f78b73SLoGin    pushq %rax
40611f78b73SLoGin    lretq
40711f78b73SLoGin
40811f78b73SLoGin// 64位模式的代码
40911f78b73SLoGinswitch_seg:
41011f78b73SLoGin
41111f78b73SLoGin    .quad entry64
41211f78b73SLoGin
41311f78b73SLoGin
41411f78b73SLoGinentry64:
41511f78b73SLoGin
41611f78b73SLoGin    movq $0x10, %rax
41711f78b73SLoGin    movq %rax, %ds
41811f78b73SLoGin    movq %rax, %es
41911f78b73SLoGin    movq %rax, %gs
42011f78b73SLoGin    movq %rax, %ss
42111f78b73SLoGin
4223959e94dS曾俊    // 分支,判断是否为apu,然后设置栈指针·
4233959e94dS曾俊    movq	$0x1b,	%rcx		// 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
4243959e94dS曾俊	rdmsr
4253959e94dS曾俊	bt	$8,	%rax
4263959e94dS曾俊	jnc	__set_ap_tmp_stack_start2
4273959e94dS曾俊__set_bsp_stack_start2:
4283959e94dS曾俊    movq head_stack_start(%rip), %rsp
4293959e94dS曾俊    jmp __set_stack_start2_ok
4303959e94dS曾俊__set_ap_tmp_stack_start2:
4313959e94dS曾俊    // 设置ap核心的临时栈
4323959e94dS曾俊    movq _apu_boot_tmp_stack_top_addr(%rip), %rsp
4333959e94dS曾俊    jmp __set_stack_start2_ok
4343959e94dS曾俊
4353959e94dS曾俊__set_stack_start2_ok:
4363959e94dS曾俊
43711f78b73SLoGin
43811f78b73SLoGin    // 重新加载GDT和IDT,加载到高地址
43911f78b73SLoGin    leaq GDT_Table(%rip), %r8
44011f78b73SLoGin    leaq GDT_END(%rip), %r9
44111f78b73SLoGin
44211f78b73SLoGin    subq %r8, %r9
44311f78b73SLoGin    movq %r9, %r13    // GDT size
44411f78b73SLoGin
44511f78b73SLoGin    leaq IDT_Table(%rip), %r8
44611f78b73SLoGin    leaq IDT_END(%rip), %r9
44711f78b73SLoGin
44811f78b73SLoGin    subq %r8, %r9
44911f78b73SLoGin    movq %r9, %r12    // IDT size
45011f78b73SLoGin
45111f78b73SLoGin    lgdt GDT_POINTER64(%rip)
45211f78b73SLoGin    lidt IDT_POINTER64(%rip)
45311f78b73SLoGin
45411f78b73SLoGin    // 分支,判断是否为apu
45511f78b73SLoGin    movq	$0x1b,	%rcx		// 根据IA32_APIC_BASE.BSP[8]标志位判断处理器是否为apu
45611f78b73SLoGin	rdmsr
45711f78b73SLoGin	bt	$8,	%rax
45811f78b73SLoGin	jnc	start_smp
45911f78b73SLoGin
46011f78b73SLoGinsetup_IDT:
46111f78b73SLoGin    // 该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,
46211f78b73SLoGin    leaq m_ignore_int(%rip),  %rdx // 将ignore_int的地址暂时存到中段描述符的高8B
46311f78b73SLoGin    movq $(0x08 << 16), %rax  // 设置段选择子。由IDT结构和段选择子结构可知,本行设置段基地址为0x100000,TI=0,RPL=0
46411f78b73SLoGin    movw %dx, %ax
46511f78b73SLoGin
46611f78b73SLoGin    movq $ (0x8e00 << 32), %rcx // 设置Type=1110 P=1 DPL=00 0=0
46711f78b73SLoGin    addq %rcx, %rax
46811f78b73SLoGin
46911f78b73SLoGin    // 把ignore_int的地址填写到正确位置, rax存低8B, rdx存高8B
47011f78b73SLoGin    movl %edx, %ecx
47111f78b73SLoGin    shrl $16, %ecx // 去除低16位
47211f78b73SLoGin    shlq $48, %rcx
47311f78b73SLoGin    addq %rcx, %rax // 填写段内偏移31:16
47411f78b73SLoGin
47511f78b73SLoGin    shrq $32, %rdx // (已经填写了32位,故右移32)
47611f78b73SLoGin
47711f78b73SLoGin    leaq IDT_Table(%rip), %rdi // 获取中断描述符表的首地址,存储到rdi
47811f78b73SLoGin    mov $256, %rcx  // 初始化每个中断描述符
47911f78b73SLoGin
48011f78b73SLoGinrepeat_set_idt:
48111f78b73SLoGin    // ====== 循环,初始化总共256个中断描述符 ===
48211f78b73SLoGin    movq %rax, (%rdi)   // 保存低8B
48311f78b73SLoGin    movq %rdx, 8(%rdi)  // 保存高8B
48411f78b73SLoGin
48511f78b73SLoGin    addq $0x10, %rdi // 转到下一个IDT表项
48611f78b73SLoGin    dec %rcx
48711f78b73SLoGin    jne repeat_set_idt
48811f78b73SLoGin
48911f78b73SLoGin
49011f78b73SLoGin    //now enable SSE and the like
49111f78b73SLoGin    movq %cr0, %rax
49211f78b73SLoGin    and $0xFFFB, %ax		//clear coprocessor emulation CR0.EM
49311f78b73SLoGin    or $0x2, %ax			//set coprocessor monitoring  CR0.MP
49411f78b73SLoGin    movq %rax, %cr0
49511f78b73SLoGin    movq %cr4, %rax
49611f78b73SLoGin    or $(3 << 9), %ax		//set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
49711f78b73SLoGin    movq %rax, %cr4
49811f78b73SLoGin
49911f78b73SLoGin
50011f78b73SLoGin    movq	go_to_kernel(%rip),	%rax		/* movq address */
50111f78b73SLoGin	pushq	$0x08
50211f78b73SLoGin	pushq	%rax
50311f78b73SLoGin
50411f78b73SLoGin
5055b59005fSLoGin    // 传参
5062b7818e8SLoGin    movq mb_entry_info, %rdi
5072b7818e8SLoGin    movq mb_entry_magic, %rsi
5085b59005fSLoGin    movq %r13, %rdx // GDT size
5095b59005fSLoGin    movq %r12, %r10 // IDT size
5102b7818e8SLoGin    movq boot_entry_type, %r8
51111f78b73SLoGin
51211f78b73SLoGin	lretq
51311f78b73SLoGin
51411f78b73SLoGingo_to_kernel:
5155b59005fSLoGin    .quad kernel_main
51611f78b73SLoGin
51711f78b73SLoGinstart_smp:
51811f78b73SLoGin
51911f78b73SLoGin
52011f78b73SLoGin    //now enable SSE and the like
52111f78b73SLoGin    movq %cr0, %rax
52211f78b73SLoGin    and $0xFFFB, %ax		//clear coprocessor emulation CR0.EM
52311f78b73SLoGin    or $0x2, %ax			//set coprocessor monitoring  CR0.MP
52411f78b73SLoGin    movq %rax, %cr0
52511f78b73SLoGin    movq %cr4, %rax
52611f78b73SLoGin    or $(3 << 9), %ax		//set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
52711f78b73SLoGin    movq %rax, %cr4
52811f78b73SLoGin
52911f78b73SLoGin
53011f78b73SLoGin	movq	go_to_smp_kernel(%rip),	%rax		/* movq address */
53111f78b73SLoGin	pushq	$0x08
53211f78b73SLoGin	pushq	%rax
53311f78b73SLoGin
53411f78b73SLoGin/*
53511f78b73SLoGin    // 重新加载GDT和IDT,加载到高地址
53611f78b73SLoGin    leaq GDT_Table(%rip), %r8
53711f78b73SLoGin    leaq GDT_END(%rip), %r9
53811f78b73SLoGin
53911f78b73SLoGin    subq %r8, %r9
54011f78b73SLoGin    movq %r9, %r13    // GDT size
54111f78b73SLoGin
54211f78b73SLoGin    leaq IDT_Table(%rip), %r8
54311f78b73SLoGin    leaq IDT_END(%rip), %r9
54411f78b73SLoGin
54511f78b73SLoGin    subq %r8, %r9
54611f78b73SLoGin    movq %r9, %r12    // IDT size
54711f78b73SLoGin
54811f78b73SLoGin    lgdt GDT_POINTER64(%rip)
54911f78b73SLoGin    lidt IDT_POINTER64(%rip)
55011f78b73SLoGin*/
55111f78b73SLoGin	lretq
55211f78b73SLoGin
55311f78b73SLoGingo_to_smp_kernel:
55411f78b73SLoGin
55511f78b73SLoGin	.quad	smp_ap_start
55611f78b73SLoGin
55711f78b73SLoGin// ==== 异常/中断处理模块 ignore int: 忽略中断
55811f78b73SLoGin// (该部分代码只在启动初期使用,后面的c文件中会重新设置IDT,从而重设ignore_int的中断入点)
55911f78b73SLoGinm_ignore_int:
56011f78b73SLoGin// 切换到c语言的ignore_int
56111f78b73SLoGin    movq go_to_ignore_int(%rip), %rax
56211f78b73SLoGin    pushq $0x08
56311f78b73SLoGin    pushq %rax
56411f78b73SLoGin    lretq
56511f78b73SLoGin
56611f78b73SLoGin
56711f78b73SLoGin
56811f78b73SLoGingo_to_ignore_int:
56911f78b73SLoGin    .quad ignore_int_handler
57011f78b73SLoGin
57111f78b73SLoGinENTRY(head_stack_start)
57211f78b73SLoGin    .quad BSP_IDLE_STACK_SPACE + 32768
57311f78b73SLoGin
5743959e94dS曾俊ENTRY(_apu_boot_tmp_stack_top_addr)
5753959e94dS曾俊    .quad _apu_boot_tmp_stack_start + APU_BOOT_TMP_STACK_SIZE
5763959e94dS曾俊
57711f78b73SLoGin// 初始化页表
57811f78b73SLoGin.align 0x1000 //设置为4k对齐
57911f78b73SLoGin__PML4E:
58011f78b73SLoGin    .skip 0x1000
58111f78b73SLoGin__PDPTE:
58211f78b73SLoGin	.skip 0x1000
58311f78b73SLoGin
58411f78b73SLoGin// 三级页表
58511f78b73SLoGin__PDE:
58611f78b73SLoGin    .skip 0x1000
58711f78b73SLoGin
58811f78b73SLoGin// 预留50个四级页表,总共表示100M的内存空间。这50个页表占用200KB的空间
58911f78b73SLoGin__PT_S:
59011f78b73SLoGin    .skip 0x32000
59111f78b73SLoGin
59211f78b73SLoGin
59311f78b73SLoGin.global __APU_START_CR3
59411f78b73SLoGin__APU_START_CR3:
59511f78b73SLoGin    .quad 0
59611f78b73SLoGin
59711f78b73SLoGin// GDT表
59811f78b73SLoGin
59911f78b73SLoGin.align 16
60011f78b73SLoGin.global GDT_Table // 使得GDT可以被外部程序引用或者访问
60111f78b73SLoGin
60211f78b73SLoGinGDT_Table:
60311f78b73SLoGin    .quad 0x0000000000000000 // 0 空描述符 0x00
60411f78b73SLoGin    .quad 0x0020980000000000 // 1 内核64位代码段描述符 0x08
60511f78b73SLoGin    .quad 0x0000920000000000 // 2 内核64位数据段描述符 0x10
60611f78b73SLoGin    .quad 0x0000000000000000 // 3 用户32位代码段描述符 0x18
60711f78b73SLoGin    .quad 0x0000000000000000 // 4 用户32位数据段描述符 0x20
60811f78b73SLoGin    .quad 0x00cff3000000ffff // 5 用户64位数据段描述符 0x28
60911f78b73SLoGin    .quad 0x00affb000000ffff // 6 用户64位代码段描述符 0x30
61011f78b73SLoGin    .quad 0x00cf9a000000ffff // 7 内核32位代码段描述符 0x38
61111f78b73SLoGin    .quad 0x00cf92000000ffff // 8 内核32位数据段描述符 0x40
61211f78b73SLoGin    .fill 100, 8, 0           // 10-11 TSS(跳过了第9段)  重复十次填充8字节的空间,赋值为0   长模式下,每个TSS长度为128bit
61311f78b73SLoGinGDT_END:
61411f78b73SLoGin
61511f78b73SLoGin.global GDT_POINTER
61611f78b73SLoGinGDT_POINTER:
61711f78b73SLoGinGDT_LIMIT: .word GDT_END - GDT_Table - 1 // GDT的大小
61811f78b73SLoGinGDT_BASE: .quad GDT_Table
61911f78b73SLoGin
62011f78b73SLoGin.global GDT_POINTER64
62111f78b73SLoGinGDT_POINTER64:
62211f78b73SLoGinGDT_LIMIT64: .word GDT_END - GDT_Table - 1 // GDT的大小
62311f78b73SLoGinGDT_BASE64: .quad GDT_Table + 0xffff800000000000
62411f78b73SLoGin
62511f78b73SLoGin// IDT 表
62611f78b73SLoGin.global IDT_Table
62711f78b73SLoGin
62811f78b73SLoGinIDT_Table:
62911f78b73SLoGin    .fill 512, 8, 0 // 设置512*8字节的IDT表的空间
63011f78b73SLoGinIDT_END:
63111f78b73SLoGin
63211f78b73SLoGin.global IDT_POINTER
63311f78b73SLoGinIDT_POINTER:
63411f78b73SLoGinIDT_LIMIT: .word IDT_END - IDT_Table - 1
63511f78b73SLoGinIDT_BASE: .quad IDT_Table
63611f78b73SLoGin
63711f78b73SLoGin.global IDT_POINTER64
63811f78b73SLoGinIDT_POINTER64:
63911f78b73SLoGinIDT_LIMIT64: .word IDT_END - IDT_Table - 1
64011f78b73SLoGinIDT_BASE64: .quad IDT_Table + 0xffff800000000000
64111f78b73SLoGin
64211f78b73SLoGin
64311f78b73SLoGin
64411f78b73SLoGin.section .bootstrap.data
6452b7818e8SLoGinmb_entry_magic: .quad 0
6462b7818e8SLoGinmb_entry_info: .quad 0
6472b7818e8SLoGin// 引导协议类型
6482b7818e8SLoGinboot_entry_type: .quad 0
64911f78b73SLoGin
65011f78b73SLoGin.code32
65111f78b73SLoGin// 临时页表 4KB/页
65211f78b73SLoGin.align 0x1000
65311f78b73SLoGin.global pml4
65411f78b73SLoGinpml4:
65511f78b73SLoGin    .skip 0x1000
65611f78b73SLoGinpdpt:
65711f78b73SLoGin    .skip 0x1000
65811f78b73SLoGinpd:
65911f78b73SLoGin    .skip 0x1000
66011f78b73SLoGinpt:
66111f78b73SLoGin    .skip 0x1000
66211f78b73SLoGin
66311f78b73SLoGin// 临时 GDT
66411f78b73SLoGin.align 16
66511f78b73SLoGingdt64:
66611f78b73SLoGinnull_desc:
66711f78b73SLoGin    .short 0xFFFF
66811f78b73SLoGin    .short 0
66911f78b73SLoGin    .byte 0
67011f78b73SLoGin    .byte 0
67111f78b73SLoGin    .byte 0
67211f78b73SLoGin    .byte 0
67311f78b73SLoGincode_desc:
67411f78b73SLoGin    .short 0
67511f78b73SLoGin    .short 0
67611f78b73SLoGin    .byte 0
67711f78b73SLoGin    .byte 0x9A
67811f78b73SLoGin    .byte 0x20
67911f78b73SLoGin    .byte 0
68011f78b73SLoGindata_desc:
68111f78b73SLoGin    .short 0
68211f78b73SLoGin    .short 0
68311f78b73SLoGin    .byte 0
68411f78b73SLoGin    .byte 0x92
68511f78b73SLoGin    .byte 0
68611f78b73SLoGin    .byte 0
68711f78b73SLoGinuser_code_desc:
68811f78b73SLoGin    .short 0
68911f78b73SLoGin    .short 0
69011f78b73SLoGin    .byte 0
69111f78b73SLoGin    .byte 0xFA
69211f78b73SLoGin    .byte 0x20
69311f78b73SLoGin    .byte 0
69411f78b73SLoGinuser_data_desc:
69511f78b73SLoGin    .short 0
69611f78b73SLoGin    .short 0
69711f78b73SLoGin    .byte 0
69811f78b73SLoGin    .byte 0xF2
69911f78b73SLoGin    .byte 0
70011f78b73SLoGin    .byte 0
70111f78b73SLoGingdt64_pointer:
70211f78b73SLoGin    .short gdt64_pointer-gdt64-1
70311f78b73SLoGin    .quad gdt64
70411f78b73SLoGingdt64_pointer64:
70511f78b73SLoGin    .short gdt64_pointer-gdt64-1
70611f78b73SLoGin    .quad gdt64
70711f78b73SLoGin