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:
A | kernel/entry64.S | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | kernel/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);