I'm playing with the Real mode and was trying to code something when suddenly I exceeded the 510
boundary (.org 510
) of the 512
boot sector size for BIOS and as
warning popped out:
code.s: Assembler messages:
code.s:<line num>: Error: attempt to move .org backwards
So I started reading about how to split the code into multiple sectors and load them from the disk using the floppy for simplicity.
I'm probably missing a lot of stuff one of which would be manual stack init, though I'm not sure if that would affect the loading as it's coded here. I'm using -monitor stdio
to check the values in registers if necessary with info registers
. Seems sufficient enough for now, but feel free to suggest better debugging tools that work with Qemu.
Feel free not to hold back, I'd like to learn more. :)
The code is simple:
- stores the disk number the boot sector was loaded from
- prints
a
from the first sector via aprint
label - loads the next sector right after the boot sector in memory (to
0x7c00
+0x200
) - prints
b
from the second sector using theprint
label from the first sector, so should prove that it's not overlapping in or something weird like that - jumps to infinite loop to keep it running
Building:
#!/bin/sh -xe
as -o code.o code.s -g --statistics --warn --fatal-warnings
ld -o code.bin --oformat=binary -Ttext=0x7c00 --build-id=none code.o
qemu-system-i386 -monitor stdio -drive file=code.bin,index=0,if=floppy,format=raw
Code:
.att_syntax
.code16
.global _start
.text
// sector 1 begin
_start:
// store booted from disk number for sector loading
mov %dl, diskNum
mov $'a', %al
call print
jmp load_next_sector
print:
// expects char to print in %al
mov $0x0e, %ah
int $0x10
ret
load_next_sector:
// load the code to memory directly after the boot sector
// boot: [0x7c00, 0x7c00 + 512); after: 0x7e00 = 0x7c00 + 512
// service 02h: Read Sectors From Drive
mov $0x02, %ah
// Sectors To Read Count
mov $0x01, %al
// Cylinder/Track number 1 (zero-based)
mov $0x00, %ch
// Sector number 2 (one-based)
mov $0x02, %cl
// Head 1 (zero-based)
mov $0x00, %dh
// Disk Number
mov diskNum, %dl
// set Buffer Address Pointer to after boot sector (0x7e00)
// es:bx = 0x7e00 -> es * 16 + bx = 0x7e00 -> 0 * 16 + 0x7e00
push $0x00
pop %es
mov $0x7e00, %bx
int $0x13
// fail, AL codes: http://www.oocities.org/wangxuancong/int13h.html
jc load_next_sector
// success
jmp sector_2
.org 510
.word 0xAA55
// sector 1 end
// sector 2 begin
sector_2:
mov $'b', %al
call print
jmp pause
pause:
jmp pause
.data
diskNum:
.byte 0xff
.org 1024
// sector 2 end
.end
Binary:
0000000 1688 8000 61b0 02e8 eb00 b405 cd0e c310
0000010 02b4 01b0 00b5 02b1 00b6 168a 8000 006a
0000020 bb07 7e00 13cd e872 d5e9 0001 0000 0000
0000030 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200 62b0 06e8 ebfe eb00 00fe 0000 0000 0000
0000210 0000 0000 0000 0000 0000 0000 0000 0000
*
0000400 00ff 0000 0000 0000 0000 0000 0000 0000
0000410 0000 0000 0000 0000 0000 0000 0000 0000
*
0000800
Output:
0x7c00
+0x100
. In other words, you got a typo here: should read0x200
. \$\endgroup\$256
(0x100
,0x7d00
) instead of512
(0x200
,0x7e00
), then I forgot about it and left it in the text. Thanks, editing! \$\endgroup\$