]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/i386/start.s
xnu-2050.18.24.tar.gz
[apple/xnu.git] / osfmk / i386 / start.s
index 3218d3d15f577a719e089f29daf4a7f9ed442926..c8a9040388d120a4da276da9be8a7e37cb76ae85 100644 (file)
@@ -57,7 +57,6 @@
  */
 
 #include <platforms.h>
-#include <mach_kdb.h>
 
 #include <i386/asm.h>
 #include <i386/proc_reg.h>
 
 #define        CX(addr,reg)    addr(,reg,4)
 
-#include <i386/mp.h>
-#include <i386/mp_slave_boot.h>
+#include <i386/acpi.h>
 #include <i386/cpuid.h>
 
-/*
- * 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,109 +120,10 @@ 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)
-
-/*
- * 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.
  *     eax points to kernbootstruct
@@ -257,330 +135,57 @@ 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
+       mov             %ds, %bx
+       mov             %bx, %es
+       mov             %eax, %ebp              /* Move kernbootstruct to ebp */
+       mov             %eax, %ebx              /* get pointer to kernbootstruct */
 
-       .text
-       .globl __start
-       .set __start, PA(EXT(_pstart))
-
-/*
- * 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    %cr0,%eax                       /* paging */
+       orl     $(CR0_PG|CR0_WP),%eax
+       movl    %eax,%cr0
 
-       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    $(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 */
+       POSTCODE(PSTART_VSTART)
        
-       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 +198,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 */
-
-       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)
-
-       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 */
+/* Code to get from real mode to protected mode */
 
-       mov     $(CPU_DATA_GS),%ax
-       mov     %ax,%gs
+#define        operand_size_prefix     .byte 0x66
+#define        address_size_prefix     .byte 0x67
+#define        cs_base_prefix          .byte 0x2e
 
-/*
- * 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(BootPTD) + (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