The problem is when I try to do a long jump from the 16-bit boot code to 0x08:0x7e00 which is where the 32-bit code is it just triple faults, I can load the data segment selectors without failing, the GDT appears to have been loaded with the proper address and the addressing everywhere seems fine to me. I guessed that my GDT entry was wrong but it seems all right with what I've checked it against. So far I've narrowed down the crash to being caused by loading CS with a far jump after the Protected mode bit has been set in CR0* but for the life of me haven't been able to work out why even with disassembling the compiled code and checking the code of other projects. I am testing it on VMWare Workstation 7.0.0. I think that's just about all I can say about it and so here is my source code:
boot.asm:
Code: Select all
; This code should produce 16-bit x86 code that will be loaded into
; memory at 0x7c00 by the BIOS as it has the boot sector marker
; (0xaa55) at the end. The code is limited to 512B in size and it's
; purpose is to load the rest of the OS into memory from a floppy
; drive, load up a flat GDT and then jump past the end of the code
; where 32-bit code will be for the rest of the OS (32-bit mode is
; activated by the far jump).
%include "include/macros.mac"
[BITS 16]
[ORG 0x7c00]
; clear all segment registers so addressing is correct for all code under
; 64KiB
xor ax,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
jmp word 0:Boot
Boot:
; load the next 65 sectors (32.5KiB), should load 1439.5KiB (rest of disk)
; wang disks consist of sectors of 512B, 18 per tracks, 80 tracks per side
; and two sides leading to 1440KiB, 1.44MB my @$$, the liars >:( CF will
; be set if operation FAILED
mov ax,0x0241
mov bx,0x7e00
mov cx,0x0001
mov dh,0
int 0x13
jc Terminal
;; enable A20 address line using BIOS, CF will be set if failed
mov ax,0x2401
int 0x15
jc Terminal
; disable interrupts as there is no IVT/IDT otherwise when entering 32-bit
; mode the world with abruptly turn to faecal matter
cli
; Load GDT into GDTIR and enable protected mode bit of CR0
lgdt [GDT]
mov eax,cr0
or eax,byte 1
mov cr0,eax
mov ax,DATA
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov ebp,32 MiB
mov esp,ebp
; Lunge forth into protected mode at 0x7e00 (just after boot block), sets
; CS to 0x08 where the CODE GDT entry is.
jmp word CODE:END
; Resort to this in the event of an error which we CBA to account for
; this will triple fault as soon as protected mode is activated as it uses
; segment registers (es)
Terminal:
mov ax,0xb800
mov es,ax
mov si,fatal_message;.msg
xor bx,bx
mov cx,fatal_message._len
.put:
mov ax,word[si]
mov word[es:bx],ax
add si,2
add bx,2
dec cx
jnz .put
cli
hlt
fatal_message:
VGASTRING 0x09,"A case that has "
VGASTRING 0x04,"NOT "
VGASTRING 0x09,"been accounted for has occured, Goodbye!"
FINALIZE fatal_message,VGA
;==============================================================================
;===Global Descriptor Table ===================================================
;==============================================================================
align(4)
; use the first entry in the GDT to store the GDT information to be used with
; lgdt as it's never used, right?
GDT:
dw GDT.end - GDT - 1
dd GDT
dw 0
; entry 1, addr 0x08
CODE EQU .flat_code - GDT
.flat_code db 0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00
; entry 1, addr 0x10
DATA EQU .flat_data - GDT
.flat_data db 0xff,0xff,0x00,0x00,0x00,0x92,0xcf,0x00
.end:
;==============================================================================
times 510-($-$$) db 0 ; if this fails the code is too long
db 0x55
db 0xaa
; end of code, will be at 0x7e00
END:
Code: Select all
%ifndef MACROS_MAC
%define MACROS_MAC 1
; align data/code to boundry
%define align(n) times ((n - (($-$$) % n)) % n) nop
; size macros
%define KiB * (1<<10)
%define MiB * (1<<20)
; define an external C label
%macro EXTERNALC 1
extern _%1
%1 EQU _%1
%endmacro
; export an internal label for C
%macro EXPORTC 1
%define %1 _%1
global _%1
%1:
%endmacro
; define a VGA string with %1 as character attributes, the string is defined by %2 and it's length is in label.len
%macro VGASTRING 2
%assign a %1
%assign i 1
%strlen len %2
%rep len
%substr c %2 i
%assign i i+1
dw (c + (a << 8))
%endrep
%endmacro
%assign VGA 2
;gets the number of bytes from %1 to $ and sets %1._len to that value
%macro FINALIZE 1-2 1
%1._len EQU (($ - %1) / %2)
%endmacro
%endif
*as a side note the article on the tutorials at osdever.net (recommended on the IRC channel) says that enabling protected mode is done by CR3 = CR0 | 1 which I think is wrong, wouldn't that only be if you were using pages or something along those lines?