diff options
Diffstat (limited to 'entry.S')
-rw-r--r-- | entry.S | 245 |
1 files changed, 22 insertions, 223 deletions
@@ -1,223 +1,22 @@ -# x86-64 bootstrap, assuming load by MultiBoot-compliant loader. -# The MutliBoot specification is at: -# http://www.gnu.org/software/grub/manual/multiboot/multiboot.html -# GRUB is a MultiBoot loader, as is qemu's -kernel option. - -#include "mmu.h" -#include "memlayout.h" - -# STACK is the size of the bootstrap stack. -#define STACK 8192 - -# MultiBoot header. -# http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-layout -.align 4 -.text -.globl multiboot_header -multiboot_header: - #define magic 0x1badb002 - #define flags (1<<16 | 1<<0) - .long magic - .long flags - .long (- magic - flags) # checksum - .long V2P_WO(multiboot_header) # header address - .long V2P_WO(multiboot_header) # load address - .long V2P_WO(edata) # load end address - .long V2P_WO(end) # bss end address - .long V2P_WO(start) # entry address - -# Entry point jumped to by boot loader. Running in 32-bit mode. -# http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Machine-state -# -# EAX = 0x2badb002 -# EBX = address of multiboot information structure -# CS = 32-bit read/execute code segment with identity map -# DS, ES, FS, GS, SS = 32-bit read/write data segment with identity map -# A20 gate = enabled -# CR0 = PE set, PG clear -# EFLAGS = VM clear, IF clear -# -.code32 -.globl start -start: - # Tell BIOS to do "warm reboot" when we shut down. - movw $0x1234, 0x472 - - # Set up multiboot arguments for main. - movl %eax, %edi - movl %ebx, %esi - - # Initialize stack. - movl $V2P_WO(stack+STACK), %esp - - # Zero bss. QEMU's MultiBoot seems not to. - # It's possible that the header above is not right, but it looks right. - # %edi is holding multiboot argument, so save in another register. - # (The stack is in the bss.) - movl %edi, %edx - movl $V2P_WO(edata), %edi - movl $V2P_WO(end), %ecx - subl $V2P_WO(edata), %ecx - movl $0, %eax - cld - rep stosb - movl %edx, %edi - - call loadgdt - - # Enter new 32-bit code segment (already in 32-bit mode). - ljmp $SEG_KCODE32, $V2P_WO(start32) // code32 segment selector - -start32: - # Initialize page table. - call initpagetables - call init32e - - movl $V2P_WO(start64), %eax - # Enter 64-bit mode. - ljmp $SEG_KCODE, $V2P_WO(tramp64) // code64 segment selector - -.code64 -start64: - # Load VA of stack - movabsq $(stack+STACK), %rsp - # Clear frame pointer for stack walks - movl $0, %ebp - # Call into C code. - call main - # should not return from main - jmp . - -.code32 -.global apstart -apstart: - call loadgdt - ljmp $SEG_KCODE32, $V2P_WO(apstart32) // code32 segment selector - -apstart32: - call init32e - movl $V2P_WO(apstart64), %eax - ljmp $SEG_KCODE, $V2P_WO(tramp64) // code64 segment selector - -.code64 -apstart64: - # Remember (from bootothers), that our kernel stack pointer is - # at the top of our temporary stack. - popq %rax - movq %rax, %rsp - movq $0, %rbp - call apmain - jmp . - -.code64 -tramp64: - # The linker thinks we are running at tramp64, but we're actually - # running at PADDR(tramp64), so use an explicit calculation to - # load and jump to the correct address. %rax should hold the - # physical address of the jmp target. - movq $KERNBASE, %r11 - addq %r11, %rax - jmp *%rax - -# Initial stack -.comm stack, STACK - -# Page tables. See section 4.5 of 253668.pdf. -# We map the first GB of physical memory at 0 and at 1 TB (not GB) before -# the end of virtual memory. At boot time we are using the mapping at 0 -# but during ordinary execution we use the high mapping. -# The intent is that after bootstrap the kernel can expand this mapping -# to cover all the available physical memory. -# This would be easier if we could use the PS bit to create GB-sized entries -# and skip the pdt table, but not all chips support it, and QEMU doesn't. -.align 4096 -pml4: - .quad V2P_WO(pdpt) + PTE_P + PTE_W // present, read/write - .quad 0 - .space 4096 - 2*16 - .quad V2P_WO(pdpt) + PTE_P + PTE_W - .quad 0 - -.align 4096 -pdpt: - .quad V2P_WO(pdt) + PTE_P + PTE_W - .space 4096 - 8 - -.align 4096 -pdt: - // Filled in below. - .space 4096 - -.code32 -initpagetables: - pushl %edi - pushl %ecx - pushl %eax - - // Set up 64-bit entry in %edx:%eax. - // Base address 0, present, read/write, large page. - movl $(0 | PTE_P | PTE_W | PTE_PS), %eax - movl $0, %edx - - // Fill in 512 entries at pdt. - movl $V2P_WO(pdt), %edi - movl $512, %ecx -1: - // Write this 64-bit entry. - movl %eax, 0(%edi) - movl %edx, 4(%edi) - addl $8, %edi - // 64-bit add to prepare address for next entry. - // Because this is a large page entry, it covers 512 4k pages (2 MB). - add $(512*4096), %eax - adc $0, %edx - loop 1b - - popl %eax - popl %ecx - popl %edi - ret - -# Initialize IA-32e mode. See section 9.8.5 of 253668.pdf. -init32e: - # Set CR4.PAE and CR4.PSE = 1. - movl %cr4, %eax - orl $0x30, %eax - movl %eax, %cr4 - - # Load CR3 with physical base address of level 4 page table. - movl $V2P_WO(pml4), %eax - movl %eax, %cr3 - - # Enable IA-32e mode by setting IA32_EFER.LME = 1. - # Also turn on IA32_EFER.SCE (syscall enable). - movl $0xc0000080, %ecx - rdmsr - orl $0x101, %eax - wrmsr - - # Enable paging by setting CR0.PG = 1. - movl %cr0, %eax - orl $0x80000000, %eax - movl %eax, %cr0 - nop - nop - - ret - -loadgdt: - subl $8, %esp - movl $V2P_WO(bootgdt), 4(%esp) - movw $(8*NSEGS-1), 2(%esp) - lgdt 2(%esp) - addl $8, %esp - - movl $SEG_KDATA, %eax // data segment selector - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movl $0, %eax // null segment selector - movw %ax, %fs - movw %ax, %gs - - ret + # qemu -kernel starts at 0x1000. the instructions + # there seem to be provided by qemu, as if it + # were a ROM. the code at 0x1000 jumps to + # 0x8000000, the _start function here, + # in machine mode. +.section .data +.globl stack0 +.section .text +.globl mstart +.section .text +.globl _entry +_entry: + # set up a stack for C; stack0 is declared in start. + la sp, stack0 + addi sp, sp, 1024 + addi sp, sp, 1024 + addi sp, sp, 1024 + addi sp, sp, 1024 + # jump to mstart() in start.c + call mstart +junk: + j junk |