I have done it with FASM without any problems. But now I don't do it like that anymore, I prefer the 3 modes being split up. But is't possible:
Code: Select all
org 7C00h
USE16
start:
jmp short boot_code
nop
bBootDrive db 'X'
boot_code:
cli
push cs
pop ds
; BIOS puts boot drive code in dl
mov [bBootDrive], dl
; Set ss to 9000h
mov ax, 09000h
mov ss, ax
mov sp, start
mov es, ax
mov si, sp
mov di, sp
; Copy 256 words (512 bytes)
mov cx, 0100h
cld
rep movsw
; ds:si->int 1Eh "handler"
lds si, [1Eh * 4]
; es:di->boot_code + 4
mov di, boot_code + 4
; Save the address of the old int 1Eh "handler"
mov [cs:di - 4], si
mov [cs:di - 2], ds
; Store the offset and segment of new int 1Eh "handler"
mov [cs:1Eh * 4], di
mov [cs:1Eh * 4 + 2], ax
; Copy 11 bytes
mov cx, 11
rep movsb
mov ax, 0900h
mov ds, ax
; set head settle time to 15ms
mov byte [di-2], 15
; al = sectors per track (last sector)
;mov al, byte [wSecsPerTrack]
; Set last sector on track
;mov byte [di-7], al
; Set last sector on track <-- hmm, ok?
mov byte [di-7], 36
; Jump to the new code
jmp far 9000h:jump_here
jump_here:
mov ax, 0160h
mov es, ax
; Read 1 sector starting on head 0, track 0, sector 1
mov ax, 020Eh
mov cx, 0002h
mov dh, 0
mov dl, [bBootDrive]
; Read into es:bx = 0160h:0000h
xor bx, bx
int 13h
; TODO: check cf, ah, al
jnc read_ok
mov bx, 0b800h
mov es, bx
xor di, di
mov bx, 01f45h
mov [es:di], bx
mov [es:di + 2], ax
hlt
read_ok:
; Enable A20
in al, 0x92
or al, 2
out 0x92, al
jmp far 0000h:1600h
rb 7C00h + 512 - 2 - $ ; fill boot sector with emptyness except for signature
db 055h, 0aah ; boot signature
org 1600h
kernel_start:
lgdt [cs:GDTR]
; Switch to protected mode
mov eax, cr0
or al, 1
mov cr0, eax
jmp CODE_SELECTOR:protectedmode_start
NULL_SELECTOR = 0
DATA_SELECTOR = 1 shl 3 ; flat data selector (ring 0)
CODE_SELECTOR = 2 shl 3 ; 32-bit code selector (ring 0)
LONG_SELECTOR = 3 shl 3 ; 64-bit code selector (ring 0)
GDTR: ; Global Descriptors Table Register
dw 4*8-1 ; limit of GDT (size minus one)
dq GDT ; linear address of GDT
GDT rw 4 ; null desciptor
dw 0FFFFh,0,9200h,08Fh ; flat data desciptor
dw 0FFFFh,0,9A00h,0CFh ; 32-bit code desciptor
dw 0FFFFh,0,9A00h,0AFh ; 64-bit code desciptor
USE32
protectedmode_start:
; Load 4 GB data descriptor to all data segment registers
mov eax, DATA_SELECTOR
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov edi, [0x80000 + 40]
mov eax, 0xFFFF0000
mov ecx, 65536 / 4
rep stosd
; Enable physical-address extensions
mov eax, cr4
or eax, 1 shl 5
mov cr4, eax
; Clear the page tables
mov edi, 70000h
mov ecx, 4000h shr 2
xor eax, eax
rep stosd
; Address of first PDE table, 4GB of pages to map
mov edi, 72000h
mov eax, 0 + 10000111b
mov ecx, 2048
make_page_entries:
stosd
add edi, 4
add eax, 200000h
loop make_page_entries
mov dword [70000h], 71000h + 111b ; PML4 index 0 = PDPE at 71000h
mov dword [71000h + 0], 72000h + 111b ; PDPE index 0 = PDE at 72000h
mov dword [71000h + 8], 73000h + 111b ; PDPE index 1 = PDE at 73000h
mov dword [71000h + 16], 74000h + 111b ; PDPE index 2 = PDE at 74000h
mov dword [71000h + 24], 75000h + 111b ; PDPE index 3 = PDE at 75000h
mov dword [71000h + 32], 76000h + 111b ; PDPE index 4 = PDE at 76000h
mov dword [71000h + 40], 77000h + 111b ; PDPE index 5 = PDE at 77000h
mov dword [71000h + 48], 78000h + 111b ; PDPE index 6 = PDE at 78000h
mov dword [71000h + 56], 79000h + 111b ; PDPE index 7 = PDE at 79000h
; Load page-map level-4 base
mov eax, 70000h
mov cr3, eax
; EFER MSR
mov ecx, 0C0000080h
rdmsr
; Enable long mode
or eax, 1 shl 8
wrmsr
; Enable paging
mov eax, cr0
or eax, 1 shl 31
mov cr0, eax
jmp LONG_SELECTOR:longmode_start
USE64
longmode_start:
mov al, 10001b ; begin PIC 1 initialization
out 20h, al
mov al, 10001b ; begin PIC 2 initialization
out 0A0h, al
mov al, 80h ; IRQ 0-7: interrupts 80h-87h
out 21h, al
mov al, 88h ; IRQ 8-15: interrupts 88h-8Fh
out 0A1h, al
mov al, 100b ; slave connected to IRQ2
out 21h, al
mov al, 2
out 0A1h, al
mov al, 1 ; Intel environment, manual EOI
out 21h, al
out 0A1h, al
in al, 21h
mov al, 0;11111100b ; enable only clock and keyboard IRQ
out 21h, al
in al, 0A1h
mov al, 0;11101111b ; enable only ps2-mouse IRQ
out 0A1h, al
xor edi, edi ; create IDT (at linear address 0)
mov ecx, 21
make_exception_gates: ; make gates for exception handlers
mov esi, exception_gate
movsq
movsq
loop make_exception_gates
mov ecx, 256 - 21
make_interrupt_gates: ; make gates for the other interrupts
mov esi, interrupt_gate
movsq
movsq
loop make_interrupt_gates
mov word [80h*16], clock ; set IRQ 0 handler
mov word [81h*16], keyboard ; set IRQ 1 handler
mov word [82h*16], irq2
mov word [83h*16], irq3
mov word [84h*16], irq4
mov word [85h*16], irq5
mov word [86h*16], irq6
mov word [87h*16], irq7
mov word [88h*16], irq8
mov word [89h*16], irq9
mov word [8Ah*16], irqA
mov word [8Bh*16], irqB
mov word [8Ch*16], mouse ; set IRQ 12 handler
mov word [8Dh*16], irqD
mov word [8Eh*16], irqE
mov word [8Fh*16], irqF
lidt [IDTR]
...
This code is quick&dirty and I have omitted some of it because it's not necessary to show that it's possible.
That's FASM of course.