Higher Half x86 Bare Bones (Backup): Difference between revisions

add maintenance template
[unchecked revision][unchecked revision]
No edit summary
(add maintenance template)
 
(35 intermediate revisions by 19 users not shown)
Line 1:
{{Disputed|Talk:Higher_Half_x86_Bare_Bones}}
Here is some sample code for a kernel that is loaded by GRUB and is mapped in the upper half of memory. In this case, the kernel is loaded at 1MB in the physical address space (0x00100000), but is mapped at 3GB + 1MB in the virtual address space (0xC0100000). It is recommended that you have a firm grasp of the contents within the [[Tutorial:Bare bones|Bare bones tutorial]] before attempting this.
{{FirstPerson}}
{{TutorialExplain}}
{{BeginnersWarning}}
{{You}}
{{Rating|2}}
 
Here is some sample code for a kernel that is loaded by GRUB and is mapped in the upper half of memory. In this case, the kernel is loaded at 1MB in the physical address space (0x00100000), but is mapped at 3GB + 1MB in the virtual address space (0xC0100000). It is recommended that you have a firm grasp of the contents within the [[Tutorial:Bare bones|Bare bones tutorial]] and [[Paging]] before attempting this.
 
==loader.asm==
This piece of code is taking over control from the Multiboot bootloader. It sets up a page directory with page table entries that identity map the first 4MB, and also map the first 4MB to virtual 3GB. After setting up paging, it unmaps the identity mapping so that the kernel is entirely in the higher half and jumps into the kernel proper.
 
<syntaxhighlight lang="asm">
<pre>
global _loader ; Make entry point visible to linker.
extern _main ; _main is defined elsewhere
Line 49 ⟶ 56:
; reserve initial kernel stack space -- that's 16k.
STACKSIZE equ 0x4000
 
; setting up entry point for linker
loader equ (_loader - 0xC0000000)
global loader
 
_loader:
Line 65 ⟶ 76:
 
; Start fetching instructions in kernel space.
; Since eip at this point holds the physical address of this command (approximately 0x00100000)
; we need to do a long jump to the correct virtual address of StartInHigherHalf which is
; approximately 0xC0100000.
lea ecx, [StartInHigherHalf]
jmp ecx ; NOTE: Must be absolute jump!
Line 92 ⟶ 106:
align 32
stack:
resb STACKSIZE ; reserve 16k stack on a quadworduint64_t boundary
</syntaxhighlight>
</pre>
 
==kernel.c==
This is not exactly your average int main(). Most notably, you do not have any library stuff available. As soon as you write so much as #include <, you have probably made the first mistake. Welcome to kernel land.
 
<pre>
void _main( void* mbd, unsigned int magic )
{
//write your kernel here
}
</pre>
 
==linker.ld==
This is a little trickier than it was for the [[Tutorial:CBare kernelbones|C kernel tutorial]], since you need to distinguish between virtual addresses (which will be in the higher half) and load addresses, which GRUB needs to decide where to put your kernel.
 
<syntaxhighlight lang="c">
<pre>
ENTRY(_loaderloader)
OUTPUT_FORMAT(elf32-i386)
 
Line 134 ⟶ 138:
}
}
</syntaxhighlight>
</pre>
 
Note that we use loader (and not _loader) as our entry point. This is due to the fact that _loader's address is approximately 0xC0100000, if we try to set our eip to that address it will not find our loader function.
==Troubleshooting==
Also note our entry point is not being converted to physical address. GRUB does this conversion when calculating starting value of EIP, and if you attempt to do the translation, you may get your execution when you don't want it or get "entry point isn't in a segment" error.
;Grub <tt><nowiki>Error 7: Loading below 1MB is not supported</nowiki></tt>
:Many older versions of GRUB ignore the 'physical address hint' of the [[ELF]] sections. Try to make sure you are using at least GRUB v 0.94.
 
==kernel.c==
;It doesn't work with BOCHS
 
:Some prebuilt versions of Bochs do not support 4MB pages. You may need to build your own with the following options:
Using the [[Bare bones#Writing_a_kernel_in_C|kernel.c code]] from the original bare bones tutorial will work fine, with one small change. On the fourth line in terminal_initialize(), change:
<pre>
 
--enable-4meg-pages support 4Megabyte pages extensions
<syntaxhighlight lang="c">
--enable-pae support Physical Address Extensions
terminal_buffer = (uint16_t*) 0xB8000;
</pre>
</syntaxhighlight>
 
to
 
<syntaxhighlight lang="c">
terminal_buffer = (uint16_t*) 0xC00B8000;
</syntaxhighlight>
 
This accomodates for the kernel's new offset into higher-half space. Any direct memory access by the kernel at this point should take place with respect to this offset where necessary.
 
==Troubleshooting==
;I got a page fault (#PF) when accessing my GRUB Multiboot info structure
The address passed by loader.s is physical, you have to make it virtual to add your virtual base to it. For example, in your loader.s:
<syntaxhighlight lang="asm">
add ebx, KERNEL_VIRTUAL_BASE ; make the address virtual
push ebx ; push it on the stack for _main()
</syntaxhighlight>
Don't forget to make all addresses pointing to memory locations in the Multiboot info structure also virtual.
 
==See Also==
===Articles===
*[[Tutorial:Bare bones|Bare bones]]
*An [[User:Glauxosdever/Higher_Half_x86_Bare_Bones|alternate]] higher half Bare Bones.
 
[[Category:Bare bones tutorials|Higher Half bare bones]]