Loading 2nd stage of bootloader and starting it [duplicate]
Recently I'm trying to get a hang on how bootloaders work. I'm writing my loader in nasm assembler and test it with bochs and a floppy image.
The compiled binaries for stage 1 and 2 get joined via copy into one image. This image is exactly as I want it. 512Bytes stage1 code (magicnumber included and it loads just fine) and 512 stage2 code in the 2nd sector.
But I think my problem is loading the sector into the ram and jumping into it. Is there something wrong with my code?
Stage1.asm
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ;Set data segment to where we're loaded
mov ds, ax
mov si,s_version
call print_string
; ## Load stage2
mov si,s_loading
call print_string
xor ax,ax
xor bx,bx
开发者_如何学Python xor cx,cx
xor dx,dx
;read 2nd sector
mov ah,02h
mov al,1 ;read 1
mov ch,0 ;on track 0
mov cl,2 ;2nd sector
mov dh,0 ;head 1
mov dl,0 ;from floppy a
mov bx,09C0h;destination segment
mov es,bx
mov bx,0 ;destination offset
int 13h ;<-- Fails right here
mov si,s_sector
call print_string
;print number of read sectors
add ax, 48
mov ah, 0Eh
int 10h
mov al, 21
mov ah, 0Eh
int 10h
;print the sector's magicnumber (debugging purposes)
mov al, [09C0h+511]
int 10h
xor ax,ax
int 16h
mov si,s_jumping
call print_string
call word 09C0h:0000h
; #### print a string from si
print_string:
push ax
push bx
mov ah, 0Eh
.repeat:
lodsb
cmp al, 0
je .exit
int 10h
jmp .repeat
.exit:
pop bx
pop ax
ret
; ****
; #### define strings
s_version db 'VeOS 0.0.0.1',10,13,0
s_loading db 'Loading Stage2...',10,13,0
s_sector db 'Loading sector...',10,13,0
s_jumping db 'Passing control to Stage2.',10,13,0
; ****
;fillup with zeros
times 510-($-$$) db 0
;boot signature
dw 0xAA55
stage2.asm
BITS 16
start:
mov ax, 09C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 09C0h ;Set data segment to where we're loaded
mov ds, ax
mov ah, 0Eh
mov al, 21 ;"!"
int 10h
mov ah, 00h
int 16h
jmp $
times 511-($-$$) db 0
;Magicnumber for debugging
db 0x41
I googled thoroughly and found nothing describing exactly how to load a sector into the ram and jump into it. Not even the Magicnumber of the 2nd sector is found by my programm.
Would be great if it is just some miscalculation on the addresses.
Update: Current sourcecode, the line where it has a lockup is marked. I set all 4 main registers to 0 out of pure paranoia.
Update2: Again the current version. No stuff done between setting up the registers and issuing int 13h.
Update: In addition to the below, you're also overwriting your stack when you load!
Your stack is located at 07C0h + 288 : 4096
which is 08E0h:1000h = 09E0h:0000h
, and you're reading to 09C0h:0000
, and 512 bytes forward (ending at 09E0h:0000h
) overwriting the stack. Either move your stack or read to some other place. See the memory map from osdev.org for inspiration.
I'm afraid I don't know a good step-by-step debugger. I just placed a jmp $-2
instruction in the code and used QEMUs built-in debugger to do "info registers" at appropriate points. I think Bochs might have something similar.
Three (2.5) things I see (though there might be more):
;read 2nd sector
mov ah,02h
mov al,1 ;read 1
mov ch,0 ;on track 0
mov cl,1 ;2nd sector
mov dl,0 ;from floppy a
mov bx,09C0h ;destination
mov es,bx
int 13h
- You're leaving
bx
as09c0h
, so it will read to09C0h:09C0h
rather than09C0h:0000h
. - You say you're reading from the second sector (
cl = 1
), but you're reading from the first!. See Ralph Brown. - You're not setting
dh
(head). It's probably fine in Bochs, but I can't recall off the top of my head what initial conditions are guaranteed apart fromdl
being set to the drive number.
Here's the boot loader I've used for a small test kernel (parts taken from various parts of osdev.org and might have errors I've introduced, so be careful), if you wish to compare/copy. (I leave dl
intact because it contains the boot drive so you don't have to hard code it).
bits 16
org 0x7c00
Start: jmp EntryPoint
PrintString16:
pusha
.PrintLoop:
lodsb
or al, al
jz .PrintDone
mov ah, 0xe
int 0x10
jmp .PrintLoop
.PrintDone:
popa
ret
EntryPoint:
xor ax, ax
mov ss, ax
mov ds, ax
mov sp, 0x7c00
.DiskReset:
mov ah, 0
int 0x13
jc .DiskReset
mov ax, 0x50 ; load to 0x500 linear address. It has unused space up to 0x7bff
mov es, ax
xor bx, bx
mov ax, 0x023B ; count = 0x3b = 59, the maximum (while still leaving soom room for the stack and the boot sector code we're currently running)
mov cx, 0x0002
xor dh, dh ; leave dl intact
int 0x13
jnc .ReadDone
mov si, ReadError
call PrintString16
jmp .DiskReset
.ReadDone:
;jmp 0x50:0x0 ;jump to stage 2 loaded at 0x500
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ax, 0x9000
mov ss, ax
mov sp, 0xffff
sti
mov si, HelloMsg
call PrintString16
; Disable interrupts until safely in protected mode
cli
; Install GDT
lgdt [toc]
; Enable A20
mov al, 0xdd
out 0x64, al
mov si, GoPMode
call PrintString16
; enable protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:PmodeStart
bits 32
PmodeStart:
; setup stack and datasegments
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Setup stack at 0x90000
mov esp, 0x90000
; Jump to C-code
jmp 0x8:0x500
; Reboot if C-code returns
Reboot:
mov word [0x472], 0x1234
jmp 0x8:0xffff0
ReadError db 'Read error - retrying...', 13, 10, 0
HelloMsg db 'Loading...',0
GoPMode db 'Entering protected mode..',0
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)10:56 AM 7/8/2007
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
times 510 - ($-$$) db 0 ; pad to 512 bytees, will also warn if we exceed 512 bytes
dw 0xAA55 ; boot signature
精彩评论