I am writing a simple OS in real mode ASM for the fun of it. I have recently decided to move on to the filesystem. I assembled the code with
nasm -f bin -o boot.o boot.asm
nasm -f bin -o kernel.o kernel.asm
nasm -f bin -o fs.o fs.asm
dd if=boot.o bs=512 of=os.img
dd if=kernel.o bs=512 of=os.img seek=1
dd if=fs.o bs=512 of=os.img seek=2
In my bootloader I load the filesystem at the address 0x1000:0000, and my kernel at 0x2000:0000. Each are 512 bytes (so far) are fairly small. So, to test out my new filesystem, I wrote my kernel to print out the first letter of the name of the first file in the table. It puts the value 0x2000 into si, moves the byte at the address in si into al. It then passes 0x0e into ah and calls int 0x10. It then halts. However, when I boot the os into qemu, it simply shows me the bios information, says booting from floppy, then does nothing. No letter. Nothing. Here is the relevent code:
relevent bootloader code
;;the part that loads the file system.
;;The part for the kernel is identical, except that cl is 02 and bx is 0x2000
mov ah, 02
mov al, 01
mov ch, 00
mov cl, 03
mov dh, 00
mov dl, 00
mov bx, 0x1000
mov es, bx
xor bx, bx
int 0x13
;;jumps to address 0x2000 (where the kernel is)
mov ax, 0x2000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
xor ax, ax
jmp 0x2000
;;halts
hlt
relevent kernel code
;;gets address
mov si, 0x1000
;;loads al
mov al, [si]
;;prints
mov ah, 0x0e
int 0x10
;;halts
hlt
relevent filesystem code
;;declares first file (it is hard coded for testing purposes)
;;format: [name], [sector number], [number of sectors to load]
db 'file.bin', 4, 1
If I have done something wring in posting this, please forgive me, as this is my first post.
There are several problems in your code.
0x1000:0000
. Translated to linear address (which is the most important form) it is0x10000
, or simply 64KiB.You're loading your kernel on address
0x2000:0000
(0x20000
, 128KiB). The jump you're doingis IP-relative jump, so you don't get to position you want. Execution of this jump is performed by adding immediate value passed as instruction parameter to value of IP register, which holds (in that time) address of next instruction (your
hlt
). What you need to do is far jump. It jumps to absolute address. Form of far jump is following:Replace the jump you have with this one:
Kernel code that should print character is using
SI
register uses segment-relative addressing, as you're executing your code in real mode. In difference to IP-relative jumps, you can't pass signed value as offset (although it would be cool and sometimes useful). Change value ofDS
segment, or use segment override to make everything faster. In your case, I would recommend usingfs
segment for all filesystem manipulations, so there would be no need for saving and restoring value ofds
.Remember that
ds
is default segment for all addressing exceptBP
usage. You should use it for main purposes of kernel (it will save some bytes and again, it will surely be faster).es
,fs
andgs
are here for you for other memory operations. You can usees
for processing destinations,fs
for filesystem andgs
for video memory pointing. Everything is up to you.Note that some instructions (
movs
,cmps
,scas
...) have pre-assigned combinations of registers and segments (and sometimes only one of them can be overridden), so be wise when chossing them, and attentive when using them.