Basically, I have a custom bootloader for legacy systems that uses the BIOS extended read INT 13h. It sets the kernel to load at address 0x1000, and while it is entirely functional on the emulators, I'm having some real pains not being able to find out why it does not work on bare metal. Perhaps one of the wiser members of this place can guide me, and ultimately anyone else who has this problem as well, toward the correct solution.
For reference: the machine I am trying to boot on is an HP t5000 slim model, with a Phoenix AwardBIOS and a VIA Esther C7 (400MHz) processor. It has 64MB of onboard flash memory, and 128MB of RAM. When I got it as a gift, I just knew it'd be the perfect legacy model to test with real hardware. I have considered that perhaps this PC is the problem and not the code, I do not know. I am booting from a flash drive. All of my code has worked up until the kernel call. Nothing in my code reaches even close to addresses towards the end of the small on-board RAM.
I know this is asking a lot, but the boot code actually will triple-fault once before even getting to the kernel call, then on restart it will reach the kernel call. Then once it finally reaches the kernel call, it never makes the jump. What gives??
Code: Select all
[BITS 16]
_bootLoadKernel:
push si
mov ah, 0x42
mov dl, [bDrive]
mov si, DiskAddrPkt
int 0x13 ; Read the disk into memory
jc .errorRead
pop si
ret
.errorRead:
mov si, szDiskReadError
call _Bootloopstr
jmp $
......
ALIGN 16
DiskAddrPkt:
db 0x10 ; Packet size (16 bytes)
db 0 ; Reserved (0)
dw 0x0010 ; Blocks to transfer (16x512 = 8192 = sizeof kernel)
dw KERNEL_OFFSET ; OFFSET (KERNEL_OFFSET = 0x1000)
dw 0x0000 ; SEGMENT
dd 0x00000001 ; start at sector 1
dd 0x00000000
Code: Select all
_globalBootStart:
mov [bDrive], dl ; Capture the drive number before anything else.
; Clear the segments.
xor ax, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ax, 0x7C00
mov sp, ax
call _bootLoadKernel ; This is the function from the code above. It does work on all machines, no read errors.
jmp near A20_setup
A20_setup:
; Key-press initialization is required on the bare metal machine I am using.
; -- Skipping this for the sake of brevity.
.........
_globalBootProtMode:
cli
xor ax, ax ; Video mode
mov al, 03h
int 0x10
lgdt [gdt_descriptor]
mov eax, cr0 ; Protected Mode.
or eax, 0x1
mov cr0, eax
jmp CODE_SELECTOR:_bootInitializeSegments
[BITS 32]
_bootInitializeSegments:
mov eax, DATA_SELECTOR ; flushing segments
mov ds, ax ; this completes gdt_init process
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x90000
mov esp, ebp
; --- Paging ---
pushad
mov edi, 70000h
push edi
mov ecx, 800h
xor eax, eax
rep stosd
pop edi
lea eax, [edi + 0x1000]
or eax, 011b
mov [edi], eax
lea eax, [edi + 0x2000]
or eax, 011b
mov [edi + 0x1000], eax
push edi
mov dword edx, [pageBasePtr]
add edx, 011b ; Flags: PAGE_RW|PAGE_PR
lea edi, [edi + 0x2000]
mov eax, edx
._bootLoopBuildPageTable:
mov [edi], eax
add eax, 0x1000
add edi, 8
cmp eax, 0x200000
jb ._bootLoopBuildPageTable
; Set flags in control registers.
pop edi
mov edx, edi
mov cr3, edx
mov eax, cr4 ; Get CR4 register values.
or eax, 10100000b ; Enable bits 5&7, PAE&PGE
mov cr4, eax
mov eax, cr0
or eax, 0x80000001
mov cr0, eax
popad
jmp near _bootInitKernel
_bootInitKernel:
call KERNEL_OFFSET ; <----- This does NOT work on bare metal. CPU triple-faults. JMP does not work either.
jmp $ ; hang if the kernel returns for any reason (should not happen)