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: