汇编文件trampoline.s,主要工作为进入实模式,读取内存,磁盘,视频信息然后再次进入保护模式装入新的GDT(gdt_table),英文注释了很大部分,很容易理解。下面的代码注释中,从标号0开始运行,然后是标号1。
.code16
/* NB. bootsym() is only usable in real mode, or via BOOT_PSEUDORM_DS. */
#undef bootsym
/*bootsym(s)定义的是s的相对位置*/
#define bootsym(s) ((s)-trampoline_start)
#define bootsym_rel(sym, off, opnd...) \
bootsym(sym),##opnd; \
111:; \
.pushsection .trampoline_rel, "a"; \
.long 111b - (off) - .; \
.popsection
#define bootsym_segrel(sym, off) \
$0,$bootsym(sym); \
111:; \
.pushsection .trampoline_seg, "a"; \
.long 111b - (off) - .; \
.popsection
.globl trampoline_realmode_entry
trampoline_realmode_entry:
mov %cs,%ax
mov %ax,%ds
movb $0xA5,bootsym(trampoline_cpu_started)
cld
cli
lidt bootsym(idt_48)
lgdt bootsym(gdt_48)
mov $1,%bl # EBX != 0 indicates we are an AP
xor %ax, %ax
inc %ax
lmsw %ax # CR0.PE = 1 (enter protected mode)
ljmpl $BOOT_CS32,$bootsym_rel(trampoline_protmode_entry,6)
idt_48: .word 0, 0, 0 # base = limit = 0
gdt_48: .word 6*8-1
.long bootsym_rel(trampoline_gdt,4)
trampoline_gdt:
/* 0x0000: unused */
.quad 0x0000000000000000
/* 0x0008: ring 0 code, 32-bit mode */
.quad 0x00cf9a000000ffff
/* 0x0010: ring 0 code, 64-bit mode */
.quad 0x00af9a000000ffff
/* 0x0018: ring 0 data */
.quad 0x00cf92000000ffff
/* 0x0020: real-mode code @ BOOT_TRAMPOLINE */
.long 0x0000ffff
.long 0x00009a00
/* 0x0028: real-mode data @ BOOT_TRAMPOLINE */
.long 0x0000ffff
.long 0x00009200
.pushsection .trampoline_rel, "a"
.long trampoline_gdt + BOOT_PSEUDORM_CS + 2 - .
.long trampoline_gdt + BOOT_PSEUDORM_DS + 2 - .
.popsection
.globl cpuid_ext_features
cpuid_ext_features:
.long 0
.globl trampoline_xen_phys_start
trampoline_xen_phys_start:
.long 0
.globl trampoline_cpu_started
trampoline_cpu_started:
.byte 0
.code32
/*1: 从实模式跳转到这里运行,也就是正式进入保护模式*/
trampoline_protmode_entry:
/* Set up a few descriptors: on entry only CS is guaranteed good. */
mov $BOOT_DS,%eax
mov %eax,%ds
mov %eax,%es
/* Set up FPU. */
fninit
/* Initialise CR4. */
mov $X86_CR4_PAE,%ecx
mov %ecx,%cr4
/* Load pagetable base register. */
mov $sym_phys(idle_pg_table),%eax
add bootsym_rel(trampoline_xen_phys_start,4,%eax)
mov %eax,%cr3
/* Set up EFER (Extended Feature Enable Register). */
mov bootsym_rel(cpuid_ext_features,4,%edi)
test $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */
jz .Lskip_efer
movl $MSR_EFER,%ecx
rdmsr
#if CONFIG_PAGING_LEVELS == 4
btsl $_EFER_LME,%eax /* Long Mode */
btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */
#endif
btl $20,%edi /* No Execute? */
jnc 1f
btsl $_EFER_NX,%eax /* No Execute */
1: wrmsr
.Lskip_efer:
mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
mov %eax,%cr0
jmp 1f
1:
#if defined(__x86_64__)
/* Now in compatibility mode. Long-jump into 64-bit mode. */
ljmp $BOOT_CS64,$bootsym_rel(start64,6)
.code64
start64:
/* Jump to high mappings. */
mov high_start(%rip),%rax
jmpq *%rax
high_start:
.quad __high_start
#else /* !defined(__x86_64__) */
/* Install relocated selectors. */
lgdt gdt_descr/*正式装载初始化后的GDT,这里装入的GDT为汇编期间最终的GDT,在x86_32.s中定义*/
mov $(__HYPERVISOR_DS),%eax
mov %eax,%ds
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov %eax,%ss
/*长跳转到x86_32.s的入口__high_start,该变量在head.s中定义,为x86_32.s的入口,x86_32.s
在head.s中以包含的方式调用*/
ljmp $(__HYPERVISOR_CS),$__high_start
#endif
.code32
/*0: 从head.s的ret指令跳转后首先到达这里开始执行,32位代码,此时还处在保护模式下*/
trampoline_boot_cpu_entry:
cmpb $0,bootsym_rel(skip_realmode,5)
jnz .Lskip_realmode
/* Load pseudo-real-mode segments. */
mov $BOOT_PSEUDORM_DS,%eax
mov %eax,%ds
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov %eax,%ss
/* Switch to pseudo-rm CS, enter real mode, and flush insn queue. */
mov %cr0,%eax
dec %eax
/*通过下面两个长跳转切换到实模式*/
ljmp $BOOT_PSEUDORM_CS,$bootsym(1f)
.code16
1: mov %eax,%cr0 # CR0.PE = 0 (leave protected mode)
/* Load proper real-mode values into %cs, %ds, %es and %ss. */
ljmp bootsym_segrel(1f,2)
1: mov %cs,%ax
mov %ax,%ds
mov %ax,%es
mov %ax,%ss
/* Initialise stack pointer and IDT, and enable irqs. */
xor %sp,%sp
lidt bootsym(rm_idt)/*加载IDT*/
sti
#if defined(__x86_64__)
/*
* Declare that our target operating mode is long mode.
* Initialise 32-bit registers since some buggy BIOSes depend on it.
*/
movl $0xec00,%eax # declare target operating mode
movl $0x0002,%ebx # long mode
int $0x15
#endif
/*
* Do real-mode work:
* 1. Get memory map.
* 2. Get Enhanced Disk Drive (EDD) information.
* 3. Set video mode.
*/
/*获得内存信息,该函数于mem.s中调用,内存信息存放于e820map变量中,
类似Linux内核的处理方式,调用0x15号中断*/
call get_memory_map
/*调用于edd.s中*/
call get_edd
/*调用于video.s中*/
call video
/* Disable irqs before returning to protected mode. */
cli
/* Reset GDT and IDT. Some BIOSes clobber GDTR. */
lidt bootsym(idt_48)
lgdt bootsym(gdt_48)
/* Enter protected mode, and flush insn queue. */
xor %ax,%ax
inc %ax
lmsw %ax # CR0.PE = 1 (enter protected mode)
/* Load proper protected-mode values into all segment registers. */
/*跳转到32位代码,为进入保护模式做准备*/
ljmpl $BOOT_CS32,$bootsym_rel(1f,6)
.code32
1: mov $BOOT_DS,%eax
mov %eax,%ds
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov %eax,%ss
.Lskip_realmode:
/* EBX == 0 indicates we are the BP (Boot Processor). */
xor %ebx,%ebx
/* Jump to the common bootstrap entry point. */
jmp trampoline_protmode_entry/*跳转到保护模式入口*/
skip_realmode:
.byte 0
rm_idt: .word 256*4-1, 0, 0
/*这三部分的内容不再这里详细写了*/
#include "mem.S"
#include "edd.S"
#include "video.S"
#include "wakeup.S"