boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

kernel.S (10640B)


      1 .section .note.Xen, "a"
      2 .align 4
      3     .long 4
      4     .long 4
      5     .long 18
      6     .ascii "Xen\0"
      7     .long _start
      8 
      9 .section .text, "ax"
     10 .globl _start
     11 _start:
     12     /* QEMU's PVH path enters this address in 32-bit protected mode.
     13      * Keep this transition stub as raw encodings so the same source can
     14      * be assembled by TCC's x86_64-only assembler. */
     15     .byte 0xfa                         /* cli */
     16     .byte 0xbc; .long boot_stack_top    /* movl $boot_stack_top,%esp */
     17     .byte 0x0f,0x01,0x15; .long boot_gdt64_ptr
     18                                         /* lgdt boot_gdt64_ptr */
     19     .byte 0x0f,0x20,0xe0               /* movl %cr4,%eax */
     20     .byte 0x83,0xc8,0x20               /* orl $0x20,%eax */
     21     .byte 0x0f,0x22,0xe0               /* movl %eax,%cr4 */
     22 
     23     .byte 0xbf; .long boot_pml4         /* movl $boot_pml4,%edi */
     24     .byte 0x31,0xc0                    /* xorl %eax,%eax */
     25     .byte 0xb9; .long 0x1800            /* movl $(6*4096/4),%ecx */
     26     .byte 0xf3,0xab                    /* rep stosl */
     27 
     28     .byte 0xc7,0x05; .long boot_pml4;        .long boot_pdpt + 0x003
     29     .byte 0xc7,0x05; .long boot_pml4 + 4;    .long 0
     30     .byte 0xc7,0x05; .long boot_pml4 + 2048; .long boot_pdpt + 0x003
     31     .byte 0xc7,0x05; .long boot_pml4 + 2052; .long 0
     32 
     33     .byte 0xc7,0x05; .long boot_pdpt;      .long boot_pd0 + 0x003
     34     .byte 0xc7,0x05; .long boot_pdpt + 4;  .long 0
     35     .byte 0xc7,0x05; .long boot_pdpt + 8;  .long boot_pd1 + 0x003
     36     .byte 0xc7,0x05; .long boot_pdpt + 12; .long 0
     37     .byte 0xc7,0x05; .long boot_pdpt + 16; .long boot_pd2 + 0x003
     38     .byte 0xc7,0x05; .long boot_pdpt + 20; .long 0
     39     .byte 0xc7,0x05; .long boot_pdpt + 24; .long boot_pd3 + 0x003
     40     .byte 0xc7,0x05; .long boot_pdpt + 28; .long 0
     41 
     42     .byte 0xbf; .long boot_pd0          /* movl $boot_pd0,%edi */
     43     .byte 0xb8; .long 0x083             /* movl $0x83,%eax */
     44     .byte 0xb9; .long 2048              /* movl $2048,%ecx */
     45 1:
     46     .byte 0x89,0x07                    /* movl %eax,(%edi) */
     47     .byte 0xc7,0x47,0x04; .long 0       /* movl $0,4(%edi) */
     48     .byte 0x05; .long 0x200000          /* addl $0x200000,%eax */
     49     .byte 0x83,0xc7,0x08               /* addl $8,%edi */
     50     .byte 0xe2,0xed                    /* loop 1b */
     51 
     52     .byte 0xb8; .long boot_pml4         /* movl $boot_pml4,%eax */
     53     .byte 0x0f,0x22,0xd8               /* movl %eax,%cr3 */
     54     .byte 0xb9; .long 0xc0000080        /* movl $0xc0000080,%ecx */
     55     .byte 0x0f,0x32                    /* rdmsr */
     56     .byte 0x0d; .long 0x100             /* orl $0x100,%eax */
     57     .byte 0x0f,0x30                    /* wrmsr */
     58     .byte 0x0f,0x20,0xc0               /* movl %cr0,%eax */
     59     .byte 0x0d; .long 0x80000001        /* orl $0x80000001,%eax */
     60     .byte 0x0f,0x22,0xc0               /* movl %eax,%cr0 */
     61     .byte 0xea; .long long_mode; .word 0x08
     62                                         /* ljmp $0x08,$long_mode */
     63 long_mode:
     64     /* PVH entry hands us the hvm_start_info phys addr in ebx; preserve
     65      * it through long-mode init (zero-extend to rbx) so kmain can pull
     66      * `cmdline_paddr` out of it. The boot code above never touches ebx,
     67      * so the value survives all the way down here. */
     68     movl %ebx, %ebx
     69     movw $0x10, %ax
     70     movw %ax, %ds
     71     movw %ax, %es
     72     movw %ax, %ss
     73     movq $kstack_top, %rsp
     74 
     75     /* Enable SSE/SSE2 for user mode. tcc-emitted user binaries (tcc3,
     76      * scheme1) save callee-saved xmm regs in every function prologue,
     77      * so the first user `movq %xmm7, ...` would otherwise trap with
     78      * #UD or #NM. CR0.MP=1, EM=0; CR4.OSFXSR=1, OSXMMEXCPT=1. The
     79      * gcc-built kernel + `-mno-sse` user (user/hello.c) avoided this
     80      * because gcc never emitted SSE; tcc has no equivalent flag. */
     81     .byte 0x0f,0x20,0xc0              /* movq %cr0, %rax */
     82     andq $~4, %rax
     83     orq  $2, %rax
     84     .byte 0x0f,0x22,0xc0              /* movq %rax, %cr0 */
     85     .byte 0x0f,0x20,0xe0              /* movq %cr4, %rax */
     86     orq  $0x600, %rax
     87     .byte 0x0f,0x22,0xe0              /* movq %rax, %cr4 */
     88 
     89     call amd64_serial_init
     90 
     91     movq $__bss_start, %rdi
     92     movq $_end, %rsi
     93     xorl %eax, %eax
     94 1:
     95     cmpq %rsi, %rdi
     96     jae 2f
     97     movq %rax, (%rdi)
     98     addq $8, %rdi
     99     jmp 1b
    100 2:
    101     movq %rbx, %rdi
    102     call kmain
    103 
    104 3:
    105     hlt
    106     jmp 3b
    107 
    108 .globl amd64_int80
    109 amd64_int80:
    110     subq $216, %rsp
    111     movq %rax, 48(%rsp)
    112     movq 216(%rsp), %r11
    113     movq %r11, 192(%rsp)
    114     movq 232(%rsp), %r11
    115     movq %r11, 200(%rsp)
    116     movq 240(%rsp), %r11
    117     movq %r11, saved_user_sp(%rip)
    118 
    119     movq %rdi, 0(%rsp)
    120     movq %rsi, 8(%rsp)
    121     movq %rdx, 16(%rsp)
    122     movq %r10, 24(%rsp)
    123     movq %r8,  32(%rsp)
    124     movq %r9,  40(%rsp)
    125     movq %rbx, 56(%rsp)
    126     movq %rcx, 64(%rsp)
    127     movq %r11, 72(%rsp)
    128     movq %r12, 80(%rsp)
    129     movq %r13, 88(%rsp)
    130     movq %r14, 96(%rsp)
    131     movq %r15, 104(%rsp)
    132     movq %rbp, 112(%rsp)
    133 
    134     xorl %edi, %edi
    135     movq %rsp, %rsi
    136     call trap_sync
    137 
    138     movq 192(%rsp), %rax
    139     movq %rax, 216(%rsp)
    140     movq 200(%rsp), %rax
    141     movq %rax, 232(%rsp)
    142     movq saved_user_sp(%rip), %rax
    143     movq %rax, 240(%rsp)
    144 
    145     movq 0(%rsp), %rdi
    146     movq 8(%rsp), %rsi
    147     movq 16(%rsp), %rdx
    148     movq 24(%rsp), %r10
    149     movq 32(%rsp), %r8
    150     movq 40(%rsp), %r9
    151     movq 48(%rsp), %rax
    152     movq 56(%rsp), %rbx
    153     movq 64(%rsp), %rcx
    154     movq 72(%rsp), %r11
    155     movq 80(%rsp), %r12
    156     movq 88(%rsp), %r13
    157     movq 96(%rsp), %r14
    158     movq 104(%rsp), %r15
    159     movq 112(%rsp), %rbp
    160     addq $216, %rsp
    161     .byte 0x48,0xcf                  /* iretq */
    162 
    163 /* `syscall` entry point. Reached via MSR_LSTAR after EFER.SCE is set
    164  * by mmu.c's setup_cpu_tables(). On entry: rcx=user RIP, r11=user RFLAGS,
    165  * CS/SS reloaded from STAR, but RSP is still the user stack — we save
    166  * it to saved_user_sp and switch to kstack manually. The trapframe
    167  * mirrors amd64_int80's so trap_sync sees a uniform shape regardless
    168  * of whether userland used `int $0x80` or `syscall`. */
    169 .globl amd64_syscall_entry
    170 amd64_syscall_entry:
    171     movq %rsp, saved_user_sp(%rip)
    172     movq $kstack_top, %rsp
    173 
    174     subq $216, %rsp
    175     movq %rcx, 192(%rsp)
    176     movq %r11, 200(%rsp)
    177 
    178     movq %rdi, 0(%rsp)
    179     movq %rsi, 8(%rsp)
    180     movq %rdx, 16(%rsp)
    181     movq %r10, 24(%rsp)
    182     movq %r8,  32(%rsp)
    183     movq %r9,  40(%rsp)
    184     movq %rax, 48(%rsp)
    185     movq %rbx, 56(%rsp)
    186     movq %rcx, 64(%rsp)
    187     movq %r11, 72(%rsp)
    188     movq %r12, 80(%rsp)
    189     movq %r13, 88(%rsp)
    190     movq %r14, 96(%rsp)
    191     movq %r15, 104(%rsp)
    192     movq %rbp, 112(%rsp)
    193 
    194     xorl %edi, %edi
    195     movq %rsp, %rsi
    196     call trap_sync
    197 
    198     movq 0(%rsp), %rdi
    199     movq 8(%rsp), %rsi
    200     movq 16(%rsp), %rdx
    201     movq 24(%rsp), %r10
    202     movq 32(%rsp), %r8
    203     movq 40(%rsp), %r9
    204     movq 48(%rsp), %rax
    205     movq 56(%rsp), %rbx
    206     movq 80(%rsp), %r12
    207     movq 88(%rsp), %r13
    208     movq 96(%rsp), %r14
    209     movq 104(%rsp), %r15
    210     movq 112(%rsp), %rbp
    211 
    212     movq 192(%rsp), %rcx
    213     movq 200(%rsp), %r11
    214     addq $216, %rsp
    215 
    216     movq saved_user_sp(%rip), %rsp
    217     .byte 0x48,0x0f,0x07              /* sysretq */
    218 
    219 .globl amd64_wrmsr
    220 amd64_wrmsr:
    221     /* amd64_wrmsr(u32 msr, u64 val) */
    222     movl %edi, %ecx
    223     movq %rsi, %rax
    224     movq %rsi, %rdx
    225     shrq $32, %rdx
    226     .byte 0x0f,0x30                   /* wrmsr */
    227     ret
    228 
    229 .globl amd64_rdmsr
    230 amd64_rdmsr:
    231     /* u64 amd64_rdmsr(u32 msr) */
    232     movl %edi, %ecx
    233     .byte 0x0f,0x32                   /* rdmsr */
    234     shlq $32, %rdx
    235     orq %rdx, %rax
    236     ret
    237 
    238 .globl amd64_unhandled
    239 amd64_unhandled:
    240     subq $216, %rsp
    241     movq 216(%rsp), %rax
    242     movq %rax, 192(%rsp)
    243     movq 232(%rsp), %rax
    244     movq %rax, 200(%rsp)
    245     movq $0xdead, %rdi
    246     movq %rsp, %rsi
    247     call trap_unhandled
    248 1:
    249     hlt
    250     jmp 1b
    251 
    252 .globl eret_to_user
    253 eret_to_user:
    254     movq %rsi, saved_user_sp(%rip)
    255     movq $kstack_top, %rsp
    256     pushq $0x1b
    257     pushq %rsi
    258     pushq $0x202
    259     pushq $0x23
    260     pushq %rdi
    261     xorl %eax, %eax
    262     xorl %ebx, %ebx
    263     xorl %ecx, %ecx
    264     xorl %edx, %edx
    265     xorl %esi, %esi
    266     xorl %edi, %edi
    267     xorl %ebp, %ebp
    268     xorq %r8, %r8
    269     xorq %r9, %r9
    270     xorq %r10, %r10
    271     xorq %r11, %r11
    272     xorq %r12, %r12
    273     xorq %r13, %r13
    274     xorq %r14, %r14
    275     xorq %r15, %r15
    276     .byte 0x48,0xcf                  /* iretq */
    277 
    278 /* C-callable thunks. arch.h synthesizes the arch_*() API on top of these
    279  * (mirrors aarch64's sysreg_read/arm64_barrier/cpu_pause primitive set). */
    280 
    281 /* PAUSE_* — matches arch.h enum. */
    282 #define PAUSE_PAUSE 0
    283 #define PAUSE_HLT   1
    284 
    285 .globl cpu_pause
    286 cpu_pause:
    287     cmpl $PAUSE_HLT, %edi
    288     je .Lp_hlt
    289     pause
    290     ret
    291 .Lp_hlt:
    292     hlt
    293     ret
    294 
    295 /* BAR_* — matches arch.h enum. */
    296 #define BAR_WMB 0
    297 #define BAR_RMB 1
    298 
    299 .globl amd64_fence
    300 amd64_fence:
    301     cmpl $BAR_RMB, %edi
    302     je .Lf_rmb
    303     sfence
    304     ret
    305 .Lf_rmb:
    306     lfence
    307     ret
    308 
    309 .globl amd64_read_cr2
    310 amd64_read_cr2:
    311     movq %cr2, %rax
    312     ret
    313 
    314 .globl arch_system_off
    315 arch_system_off:
    316     movw $0x501, %dx
    317     movw $0x31, %ax
    318     outw %ax, %dx
    319 1:
    320     hlt
    321     jmp 1b
    322 
    323 .globl amd64_outb
    324 amd64_outb:
    325     movw %di, %dx
    326     movb %sil, %al
    327     outb %al, %dx
    328     ret
    329 
    330 .globl amd64_inb
    331 amd64_inb:
    332     movw %di, %dx
    333     xorl %eax, %eax
    334     inb %dx, %al
    335     ret
    336 
    337 .globl amd64_load_cr3
    338 amd64_load_cr3:
    339     movq %rdi, %cr3
    340     ret
    341 
    342 .globl amd64_lgdt
    343 amd64_lgdt:
    344     lgdt (%rdi)
    345     movw $0x10, %ax
    346     movw %ax, %ds
    347     movw %ax, %es
    348     movw %ax, %ss
    349     pushq $0x08
    350     leaq 1f(%rip), %rax
    351     pushq %rax
    352     .byte 0x48,0xcb                  /* lretq */
    353 1:
    354     ret
    355 
    356 .globl amd64_lidt
    357 amd64_lidt:
    358     lidt (%rdi)
    359     ret
    360 
    361 .globl amd64_ltr
    362 amd64_ltr:
    363     ltr %di
    364     ret
    365 
    366 amd64_serial_init:
    367     movw $0x3f9, %dx
    368     xorb %al, %al
    369     outb %al, %dx
    370     movw $0x3fb, %dx
    371     movb $0x80, %al
    372     outb %al, %dx
    373     movw $0x3f8, %dx
    374     movb $0x01, %al
    375     outb %al, %dx
    376     movw $0x3f9, %dx
    377     xorb %al, %al
    378     outb %al, %dx
    379     movw $0x3fb, %dx
    380     movb $0x03, %al
    381     outb %al, %dx
    382     movw $0x3fa, %dx
    383     movb $0xc7, %al
    384     outb %al, %dx
    385     movw $0x3fc, %dx
    386     movb $0x0b, %al
    387     outb %al, %dx
    388     ret
    389 
    390 .section .rodata, "a"
    391 .align 8
    392 boot_gdt64:
    393     /* null, 64-bit code (P=1,DPL=0,S=1,type=A; G=1,L=1; limit=0xfffff),
    394      * 64-bit data (P=1,DPL=0,S=1,type=2; G=1,limit=0xfffff). */
    395     .quad 0
    396     .quad 0x00af9a000000ffff
    397     .quad 0x00af92000000ffff
    398 boot_gdt64_ptr:
    399     .word boot_gdt64_ptr - boot_gdt64 - 1
    400     .long boot_gdt64
    401 
    402 .section .data, "aw"
    403 .align 4096
    404 boot_pml4:
    405     .skip 4096
    406 
    407 .align 4096
    408 boot_pdpt:
    409     .skip 4096
    410 
    411 .align 4096
    412 boot_pd0:
    413     .skip 4096
    414 .align 4096
    415 boot_pd1:
    416     .skip 4096
    417 .align 4096
    418 boot_pd2:
    419     .skip 4096
    420 .align 4096
    421 boot_pd3:
    422     .skip 4096
    423 
    424 .section .bss, "aw", @nobits
    425 .align 16
    426 .globl saved_user_sp
    427 saved_user_sp:
    428     .skip 8
    429 .align 16
    430 .skip 0x10000
    431 .globl kstack_top
    432 kstack_top:
    433 .align 16
    434 .skip 0x4000
    435 boot_stack_top: