Higher Half Kernel

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Higher Half Kernel

Post by Jeko »

http://www.osdev.org/wiki/Higher_Half_bare_bones

I want to do an higher half kernel like this.

But I don't want to use 4MB pages in my kernel, I want only 4kb pages. (because 4MB pages aren't supported by older computers)

How can I do?
I must modify this:

Code: Select all

global _loader                          ; Make entry point visible to linker.
extern _main                            ; _main is defined elsewhere

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0             ; align loaded modules on page boundaries
MEMINFO     equ  1<<1             ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002     ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)  ; checksum required

; This is the virtual base address of kernel space. It must be used to convert virtual
; addresses into physical addresses until paging is enabled. Note that this is not
; the virtual address where the kernel image itself is loaded -- just the amount that must
; be subtracted from a virtual address to get a physical address.
KERNEL_VIRTUAL_BASE equ 0xC0000000                  ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)  ; Page directory index of kernel's 4MB PTE.


section .data
align 0x1000
BootPageDirectory:
    ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
    ; All bits are clear except the following:
    ; bit 7: PS The kernel page is 4MB.
    ; bit 1: RW The kernel page is read/write.
    ; bit 0: P  The kernel page is present.
    ; This entry must be here -- otherwise the kernel will crash immediately after paging is
    ; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
    dd 0x00000083
    times (KERNEL_PAGE_NUMBER - 1) dd 0                 ; Pages before kernel space.
    ; This page directory entry defines a 4MB page containing the kernel.
    dd 0x00000083
    times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0  ; Pages after the kernel image.


section .text
align 4
MultiBootHeader:
    dd MAGIC
    dd FLAGS
    dd CHECKSUM

; reserve initial kernel stack space -- that's 16k.
STACKSIZE equ 0x4000

_loader:
    ; NOTE: Until paging is set up, the code must be position-independent and use physical
    ; addresses, not virtual ones!
    mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE)
    mov cr3, ecx                                        ; Load Page Directory Base Register.

    mov ecx, cr4
    or ecx, 0x00000010                          ; Set PSE bit in CR4 to enable 4MB pages.
    mov cr4, ecx

    mov ecx, cr0
    or ecx, 0x80000000                          ; Set PG bit in CR0 to enable paging.
    mov cr0, ecx

    ; Start fetching instructions in kernel space.
    lea ecx, [StartInHigherHalf]
    jmp ecx                                                     ; NOTE: Must be absolute jump!

StartInHigherHalf:
    ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
    ; anymore.
    mov dword [BootPageDirectory], 0
    invlpg [0]

    ; NOTE: From now on, paging should be enabled. The first 4MB of physical address space is
    ; mapped starting at KERNEL_VIRTUAL_BASE. Everything is linked to this address, so no more
    ; position-independent code or funny business with virtual-to-physical address translation
    ; should be necessary. We now have a higher-half kernel.
    mov esp, stack+STACKSIZE           ; set up the stack
    push eax                           ; pass Multiboot magic number

    ; pass Multiboot info structure -- WARNING: This is a physical address and may not be
    ; in the first 4MB!
    push ebx

    call  _main                  ; call kernel proper
    hlt                          ; halt machine should kernel return


section .bss
align 32
stack:
    resb STACKSIZE      ; reserve 16k stack on a quadword boundary
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Post by Laksen »

Just keep it like it is there. When you enter the kernel you build a new page directory and just set it and disable the PSE bit
mgarcia
Posts: 2
Joined: Sun Jan 27, 2008 3:01 pm

Post by mgarcia »

Hi, here is my code to use 4KB pages, it's based on the Higher Half tutorial.

Every virtual address has the form DIRECTORY | PAGE | OFFSET, so:

I create one page table that maps virtual address *|PAGE|* to physical address 0|PAGE|*
Then in my page directory I map every address like 0|*|* and 0xC0 << 2|*|* to point to the previous page table.

Code: Select all

[GLOBAL mboot]                  ; Make 'mboot' accessible from C.
[GLOBAL kaddr_start]
[GLOBAL kaddr_end]
[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

MBOOT_PAGE_ALIGN    equ 1<<0    ; Load kernel and modules on a page boundary
MBOOT_MEM_INFO      equ 1<<1    ; Provide your kernel with memory info
MBOOT_CMD_LINE      equ 1<<2    ; Provide your kernel with CMD line
MBOOT_HEADER_MAGIC  equ 0x1BADB002 ; Multiboot Magic value
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO | MBOOT_CMD_LINE
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

KERNEL_VIRTUAL_BASE equ 0xC0000000                  ; 3GB
KERNEL_DIR_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)

section .data

; Page table to map the first 4MB of physical memory
align 0x4096
boot_page_table:
%assign i 0 
%rep    1024
dd 0x00000003 + (i * 4096)
%assign i i+1 
%endrep

; Kernel page directory
align 0x1000
boot_page_directory:
    dd 0x00000003 + boot_page_table - KERNEL_VIRTUAL_BASE
    times (KERNEL_DIR_NUMBER - 1) dd 0                 ; Pages before kernel space.
    ; This page directory entry defines a 4MB page containing the kernel.
    dd 0x00000003 + boot_page_table - KERNEL_VIRTUAL_BASE
    times (1024 - KERNEL_DIR_NUMBER - 1) dd 0  ; Pages after the kernel image.

section .text
[BITS 32]                       ; All instructions should be 32-bit.


