读书人

Xen源代码分析(2)trampoline.s

发布时间: 2012-11-22 00:16:41 作者: rapoo

Xen源代码分析(二)——trampoline.s

汇编文件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"

读书人网 >云计算

热点推荐