So today I was creating another bootloader, and thought that it would be nice if I would be able to use power of 64 bit processors. Everything seems to be running fine until my bochs start to restart due to Page Fault.
NOTE: parts of code is copied from osdev and some other osdev tutorials, because I wanted to first be able to have working code, then analyze it how it works, and then rewrite it by myself.
as wikipedia says:
Page Fault happens when a running program accesses a memory page that is mapped into the virtual address space, but not actually loaded into main memory.
Unfortunately I am not able to understand what is meant by that.
Here is the code:
org 0x7C00
bits 16
xor ax,ax
mov ds,ax
mov es,ax
mov bx,0x8000
cli
mov ss,bx
mov sp,ax
sti
cld
clc
;bootloader
;plan for bootloader
;change graphics to 0x0118
;enable A20
;goto 32 bit protected mode
;goto 64 bit long mode
;set 118h VESA graphics mode
mov ax,0x4f02
mov bx,118h
int 0x10
;load 64 bit code
mov ah,0x2
mov al,0x1
mov ch,0x0
mov cl,0x2
mov dh,0x0
mov bx,0x0000
mov es,bx
mov bx,0x7E00
int 0x13
;enable A20
call check_a20
jc code
mov ax,0x2401
int 0x15
call check_a20
jc code
in al,0x92
or al,0x2
out 0x92, al
call check_a20
jnc error
code: ;label for compiler
;at this point A20 should be enabled
;going into 32 bit mode
cli
pusha
lgdt [toc]
popa
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:code32
jmp error
bits 32
code32:
mov ax,0x010
mov ds,ax
mov ss,ax
mov es,ax
;detect is long mode supported
;to detect long mode support you need to detect CPUID support
;check extended functions
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb error32 ; It is less, there is no long mode.
;to go to long mode you need
;disable paging
;set PAE enable in CR4
;load CR3 with physical address of the PML4
;enable long mode by settings EFER.LME flag in MSR 0xC0000080
;enable paging
;setup paging
mov eax, cr0 ; Set the A-register to control register 0.
and eax, 01111111111111111111111111111111b ; Clear the PG-bit, which is bit 31.
mov cr0, eax ; Set control register 0 to the A-register.
;clear tables
mov edi, 0x1000 ; Set the destination index to 0x1000.
mov cr3, edi ; Set control register 3 to the destination index.
xor eax, eax ; Nullify the A-register.
mov ecx, 4096 ; Set the C-register to 4096.
rep stosd ; Clear the memory.
mov edi, cr3 ; Set the destination index to control register 3.
;setup tables
mov DWORD [edi], 0x2003 ; Set the uint32_t at the destination index to 0x2003.
add edi, 0x1000 ; Add 0x1000 to the destination index.
mov DWORD [edi], 0x3003 ; Set the uint32_t at the destination index to 0x3003.
add edi, 0x1000 ; Add 0x1000 to the destination index.
mov DWORD [edi], 0x4003 ; Set the uint32_t at the destination index to 0x4003.
add edi, 0x1000 ; Add 0x1000 to the destination index.
mov ebx, 0x00000003 ; Set the B-register to 0x00000003.
mov ecx, 512 ; Set the C-register to 512.
SetEntry:
mov DWORD [edi], ebx ; Set the uint32_t at the destination index to the B-register.
add ebx, 0x1000 ; Add 0x1000 to the B-register.
add edi, 8 ; Add eight to the destination index.
loop SetEntry ; Set the next entry.
;enable PAE
mov eax, cr4 ; Set the A-register to control register 4.
or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5).
mov cr4, eax ; Set control register 4 to the A-register.
;switch to Long Mode
mov ecx, 0xC0000080 ; Set the C-register to 0xC0000080, which is the EFER MSR.
rdmsr ; Read from the model-specific register.
or eax, 1 << 8 ; Set the LM-bit which is the 9th bit (bit 8).
wrmsr ; Write to the model-specific register.
;enable paging
mov eax, cr0 ; Set the A-register to control register 0.
or eax, 1 << 31 ; Set the PG-bit, which is the 32nd bit (bit 31).
mov cr0, eax ; Set control register 0 to the A-register.
;setup GDT again
lgdt [GDT64.Pointer]
jmp 0x08:0x7E00
error32:
cli
hlt
bits 16
error:
cli
hlt
check_a20:
cli
push ds
xor ax,ax
mov es,ax
not ax
mov ds,ax
mov di,0x0500
mov si,0x0510
;mov al, byte [es:di] ;read beyond limit
push ax
mov al, byte [ds:si]
push ax
mov byte [es:di], 0x00
mov byte [ds:si], 0xFF
cmp byte [es:di], 0xFF
pop ax
mov byte[ds:si],al
pop ax
mov byte [es:di],al
pop ds
sti
clc ;disabled carry flag = 0
je .exit
stc ;enabled carry flag = 1
.exit:
ret
;data
;Global Descriptor Table
gdt_data:
dd 0 ; null descriptor
dd 0
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT)
dd gdt_data ; base of GDT
GDT64: ; Global Descriptor Table (64-bit).
.Null: equ $ - GDT64 ; The null descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 0 ; Granularity.
db 0 ; Base (high).
.Code: equ $ - GDT64 ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011010b ; Access (exec/read).
db 00100000b ; Granularity.
db 0 ; Base (high).
.Data: equ $ - GDT64 ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access (read/write).
db 00000000b ; Granularity.
db 0 ; Base (high).
.Pointer: ; The GDT-pointer.
dw $ - GDT64 - 1 ; Limit.
dq GDT64 ; Base.
times 0x1FE - ($ - $$) db 0x00
db 0x55
db 0xAA
;already 64 bit data
bits 64
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;new colour 0x72, 0xDC, 0xEF
;0x0118 mode starts at 0xA0000
mov EAX, 0x72DCEF00
mov DI, 0xA0000
mov ECX, 0x100000
fill:
stosd
dec DI
loop fill
cli
hlt
times 0x400 - ($ - $$) db 0x00
Page Fault occurs when I try to fill my screen with colour rgb(114, 220, 239), which is here:
;new colour 0x72, 0xDC, 0xEF
;0x0118 mode starts at 0xA0000
mov EAX, 0x72DCEF00
mov DI, 0xA0000
mov ECX, 0x100000
fill:
stosd
dec DI
loop fill
I know this may sound dumb, but what can I do about this problem?
Also please note that I have never before worked with long mode
User contributions licensed under CC BY-SA 3.0