[GLOBAL _loader]                 ; Kernel entry point.
[EXTERN start]                 ; This is the entry point of our C code

mboot:
	dd  MBOOT_HEADER_MAGIC      ; GRUB will search for this value on each
                               ; 4-byte boundary in your kernel file
	dd  MBOOT_HEADER_FLAGS      ; How GRUB should load your file / settings
	dd  MBOOT_CHECKSUM          ; To ensure that the above values are correct
	dd  mboot                   ; Location of this descriptor
kaddr_start:	dd  code        ; Start of kernel '.text' (code) section.
	dd  bss                     ; End of kernel '.data' section.
kaddr_end:	dd  end            ; End of kernel.
	dd  _loader                 ; Kernel entry point (initial EIP).

_loader:

	; Initialize VM
	; TODO: set CR4 state
   mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE)
	mov cr3, ecx                                ; Load Page Directory Base Register.
	mov ecx, cr0
	or ecx, 0x80000000                          ; enable paging.
	mov cr0, ecx

   ; Start fetching instructions in kernel space.
   lea ecx, [StartInHigherHalf]
   jmp ecx

StartInHigherHalf:
	; Load multiboot information:
	mov esp, kernel_stack       ; Setup kernel stack
	push    ebx
	push boot_page_directory
	; Execute the C init:
	cli                   		 ; Disable interrupts.
	call start 
	jmp $                       ; Avoid executing unknown things if start return


section .bss
   resb 8192                    ; Kernel stack
kernel_stack:

User avatar
AndrewAPrice
Member
Member
Posts: 2309
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

I used an alternative version which mapped the entire 3GB+ region to 0-1GB so I had room to work in when I enter my kernel.
My OS is Perception.
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Post by thepowersgang »

Wouldn't mapping the lower 1Gb to the highest 1Gb cause lots of problems (e.g. mapping non-existant memory)

I've tried this code from the tutorial out and it seems to be crashing at the line

Code: Select all

lea ecx, [StartInHigherHalf]
I'm wondering, what is the point of using the `lea` to eax and then jumping from the value in eax?


Bochs CPU Dump:

Code: Select all

00119927614i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)
00119927614i[CPU0 ] protected mode
00119927614i[CPU0 ] CS.d_b = 32 bit
00119927614i[CPU0 ] SS.d_b = 32 bit
00119927614i[CPU0 ] EFER   = 0x00000000
00119927614i[CPU0 ] | RAX=000000002badb002  RBX=000000000002bdc0
00119927614i[CPU0 ] | RCX=0000000080000011  RDX=00000000000003f2
00119927614i[CPU0 ] | RSP=0000000000067ef0  RBP=0000000000067f00
00119927614i[CPU0 ] | RSI=000000000002bf4f  RDI=000000000002bf50
00119927614i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00119927614i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00119927614i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00119927614i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00119927614i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00119927614i[CPU0 ] | SEG selector     base    limit G D
00119927614i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00119927614i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00119927614i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00119927614i[CPU0 ] | RIP=0000000000107014 (0000000000107014)
00119927614i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000070
00119927614i[CPU0 ] | CR3=0x00106000 CR4=0x00000000
00119927614i[CPU0 ] >> (invalid)  : FFFF
00119927614e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

thepowersgang wrote:Wouldn't mapping the lower 1Gb to the highest 1Gb cause lots of problems (e.g. mapping non-existant memory)
He meant exactly the opposite: the address 3G is mapped to the start of memory.
I've tried this code from the tutorial out and it seems to be crashing at the line

Code: Select all

lea ecx, [StartInHigherHalf]
I'm wondering, what is the point of using the `lea` to eax and then jumping from the value in eax?
jumps are normally relative. it is assembled as the difference between the current instruction and the instruction where you end up. While in memory the difference is minimal, you change from the lower half to the upper half, adding 3GB to your address.
JMP register on the contrary performs an absolute jump: the address provided is where you'll end up. So if you provide an address in the higher half, you'll end up in the higher half, not in the same bit of memory in the lower half.
Bochs CPU Dump:

Code: Select all

00119927614i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)
00119927614i[CPU0 ] protected mode
00119927614i[CPU0 ] CS.d_b = 32 bit
00119927614i[CPU0 ] SS.d_b = 32 bit
00119927614i[CPU0 ] EFER   = 0x00000000
00119927614i[CPU0 ] | RAX=000000002badb002  RBX=000000000002bdc0
00119927614i[CPU0 ] | RCX=0000000080000011  RDX=00000000000003f2
00119927614i[CPU0 ] | RSP=0000000000067ef0  RBP=0000000000067f00
00119927614i[CPU0 ] | RSI=000000000002bf4f  RDI=000000000002bf50
00119927614i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00119927614i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00119927614i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00119927614i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00119927614i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00119927614i[CPU0 ] | SEG selector     base    limit G D
00119927614i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00119927614i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00119927614i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00119927614i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00119927614i[CPU0 ] | RIP=0000000000107014 (0000000000107014)
00119927614i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000070
00119927614i[CPU0 ] | CR3=0x00106000 CR4=0x00000000
00119927614i[CPU0 ] >> (invalid)  : FFFF
00119927614e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
This looks like you ran into bogus memory: when reloading CR3, or enabling paging, you must make sure that the code you are currently executing still appears in memory at the same place. Check that the memory is indeed mapped there, and that your pagetables point to some sensible location rather than somewhere into nothingness.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply