http://wiki.osdev.org/Creating_a_64-bit_kernelCreating a 64-bit kernelFrom OSDev Wiki
PrerequisitesMake sure that you have the following done before proceeding:
The Main KernelThe kernel should run in a uniform environment. Let's make this simple for now... kmain.cvoid kmain(void) { /* What goes here is up to you */ } CompilingCompile each source file like any piece of C code, just remember to use the cross-compiler and the proper options. Linking will be done later... x86_64-pc-elf-gcc -ffreestanding -mcmodel=large -nostdlib <other options> -c -o <object file> <source file> The -mcmodel=large argument enables us to run the kernel at any 64-bit virtual memory address we want (only in GCC 4.3+), and -nostdlib makes sure that GCC doesn't add any unneeded crap to our kernel. LinkingThe kernel will be linked as an elf64-x86-64 executable, to run at a virtual higher-half address. Let's use a linker script... link.ldOUTPUT_FORMAT(elf64-x86-64) ENTRY(kmain) SECTIONS { . = KERNEL_VMA; .text : AT(ADDR(.text) - KERNEL_VMA) { _code = .; *(.text) *(.rodata*) . = ALIGN(4096); } .data : AT(ADDR(.data) - KERNEL_VMA) { _data = .; *(.data) . = ALIGN(4096); } .ehframe : AT(ADDR(.ehframe) - KERNEL_VMA) { _ehframe = .; *(.ehframe) . = ALIGN(4096); } .bss : AT(ADDR(.bss) - KERNEL_VMA) { _bss = .; *(.bss) . = ALIGN(4096); } _end = .; /DISCARD/ : { *(.comment) } } Feel free to edit this linker script to suit your needs. Set ENTRY(...) to your entry function, and KERNEL_VMA to your base virtual address. Now link with the following: x86_64-pc-elf-ld -nostdlib -nodefaultlibs <other options> -T <linker script> -o <kernel executable> <all object files> Congratulations! Your kernel has been compiled! LoadingBefore you can actually use your kernel, you need to deal with the hard job of loading it. Here are your three options: With your own boot loaderThis method is the simplest (since you write all the code), though it requires the most work. I won't give any code, but the basic outline is:
With a separate loaderThis requires the use of GRUB or another multiboot1-compliant loader. This may be the most error free of the three. A quick rundown:
Note that this code has to be compiled as elf32 and must contain the multiboot1-header. Either compile with i*86-elf-gcc or x86_64-pc-elf-gcc -m32 Also remember to set the text section to start at 0x100000 (-Ttext 0x100000) when linking your loader. Set up GRUB to boot your loader as a kernel in its own right, and your actual kernel as a module. Something like this in menu.lst: title My Kernel kernel --type=multiboot <loader executable> module <kernel executable> With a 32-bit bootstrap in your kernelThis requires the use of any ELF64-compatible loader that loads into protected-mode (GRUB2, or patched GRUB Legacy). This may be the simplest in the long run, but is hell to set up (well, it was for me - but I saved you some work ;). Note that GRUB2 is still in beta and unreliably implements the multiboot draft or the original multiboot specification. Highly recommended that you use the latest CVS version. First, create an assembly file like the following, which will set up virtual addressing and long mode: bootstrap.S.section .text .code32 multiboot_header: (only needed if you're using multiboot) bootstrap: (32-bit to 64-bit code goes here) (jump to 64-bit code) Then, add the following to your original linker file: link.ld... ENTRY(bootstrap) ... SECTIONS { . = KERNEL_LMA; .bootstrap : { <path of bootstrap object> (.text) } . += KERNEL_VMA; .text : AT(ADDR(.text) - KERNEL_VMA) { _code = .; *(EXCLUDE_FILE(*<path of bootstrap object>) .text) *(.rodata*) . = ALIGN(4096); } ... The above edits allow the linker to link the bootstrap code with physical addressing, as virtual addressing is set up by the bootstrap. Note that in this case, KERNEL_VMA will be equivalent to 0x0, meaning that text would have a virtual address at KERNEL_LMA + KERNEL_VMA instead of just at KERNEL_VMA. Change '+=' to '=' and your bootstrap code if you do not want this behaviour. Compile and link as usual, just remember to compile the bootstrap code as well! Set up GRUB2 to boot your kernel (depends on your bootloader) with grub.cfg: menuentry "My Kernel" { multiboot <kernel executable> } Possible ProblemsYou may experience some problems. Fix them immediately or risk spending a lot of time debugging later... My kernel is way too big!!!Try each of the following, in order:
See AlsoArticlesThreads
|