X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..7ddcb079202367355dddccdfa4318e57d50318be:/osfmk/i386/start.s diff --git a/osfmk/i386/start.s b/osfmk/i386/start.s index 3218d3d15..5472ffde3 100644 --- a/osfmk/i386/start.s +++ b/osfmk/i386/start.s @@ -57,7 +57,6 @@ */ #include -#include #include #include @@ -66,29 +65,15 @@ #define CX(addr,reg) addr(,reg,4) -#include -#include +#include #include -/* - * GAS won't handle an intersegment jump with a relocatable offset. - */ -#define LJMP(segment,address) \ - .byte 0xea ;\ - .long address ;\ - .word segment - - - -#define PA(addr) (addr) -#define VA(addr) (addr) - /* * Interrupt and bootup stack for initial processor. */ - /* in the __HIB section since the hibernate restore code uses this stack. */ - .section __HIB, __data +/* in the __HIB section since the hibernate restore code uses this stack. */ + .section __HIB, __data .align 12 .globl EXT(low_intstack) @@ -96,7 +81,7 @@ EXT(low_intstack): .globl EXT(gIOHibernateRestoreStack) EXT(gIOHibernateRestoreStack): - .set ., .+INTSTACK_SIZE + .space INTSTACK_SIZE .globl EXT(low_eintstack) EXT(low_eintstack:) @@ -109,22 +94,14 @@ EXT(gIOHibernateRestoreStackEnd): .align ALIGN .globl EXT(gdtptr) /* align below properly */ - .word 0 + .word 0 LEXT(gdtptr) .word Times(8,GDTSZ)-1 .long EXT(master_gdt) - .align ALIGN - .globl EXT(idtptr) - /* align below properly */ - .word 0 -LEXT(idtptr) - .word Times(8,IDTSZ)-1 - .long EXT(master_idt) - - /* back to the regular __DATA section. */ + /* back to the regular __DATA section. */ - .section __DATA, __data + .section __DATA, __data /* * Stack for last-gasp double-fault handler. @@ -132,7 +109,7 @@ LEXT(idtptr) .align 12 .globl EXT(df_task_stack) EXT(df_task_stack): - .set ., .+INTSTACK_SIZE + .space INTSTACK_SIZE .globl EXT(df_task_stack_end) EXT(df_task_stack_end): @@ -143,108 +120,21 @@ EXT(df_task_stack_end): .align 12 .globl EXT(mc_task_stack) EXT(mc_task_stack): - .set ., .+INTSTACK_SIZE + .space INTSTACK_SIZE .globl EXT(mc_task_stack_end) EXT(mc_task_stack_end): - #if MACH_KDB -/* - * Kernel debugger stack for each processor. - */ - .align 12 - .globl EXT(db_stack_store) -EXT(db_stack_store): - .set ., .+(INTSTACK_SIZE*MAX_CPUS) - /* * Stack for last-ditch debugger task for each processor. */ .align 12 .globl EXT(db_task_stack_store) EXT(db_task_stack_store): - .set ., .+(INTSTACK_SIZE*MAX_CPUS) + .space (INTSTACK_SIZE*MAX_CPUS) -/* - * per-processor kernel debugger stacks - */ - .align ALIGN - .globl EXT(kgdb_stack_store) -EXT(kgdb_stack_store): - .set ., .+(INTSTACK_SIZE*MAX_CPUS) #endif /* MACH_KDB */ - .data -physfree: - .long 0 /* phys addr of next free page */ - - .globl EXT(IdlePTD) -EXT(IdlePTD): - .long 0 /* phys addr of kernel PTD */ -#ifdef PAE - .globl EXT(IdlePDPT) -EXT(IdlePDPT): - .long 0 /* phys addr of kernel PDPT */ -#endif -#ifdef X86_64 - .globl EXT(IdlePML4) -EXT(IdlePML4): - .long 0 - .globl EXT(IdlePDPT64) -EXT(IdlePDPT64): - .long 0 -#endif - -KPTphys: - .long 0 /* phys addr of kernel page tables */ - - .globl EXT(KernelRelocOffset) -EXT(KernelRelocOffset): - .long 0 /* Kernel relocation offset */ - - -/* Some handy macros */ - -#define ALLOCPAGES(npages) \ - movl PA(physfree), %esi ; \ - movl $((npages) * PAGE_SIZE), %eax ; \ - addl %esi, %eax ; \ - movl %eax, PA(physfree) ; \ - movl %esi, %edi ; \ - movl $((npages) * PAGE_SIZE / 4),%ecx ; \ - xorl %eax,%eax ; \ - cld ; \ - rep ; \ - stosl - -/* - * fillkpt - * eax = page frame address - * ebx = index into page table - * ecx = how many pages to map - * base = base address of page dir/table - * prot = protection bits - */ -#define fillkpt(base, prot) \ - shll $(PTEINDX),%ebx ; \ - addl base,%ebx ; \ - orl $(PTE_V) ,%eax ; \ - orl prot,%eax ; \ -1: movl %eax,(%ebx) ; \ - addl $(PAGE_SIZE),%eax ; /* increment physical address */ \ - addl $(PTESIZE),%ebx ; /* next pte */ \ - loop 1b - -/* - * fillkptphys(prot) - * eax = physical address - * ecx = how many pages to map - * prot = protection bits - */ -#define fillkptphys(prot) \ - movl %eax, %ebx ; \ - shrl $(PAGE_SHIFT), %ebx ; \ - fillkpt(PA(KPTphys), prot) /* * BSP CPU start here. @@ -257,330 +147,55 @@ EXT(KernelRelocOffset): .text .align ALIGN .globl EXT(_start) - .globl EXT(_pstart) LEXT(_start) -LEXT(_pstart) - mov %ds, %bx - mov %bx, %es - mov %eax, %ebp // Move kernbootstruct to ebp - POSTCODE(_PSTART_ENTRY) - movl KADDR(%ebp), %ebx // Load boot image phys addr - movl %ebx, %edx // Set edx with boot load phys addr - addl KSIZE(%ebp), %edx // Add boot image size - addl $(NBPG-1), %edx // Round to a page size - andl $(-NBPG), %edx // Set edx to first free page - movl %edx, %esp // Set temporay stack - addl $(NBPG), %esp // add page size - call Ls1 -Ls1: popl %esi // Get return address - cmpl $(PA(Ls1)), %esi // Compare with static physicall addr - je EXT(pstart) // Branch if equal - subl $(PA(Ls1)), %esi // Extract relocation offset - movl %esi, %esp // Store relocation offset in esp - leal (PA(Lreloc_start))(%esp),%esi - // Set esi to reloc_start boot phys addr - movl %edx, %edi // Set edi to first free page - movl $(Lreloc_end-Lreloc_start), %ecx - // Set ecx to copy code size - cld // count up - rep - movsb // copy reloc copy code - wbinvd // Write back and Invalidate cache - movl %ebx, %esi // Set esi to kernbootstruct kaddr - movl KADDR(%ebp), %edi // Load boot image phys addr - subl %esp, %edi // Adjust to static phys addr - movl KSIZE(%ebp), %ecx // Set ecx to kernbootstruct ksize - addl $(NBPG-1), %ecx // Add NBPG-1 to ecx - andl $(-NBPG), %ecx // Truncate ecx to a page aligned addr - shrl $2, %ecx // Divide ecx by 4 - movl %esp, (PA(EXT(KernelRelocOffset)))(%esp) - // Store relocation offset - movl %edi, KADDR(%ebp) // Relocate kaddr in kernbootstruct - subl %esp, MEMORYMAP(%ebp) // And relocate MemoryMap - subl %esp, DEVICETREEP(%ebp) // And relocate deviceTreeP - subl %esp, %ebp // Set ebp with relocated phys addr - jmp *%edx // Branch to relocated copy code -Lreloc_start: - POSTCODE(_PSTART_RELOC) - rep - movsl // Copy boot image at BASE_KERNEL_PADDR - wbinvd // Write back and Invalidate cache - movl $(PA(EXT(pstart))), %edx // Set branch target - jmp *%edx // Far jmp to pstart phys addr -Lreloc_end: - /* NOTREACHED */ - hlt - - .text - .globl __start - .set __start, PA(EXT(_pstart)) + mov %ds, %bx + mov %bx, %es + mov %eax, %ebp /* Move kernbootstruct to ebp */ + mov %eax, %ebx /* get pointer to kernbootstruct */ -/* - * BSP CPU continues here after possible relocation. - * ebp points to kernbootstruct - */ - .align ALIGN - .globl EXT(pstart) -LEXT(pstart) - mov %ebp, %ebx /* get pointer to kernbootstruct */ + mov $EXT(low_eintstack),%esp /* switch to the bootup stack */ POSTCODE(PSTART_ENTRY) - mov $0,%ax /* fs must be zeroed; */ - mov %ax,%fs /* some bootstrappers don`t do this */ - mov %ax,%gs + lgdt EXT(gdtptr) /* load GDT */ -/* - * Get startup parameters. - */ - movl KADDR(%ebx), %eax - addl KSIZE(%ebx), %eax - addl $(NBPG-1),%eax - andl $(-NBPG), %eax - movl %eax, PA(physfree) + mov $(KERNEL_DS),%ax /* set kernel data segment */ + mov %ax, %ds + mov %ax, %es + mov %ax, %ss + xor %ax, %ax /* fs must be zeroed; */ + mov %ax, %fs /* some bootstrappers don`t do this */ + mov %ax, %gs cld -/* allocate kernel page table pages */ - ALLOCPAGES(NKPT) - movl %esi,PA(KPTphys) - -#ifdef X86_64 -/* allocate PML4 page */ - ALLOCPAGES(1) - movl %esi,EXT(IdlePML4) -/* allocate new 3rd level directory page */ - ALLOCPAGES(1) - movl %esi,EXT(IdlePDPT64) -#endif - -#ifdef PAE -/* allocate Page Table Directory Page */ - ALLOCPAGES(1) - movl %esi,PA(EXT(IdlePDPT)) -#endif - -/* allocate kernel page directory page */ - ALLOCPAGES(NPGPTD) - movl %esi,PA(EXT(IdlePTD)) - -/* map from zero to end of kernel */ - xorl %eax,%eax - movl PA(physfree),%ecx - shrl $(PAGE_SHIFT),%ecx - fillkptphys( $(PTE_W) ) - -/* map page directory */ -#ifdef PAE - movl PA(EXT(IdlePDPT)), %eax - movl $1, %ecx - fillkptphys( $(PTE_W) ) - - movl PA(EXT(IdlePDPT64)), %eax - movl $1, %ecx - fillkptphys( $(PTE_W) ) -#endif - movl PA(EXT(IdlePTD)),%eax - movl $(NPGPTD), %ecx - fillkptphys( $(PTE_W) ) - -/* install a pde for temp double map of bottom of VA */ - movl PA(KPTphys),%eax - xorl %ebx,%ebx - movl $(NKPT), %ecx - fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) - -/* install pde's for page tables */ - movl PA(KPTphys),%eax - movl $(KPTDI),%ebx - movl $(NKPT),%ecx - fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) - -/* install a pde recursively mapping page directory as a page table */ - movl PA(EXT(IdlePTD)),%eax - movl $(PTDPTDI),%ebx - movl $(NPGPTD),%ecx - fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) - -#ifdef PAE - movl PA(EXT(IdlePTD)), %eax - xorl %ebx, %ebx - movl $(NPGPTD), %ecx - fillkpt(PA(EXT(IdlePDPT)), $0) -#endif - -/* install a pde page for commpage use up in high memory */ - - movl PA(physfree),%eax /* grab next phys page */ - movl %eax,%ebx - addl $(PAGE_SIZE),%ebx - movl %ebx,PA(physfree) /* show next free phys pg */ - movl $(COMM_PAGE_BASE_ADDR),%ebx - shrl $(PDESHIFT),%ebx /* index into pde page */ - movl $(1), %ecx /* # pdes to store */ - fillkpt(PA(EXT(IdlePTD)), $(PTE_W|PTE_U)) /* user has access! */ - - movl PA(physfree),%edi - movl %edi,PA(EXT(first_avail)) /* save first available phys addr */ - -#ifdef PAE -/* - * We steal 0x4000 for a temp pdpt and 0x5000-0x8000 - * for temp pde pages in the PAE case. Once we are - * running at the proper virtual address we switch to - * the PDPT/PDE's the master is using */ - - /* clear pdpt page to be safe */ - xorl %eax, %eax - movl $(PAGE_SIZE),%ecx - movl $(0x4000),%edi - cld - rep - stosb - - /* build temp pdpt */ - movl $(0x5000), %eax - xorl %ebx, %ebx - movl $(NPGPTD), %ecx - fillkpt($(0x4000), $0) - - /* copy the NPGPTD pages of pdes */ - movl PA(EXT(IdlePTD)),%eax - movl $0x5000,%ebx - movl $((PTEMASK+1)*NPGPTD),%ecx -1: movl 0(%eax),%edx - movl %edx,0(%ebx) - movl 4(%eax),%edx - movl %edx,4(%ebx) - addl $(PTESIZE),%eax - addl $(PTESIZE),%ebx - loop 1b -#else -/* create temp pde for slaves to use - use unused lomem page and copy in IdlePTD */ - movl PA(EXT(IdlePTD)),%eax - movl $0x4000,%ebx - movl $(PTEMASK+1),%ecx -1: movl 0(%eax),%edx - movl %edx,0(%ebx) - addl $(PTESIZE),%eax - addl $(PTESIZE),%ebx - loop 1b -#endif - - POSTCODE(PSTART_PAGE_TABLES) - -/* - * Fix initial descriptor tables. - */ - lea PA(EXT(master_idt)),%esi /* fix IDT */ - movl $(IDTSZ),%ecx - movl $(PA(fix_idt_ret)),%ebx - jmp fix_desc_common /* (cannot use stack) */ -fix_idt_ret: - - lea PA(EXT(master_gdt)),%esi /* fix GDT */ - movl $(GDTSZ),%ecx - movl $(PA(fix_gdt_ret)),%ebx - jmp fix_desc_common /* (cannot use stack) */ -fix_gdt_ret: - - lea PA(EXT(master_ldt)),%esi /* fix LDT */ - movl $(LDTSZ),%ecx - movl $(PA(fix_ldt_ret)),%ebx - jmp fix_desc_common /* (cannot use stack) */ -fix_ldt_ret: - -/* - * - */ - - lgdt PA(EXT(gdtptr)) /* load GDT */ - lidt PA(EXT(idtptr)) /* load IDT */ + /* "The Aussie Maneuver" ("Myria" variant) */ + pushl $(0xcb<<24)|KERNEL32_CS /* reload CS */ + call .-1 +paging: + andl $0xfffffff0, %esp /* align stack */ + subl $0xc, %esp + pushl %ebp /* push boot args addr */ + xorl %ebp, %ebp /* zero frame pointer */ + POSTCODE(PSTART_BEFORE_PAGING) /* * Turn on paging. */ -#ifdef PAE - movl PA(EXT(IdlePDPT)), %eax + movl $EXT(IdlePDPT), %eax /* CR3 */ movl %eax, %cr3 - - movl %cr4, %eax + movl %cr4, %eax /* PAE */ orl $(CR4_PAE), %eax movl %eax, %cr4 - - movl $0x80000001, %eax - cpuid - and $(CPUID_EXTFEATURE_XD), %edx /* clear all but bit 20 */ - cmp $0, %edx /* skip setting NXE if 20 is not set */ - je 1f + movl %cr0,%eax /* paging */ + orl $(CR0_PG|CR0_WP),%eax + movl %eax,%cr0 - movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */ - rdmsr /* MSR value return in edx: eax */ - orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */ - wrmsr /* Update Extended Feature Enable reg */ -1: - -#else - movl PA(EXT(IdlePTD)), %eax - movl %eax,%cr3 -#endif - - movl %cr0,%eax - orl $(CR0_PG|CR0_WP|CR0_PE),%eax - movl %eax,%cr0 /* to enable paging */ - - LJMP(KERNEL_CS,EXT(vstart)) /* switch to kernel code segment */ - -/* - * BSP is now running with correct addresses. - */ -LEXT(vstart) - POSTCODE(VSTART_ENTRY) ; - - mov $(KERNEL_DS),%ax /* set kernel data segment */ - mov %ax,%ds - mov %ax,%es - mov %ax,%ss - mov %ax,EXT(master_ktss)+TSS_SS0 /* set kernel stack segment */ - /* for traps to kernel */ - -#if MACH_KDB - mov %ax,EXT(master_dbtss)+TSS_SS0 /* likewise for debug task switch */ - mov %cr3,%eax /* get PDBR into debug TSS */ - mov %eax,EXT(master_dbtss)+TSS_PDBR - mov $0,%eax -#endif - mov %cr3,%eax /* get PDBR into DF TSS */ - mov %eax,EXT(master_dftss)+TSS_PDBR - mov %eax,EXT(master_mctss)+TSS_PDBR - - movw $(KERNEL_LDT),%ax /* get LDT segment */ - lldt %ax /* load LDT */ -#if MACH_KDB - mov %ax,EXT(master_ktss)+TSS_LDT /* store LDT in two TSS, as well... */ - mov %ax,EXT(master_dbtss)+TSS_LDT /* ...matters if we switch tasks */ -#endif - movw $(KERNEL_TSS),%ax - ltr %ax /* set up KTSS */ - - mov $(CPU_DATA_GS),%ax - mov %ax,%gs - - POSTCODE(VSTART_STACK_SWITCH) - - lea EXT(low_eintstack),%esp /* switch to the bootup stack */ - pushl %ebp /* push boot args addr */ - xorl %ebp,%ebp /* clear stack frame ptr */ - - POSTCODE(VSTART_EXIT) - - call EXT(i386_init) /* run C code */ + call EXT(vstart) /* run C code */ /*NOTREACHED*/ hlt - /* * AP (slave) CPUs enter here. * @@ -593,237 +208,130 @@ LEXT(vstart) LEXT(slave_pstart) cli /* disable interrupts, so we don`t */ /* need IDT for a while */ + xor %ebp, %ebp // zero boot cpu + mov $EXT(mp_slave_stack)+PAGE_SIZE, %esp; + jmp paging - POSTCODE(SLAVE_PSTART_ENTRY) -/* - * Turn on paging. - */ -#ifdef PAE - movl %cr4, %eax - orl $(CR4_PAE), %eax - movl %eax, %cr4 - - movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */ - rdmsr /* MSR value return in edx: eax */ - orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */ - wrmsr /* Update Extended Feature Enable reg */ -#endif - movl $(0x4000),%eax /* tmp until we get mapped */ - movl %eax,%cr3 - movl %cr0,%eax - orl $(CR0_PG|CR0_WP|CR0_PE),%eax - movl %eax,%cr0 /* to enable paging */ +/* Code to get from real mode to protected mode */ - POSTCODE(SLAVE_PSTART_EXIT) - - movl $(EXT(spag_start)),%edx /* first paged code address */ - jmp *%edx /* flush prefetch queue */ - -/* - * We are now paging, and can run with correct addresses. - */ -LEXT(spag_start) +#define operand_size_prefix .byte 0x66 +#define address_size_prefix .byte 0x67 +#define cs_base_prefix .byte 0x2e - lgdt PA(EXT(gdtptr)) /* load GDT */ - lidt PA(EXT(idtptr)) /* load IDT */ - - LJMP(KERNEL_CS,EXT(slave_vstart)) /* switch to kernel code segment */ - - -/* - * Slave is now running with correct addresses. - */ -LEXT(slave_vstart) - - POSTCODE(SLAVE_VSTART_ENTRY) - -#ifdef PAE - movl PA(EXT(IdlePDPT)), %eax - movl %eax, %cr3 -#else - movl PA(EXT(IdlePTD)), %eax - movl %eax, %cr3 -#endif - - mov $(KERNEL_DS),%ax /* set kernel data segment */ - mov %ax,%ds - mov %ax,%es - mov %ax,%ss - - /* - * We're not quite through with the boot stack - * but we need to reset the stack pointer to the correct virtual - * address. - * And we need to offset above the address of pstart. - */ - movl $(VA(MP_BOOTSTACK+MP_BOOT+4)), %esp - -/* - * Switch to the per-cpu descriptor tables - */ - POSTCODE(SLAVE_VSTART_DESC_INIT) - - CPU_NUMBER_FROM_LAPIC(%eax) - movl CX(EXT(cpu_data_ptr),%eax),%ecx - - movw $(GDTSZ*8-1),0(%esp) /* set GDT size in GDT descriptor */ - movl CPU_DESC_INDEX+CDI_GDT(%ecx),%edx - movl %edx,2(%esp) /* point to local GDT (linear addr) */ - lgdt 0(%esp) /* load new GDT */ - - movw $(IDTSZ*8-1),0(%esp) /* set IDT size in IDT descriptor */ - movl CPU_DESC_INDEX+CDI_IDT(%ecx),%edx - movl %edx,2(%esp) /* point to local IDT (linear addr) */ - lidt 0(%esp) /* load new IDT */ - - movw $(KERNEL_LDT),%ax /* get LDT segment */ - lldt %ax /* load LDT */ - - movw $(KERNEL_TSS),%ax - ltr %ax /* load new KTSS */ - - mov $(CPU_DATA_GS),%ax - mov %ax,%gs - -/* - * Get stack top from pre-cpu data and switch - */ - POSTCODE(SLAVE_VSTART_STACK_SWITCH) - - movl %gs:CPU_INT_STACK_TOP,%esp - xorl %ebp,%ebp /* for completeness */ - - POSTCODE(SLAVE_VSTART_EXIT) - - call EXT(i386_init_slave) /* start MACH */ - /*NOTREACHED*/ - hlt +#undef LJMP +#define LJMP(segment,address) \ + operand_size_prefix ;\ + .byte 0xea ;\ + .long address-EXT(real_mode_bootstrap_base) ;\ + .word segment -/* - * Convert a descriptor from fake to real format. - * - * Calls from assembly code: - * %ebx = return address (physical) CANNOT USE STACK - * %esi = descriptor table address (physical) - * %ecx = number of descriptors - * - * Calls from C: - * 0(%esp) = return address - * 4(%esp) = descriptor table address (physical) - * 8(%esp) = number of descriptors - * - * Fake descriptor format: - * bytes 0..3 base 31..0 - * bytes 4..5 limit 15..0 - * byte 6 access byte 2 | limit 19..16 - * byte 7 access byte 1 - * - * Real descriptor format: - * bytes 0..1 limit 15..0 - * bytes 2..3 base 15..0 - * byte 4 base 23..16 - * byte 5 access byte 1 - * byte 6 access byte 2 | limit 19..16 - * byte 7 base 31..24 - * - * Fake gate format: - * bytes 0..3 offset - * bytes 4..5 selector - * byte 6 word count << 4 (to match fake descriptor) - * byte 7 access byte 1 - * - * Real gate format: - * bytes 0..1 offset 15..0 - * bytes 2..3 selector - * byte 4 word count - * byte 5 access byte 1 - * bytes 6..7 offset 31..16 - */ - .globl EXT(fix_desc) -LEXT(fix_desc) - pushl %ebp /* set up */ - movl %esp,%ebp /* stack frame */ - pushl %esi /* save registers */ - pushl %ebx - movl B_ARG0,%esi /* point to first descriptor */ - movl B_ARG1,%ecx /* get number of descriptors */ - lea 0f,%ebx /* get return address */ - jmp fix_desc_common /* call internal routine */ -0: popl %ebx /* restore registers */ - popl %esi - leave /* pop stack frame */ - ret /* return */ - -fix_desc_common: -0: - movw 6(%esi),%dx /* get access byte */ - movb %dh,%al - andb $0x14,%al - cmpb $0x04,%al /* gate or descriptor? */ - je 1f - -/* descriptor */ - movl 0(%esi),%eax /* get base in eax */ - rol $16,%eax /* swap 15..0 with 31..16 */ - /* (15..0 in correct place) */ - movb %al,%dl /* combine bits 23..16 with ACC1 */ - /* in dh/dl */ - movb %ah,7(%esi) /* store bits 31..24 in correct place */ - movw 4(%esi),%ax /* move limit bits 0..15 to word 0 */ - movl %eax,0(%esi) /* store (bytes 0..3 correct) */ - movw %dx,4(%esi) /* store bytes 4..5 */ - jmp 2f - -/* gate */ +#define LGDT(address) \ + cs_base_prefix ;\ + address_size_prefix ;\ + operand_size_prefix ;\ + .word 0x010f ;\ + .byte 0x15 ;\ + .long address-EXT(real_mode_bootstrap_base) + +.section __HIB,__text +.align 12 /* Page align for single bcopy_phys() */ +.code32 +Entry(real_mode_bootstrap_base) + cli + + LGDT(EXT(protected_mode_gdtr)) + + /* set the PE bit of CR0 */ + mov %cr0, %eax + inc %eax + mov %eax, %cr0 + + /* reload CS register */ + LJMP(KERNEL32_CS, 1f + REAL_MODE_BOOTSTRAP_OFFSET) 1: - movw 4(%esi),%ax /* get selector */ - shrb $4,%dl /* shift word count to proper place */ - movw %dx,4(%esi) /* store word count / ACC1 */ - movw 2(%esi),%dx /* get offset 16..31 */ - movw %dx,6(%esi) /* store in correct place */ - movw %ax,2(%esi) /* store selector in correct place */ -2: - addl $8,%esi /* bump to next descriptor */ - loop 0b /* repeat */ - jmp *%ebx /* all done */ - -/* - * put arg in kbd leds and spin a while - * eats eax, ecx, edx - */ -#define K_RDWR 0x60 -#define K_CMD_LEDS 0xed -#define K_STATUS 0x64 -#define K_IBUF_FULL 0x02 /* input (to kbd) buffer full */ -#define K_OBUF_FULL 0x01 /* output (from kbd) buffer full */ - -ENTRY(set_kbd_leds) - mov S_ARG0,%cl /* save led value */ - -0: inb $(K_STATUS),%al /* get kbd status */ - testb $(K_IBUF_FULL),%al /* input busy? */ - jne 0b /* loop until not */ - mov $(K_CMD_LEDS),%al /* K_CMD_LEDS */ - outb %al,$(K_RDWR) /* to kbd */ - -0: inb $(K_STATUS),%al /* get kbd status */ - testb $(K_OBUF_FULL),%al /* output present? */ - je 0b /* loop if not */ + /* we are in protected mode now */ + /* set up the segment registers */ + mov $KERNEL_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + mov $0, %ax + movw %ax, %fs + movw %ax, %gs + + POSTCODE(SLAVE_STARTPROG_ENTRY); + + mov PROT_MODE_START+REAL_MODE_BOOTSTRAP_OFFSET, %ecx + jmp *%ecx + +Entry(protected_mode_gdtr) + .short 160 /* limit (8*6 segs) */ + .long EXT(master_gdt) - inb $(K_RDWR),%al /* read status (and discard) */ +Entry(real_mode_bootstrap_end) -0: inb $(K_STATUS),%al /* get kbd status */ - testb $(K_IBUF_FULL),%al /* input busy? */ - jne 0b /* loop until not */ - - mov %cl,%al /* move led value */ - outb %al,$(K_RDWR) /* to kbd */ +.section __HIB,__text + .align ALIGN + .globl EXT(hibernate_machine_entrypoint) +LEXT(hibernate_machine_entrypoint) + mov %eax, %edi // save header pointer + /* restore gdt */ + lgdt EXT(protected_mode_gdtr) + + /* setup the protected mode segment registers */ + mov $KERNEL_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + mov $0,%ax /* fs must be zeroed; */ + mov %ax,%fs + mov %ax,%gs + + /* set up the page tables to use BootstrapPTD + * as done in idle_pt.c, but this must be done programatically */ + mov $EXT(IdlePDPT), %eax + mov $EXT(BootstrapPTD) + (INTEL_PTE_VALID), %ecx + mov $0x0, %edx + mov %ecx, (0*8+0)(%eax) + mov %edx, (0*8+4)(%eax) + add $(PAGE_SIZE), %ecx + mov %ecx, (1*8+0)(%eax) + mov %edx, (1*8+4)(%eax) + add $(PAGE_SIZE), %ecx + mov %ecx, (2*8+0)(%eax) + mov %edx, (2*8+4)(%eax) + add $(PAGE_SIZE), %ecx + mov %ecx, (3*8+0)(%eax) + mov %edx, (3*8+4)(%eax) + mov %eax, %cr3 + + + movl %cr4,%eax + orl $(CR4_PAE),%eax + movl %eax,%cr4 /* enable page size extensions */ - movl $10000000,%ecx /* spin */ -0: nop - nop - loop 0b /* a while */ + movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */ + rdmsr /* MSR value return in edx: eax */ + orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */ + wrmsr /* Update Extended Feature Enable reg */ - ret + movl %cr0, %eax + orl $(CR0_PG|CR0_WP), %eax + movl %eax, %cr0 /* ready paging */ + + mov $EXT(gIOHibernateRestoreStackEnd), %esp /* setup stack */ + xorl %ebp, %ebp /* zero frame pointer */ + + ljmpl $(KERNEL32_CS), $Ltemp +Ltemp: + xorl %eax, %eax /* Video memory - N/A */ + pushl %eax + pushl %eax + pushl %eax + mov %edi, %eax /* Pointer to hibernate header */ + pushl %eax + call EXT(hibernate_kernel_entrypoint) + /* NOTREACHED */ + hlt