xv6

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit c000f716d78d41d94e58a08c7cb57afef65d6d6f
parent 889fda3a3b6d827496a171d23355d5210aa03728
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 29 Dec 2013 04:02:15 -0800

32->64bit multiboot support

It appears most bootloaders still expect to start a 32bit protected mode image.
Qemu will refuse to even attempt to boot a 64bit multiboot wrapped ELF image.

This gets us from 32bit protected mode to IA-32e (oddly named) 64bit mode and
into the kernel.

- identity map the bottom 1GB of memory
- map the same 1GB at 0xFFFFFFFF80000000
- transfer control to kernel/main.c:main()

Diffstat:
Akernel/entry64.S | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/kernel64.ld | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 219 insertions(+), 0 deletions(-)

diff --git a/kernel/entry64.S b/kernel/entry64.S @@ -0,0 +1,154 @@ +/* entry64.S + * + * Copyright (c) 2013 Brian Swetland + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define mboot_magic 0x1badb002 +#define mboot_flags 0x00010000 + +.code32 +.global mboot_header +.global mboot_entry + +mboot_header: + .long mboot_magic + .long mboot_flags + .long (-mboot_magic -mboot_flags) # checksum + .long mboot_load_addr # header_addr + .long mboot_load_addr + .long mboot_load_end + .long mboot_bss_end + .long mboot_entry_addr + +mboot_entry: + +# zero 4 pages for our bootstrap page tables + xor %eax, %eax + mov $0x1000, %edi + mov $0x5000, %ecx + rep stosb + +# P4ML[0] -> 0x2000 (PDPT-A) + mov $(0x2000 | 3), %eax + mov %eax, 0x1000 + +# P4ML[511] -> 0x3000 (PDPT-B) + mov $(0x3000 | 3), %eax + mov %eax, 0x1FF8 + +# PDPT-A[0] -> 0x4000 (PD) + mov $(0x4000 | 3), %eax + mov %eax, 0x2000 + +# PDPT-B[510] -> 0x4000 (PD) + mov $(0x4000 | 3), %eax + mov %eax, 0x3FF0 + +# PD[0..511] -> 0..1022MB + mov $0x83, %eax + mov $0x4000, %ebx + mov $512, %ecx +ptbl_loop: + mov %eax, (%ebx) + add $0x200000, %eax + add $0x8, %ebx + dec %ecx + jnz ptbl_loop + +# CR3 -> 0x1000 (P4ML) + mov $0x1000, %eax + mov %eax, %cr3 + + lgdt (gdtr64 - mboot_header + mboot_load_addr) + +# Enable PAE - CR4.PAE=1 + mov %cr4, %eax + bts $5, %eax + mov %eax, %cr4 + +# enable long mode - EFER.LME=1 + mov $0xc0000080, %ecx + rdmsr + bts $8, %eax + wrmsr + +# enable paging + mov %cr0, %eax + bts $31, %eax + mov %eax, %cr0 + +# shift to 64bit segment + ljmp $8,$(entry64low - mboot_header + mboot_load_addr) + +.align 16 +gdtr64: + .word gdt64_end - gdt64_begin - 1; + .quad gdt64_begin - mboot_header + mboot_load_addr + +.align 16 +gdt64_begin: + .long 0x00000000 # 0: null desc + .long 0x00000000 + .long 0x00000000 # 1: Code, R/X, Nonconforming + .long 0x00209800 + .long 0x00000000 # 2: Data, R/W, Expand Down + .long 0x00009000 +gdt64_end: + +.align 16 +.code64 +entry64low: + movw $0x3f8, %dx + movb $'6', %al + out %al, (%dx) + + movq $entry64high, %rax + jmp *%rax + +.global _start +_start: +entry64high: + movw $0x3f8, %dx + movb $'4', %al + out %al, (%dx) + +# ensure data segment registers are sane + xor %rax, %rax + mov %ax, %ss + + mov $0x10, %rax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + +# setup initial stack + mov $0x00010000, %rax + mov %rax, %rsp + +# enter main() + jmp main + +# we should never return here... + jmp . + diff --git a/kernel/kernel64.ld b/kernel/kernel64.ld @@ -0,0 +1,65 @@ +/* Simple linker script for the JOS kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +/* OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) + +mboot_load_addr = 0x00100000; + +SECTIONS +{ + /* Link the kernel at this address: "." means the current address */ + /* Must be equal to KERNLINK */ + . = 0xFFFFFFFF80100000; + + PROVIDE(begin = .); + + .text : AT(mboot_load_addr) { + *(.text .rela.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + /* Conventionally, Unix linkers provide pseudo-symbols + * etext, edata, and end, at the end of the text, data, and bss. + * For the kernel mapping, we need the address at the beginning + * of the data section, but that's not one of the conventional + * symbols, because the convention started before there was a + * read-only rodata section between text and data. */ + PROVIDE(data = .); + + /* The data segment */ + .data : { + *(.data) + } + + . = ALIGN(0x1000); + + PROVIDE(edata = .); + + .bss : { + *(.bss) + *(COMMON) + } + + . = ALIGN(0x1000); + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .rela.eh_frame .note.GNU-stack) + } +} + +mboot_load_end = mboot_load_addr + (edata - begin); +mboot_bss_end = mboot_load_addr + (end - begin); +mboot_entry_addr = mboot_load_addr + (mboot_entry - begin);