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