Bootloader Page Fault

0

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

assembly
nasm
bare-metal
page-fault
asked on Stack Overflow Aug 19, 2016 by vakus

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0