1 /*
   2  * Parts copyright Michael Brown <mbrown@fensystems.co.uk>
   3  *
   4  * Copyright 2020, Joyent, Inc.
   5  */
   6 
   7 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
   8 
   9 /* CR0: protection enabled */
  10 #define CR0_PE ( 1 << 0 )
  11 
  12 /* CR0: paging */
  13 #define CR0_PG ( 1 << 31 )
  14 
  15 /* CR4: physical address extensions */
  16 #define CR4_PSE ( 1 << 4 )
  17 #define CR4_PAE ( 1 << 5 )
  18 #define CR4_PGE ( 1 << 7 )
  19 
  20 /* Extended feature enable MSR (EFER) */
  21 #define MSR_EFER 0xc0000080
  22 
  23 /* EFER: long mode enable */
  24 #define EFER_LME ( 1 << 8 )
  25 
  26 #define GDTSEL_CODE 0x8
  27 #define GDTSEL_DATA 0x10
  28 
  29 #if defined(PXE_EFI) && defined(__x86_64__)
  30 
  31         .section ".text", "ax", @progbits
  32 
  33         .data
  34 
  35 newcs_vector:
  36         .long   newcs, GDTSEL_CODE
  37 
  38 entry_gdt:
  39         /* null entry */
  40         .word   0x0, 0x0
  41         .byte   0x0, 0x0, 0x0, 0x0
  42 
  43         /* 32 bit protected mode code segment */
  44         .word   0xffff, 0x0
  45         .byte   0x0, 0x9f, 0xcf, 0x0
  46 
  47         /* 32 bit protected mode data segment */
  48         .word   0xffff, 0x0
  49         .byte   0x0, 0x93, 0xcf, 0x0
  50 
  51 entry_gdt_end:
  52         .equ    entry_gdt_length, entry_gdt_end - entry_gdt
  53 
  54 entry_gdtr:
  55         .word entry_gdt_length - 1
  56 entry_gdt_base:
  57         .quad 0
  58 
  59         /*
  60          * %rdi -> struct mb2 *
  61          * %rsi -> stack pointer to switch to
  62          * %rdx -> &multiboot2_enter_kernel
  63          */
  64         .code64
  65         .globl multiboot2_bounce
  66 
  67 multiboot2_bounce:
  68         movq    %rsi, %rsp
  69         jmp     *%rdx
  70 
  71         /*
  72          * %rdi -> multiboot2 magic
  73          * %rsi -> multiboot info pointer
  74          * %rdx -> entry address (32 bits)
  75          *
  76          *
  77          * We need to transition from our 64-bit environment into the one
  78          * defined by the multiboot2 spec, section 3.3. Namely, drop down to
  79          * 32-bit protected mode with a basic GDT, paging disabled, interrupts
  80          * off, and
  81          *
  82          * %eax -> multiboot2 magic
  83          * %ebx -> multiboot info pointer (physical)
  84          */
  85         .globl multiboot2_entry
  86 
  87 multiboot2_entry:
  88         cli
  89 
  90         movq    %rsi, %rbx /* mb2 infop */
  91         movq    %rdx, %rsi /* entry address */
  92 
  93         /* Load the mb2-mandated code and data segments.  */
  94         leaq    entry_gdt_base(%rip), %rcx
  95         leaq    entry_gdt(%rip), %rax
  96         movq    %rax, (%rcx)
  97 
  98         leaq    entry_gdtr(%rip), %rax
  99         lgdt    (%rax)
 100 
 101         /* Load our new %cs. */
 102         ljmp    *newcs_vector
 103 
 104         .code32
 105 newcs:
 106 
 107         movw    $GDTSEL_DATA, %ax
 108         movw    %ax, %ds
 109         movw    %ax, %es
 110         movw    %ax, %fs
 111         movw    %ax, %gs
 112         movw    %ax, %ss
 113 
 114         /* Disable paging */
 115         movl    %cr0, %eax
 116         andl    $~CR0_PG, %eax
 117         movl    %eax, %cr0
 118 
 119         movl    %cr4, %eax
 120         andb    $~(CR4_PAE | CR4_PGE | CR4_PSE), %al
 121         movl    %eax, %cr4
 122 
 123         /* Disable long mode (clobbers %eax, %edx) */
 124         movl    $MSR_EFER, %ecx
 125         rdmsr
 126         andw    $~EFER_LME, %ax
 127         wrmsr
 128 
 129         /* %ebx still has our infop */
 130         movl    %edi, %eax
 131         jmp     *%esi
 132 
 133 #endif /* PXE_EFI && __x86_64__ */