Reputation: 31
I am following Nick Blundell's tutorials for boot sector programming (https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf and https://www.youtube.com/watch?v=YvZhgRO7hL4). My code works just fine in my qemu emulator, however when I run it on a physical machine it will crash whenever I begin to reference the segment registers. My teachers at school are not familiar with low level programming and cannot help me. Here is my bootloader, here I have annotated the lines that cause it to crash with the string CRASH (note: when I say crash, it actually just goes on to load my OS from the next disk. I am loading this code from an external HDD) :
[bits 16]
[org 0x7c00]
mov bp, 0xffff
mov sp, bp
mov ax, 0x0000
mov ds, ax
;; mov es, ax ;; CRASH
;; mov ss, ax ;; CRASH
mov si, BOOT_MSG
call print_string
call print_newline
mov si, INIT_SEG_MSG
call print_string
call print_newline
;; mov dx, ds ;; CRASH
;; call print_hex
;; call print_newline
;;mov dx, cs ;; CRASH
;;call print_hex
;;call print_newline
;;mov dx, es ;; CRASH
;;call print_hex
;;call print_newline
;;mov dx, ss ;; CRASH
;;call print_hex
;;call print_newline
;; mov dl, 0x80 ;; disk where kernel is
;; mov cl, 3 ;; start sect
;; mov al, 1 ;; num sect
;; mov bx, 0x7ef0 ;; RAM addr
;; call load_kernel
;; mov si, KERN_MSG
;; call print_string
;; call print_newline
;; call switch_to_pm
jmp $
%include "print.asm"
%include "print_hex.asm"
%include "disk.asm"
%include "pm.asm"
[bits 32]
pm :
mov esi, PM_MSG
call print_string_pm
jmp 0x7ef0
jmp $
[bits 16]
BOOT_MSG : db 'booted 16-bit to 0x7c00',0
KERN_MSG : db 'loaded kernel to es 0x7ef0',0
PM_MSG : db 'switched to 32-bit mode',0
INIT_SEG_MSG : db 'init segment registers',0
times 510-($-$$) db 0
dw 0xaa55 `
I am sure I have a fundamental misunderstanding, any help will be appreciated. Here are my printing routines:
print_string :
push ax
_loop :
lodsb
cmp al, 0
je _end
mov ah, 0x0e
int 0x10
jmp _loop
_end :
pop ax
ret
print_hex :
mov si, HEX_TEMPLATE
mov bx, dx
shr bx, 12
mov bx, [bx+HEXABET]
mov [HEX_TEMPLATE+2], bl
mov bx, dx ;; bx -> 0x1234
shr bx, 8 ;; bx -> 0x0012
and bx, 0x000f ;; bx -> 0x0002
mov bx, [bx+HEXABET]
mov [HEX_TEMPLATE+3], bl
mov bx, dx
shr bx, 4
and bx, 0x00f
mov bx, [bx+HEXABET]
mov [HEX_TEMPLATE+4], bl
mov bx, dx
and bx, 0x0f
mov bx, [bx+HEXABET]
mov [HEX_TEMPLATE+5], bl
call print_string
ret
HEX_TEMPLATE : db '0x???? ',0
HEXABET : db '0123456789abcdef'
print_newline :
pusha
mov ah, 0x0e
mov al, 0x0d
int 0x10
mov al, 0x0a
int 0x10
popa
ret
Upvotes: 1
Views: 607
Reputation: 31
So after many hard resets, I have found the solution. The problem was that what I thought was the problem, WASN'T THE PROBLEM. So I decided to take my flash drive and boot from my dad's pc. It worked perfectly. So I continued to write my bootloader on my own pc. I wrote the code to enter PM mode, ran it, perfect, no problems. Then I made another change. Copied the bytes to the flash drive using dd, and ran it on my dad's pc. But wait. The change didn't show up... So I ran dd a few more times, zeroed the drive, and still, nothing. So I REBOOTED MY COMPUTER, RAN DD AGAIN, AND IT WORKED. The problem seemed to be the way that my OS (Ubuntu 16, not sure if it is relevant) issued the dd command. It seems the /dev/sdb is a sort of buffer that doesn't actually get written to the disk, at least after I remove the flash drive the first time. Maybe it is a bug in the OS. Maybe it is a bug in dd. Maybe I'm missing something. Who knows. The problem (as stated in the comments) is that I was unaware of how Linux block devices work. See: sync. Apparently the changes I made were CACHED and not written. Either way I will be using an emulator from now on. Thanks everyone!
Upvotes: 2
Reputation: 1243
BIOS's have a peculiarity about them in that the state of CS is unknown. In Bochs and probably Qemu CS = 0, therefore code with an origin of 0x7C00 will work. Real hardware may possibly pass CS = 0x7C0, so without an appropriate far jump at the beginning of code calls to near absolute functions would be skewed by 0x7C00 bytes with the origin set to 0x7C00.
Solutions:
org 0x7C00
jmp 0:Begin ; Far jump so CS = 0
Begin:
mov ax, cs
mov ds, ax
mov es, ax
or
org 0
jmp 0x7C0:0 ; Far jump so CS = 0x7C0
This is probably what's happening and the crash is coming @ call print_string which is actually looking for code @ 0xF8??.
Upvotes: 2