In response to one of your questions. This code:
startload:
push 0x00000200
ret
Is pretty much the equivalent of a near absolute jump to CS:0x200. We don't know what the value in CS is, but many BIOSes will start with CS=0 and IP=0x7c00 (but that isn't always the case). You can't really rely on CS being a particular value unless you set it your self. In most cases CS is probably zero which means that you are likely jumping to physical memory address 0x00200 (0x0000:0x0200). This happens to be in the middle of the real mode interrupt table that runs from physical address 0x00000 to 0x003FF. Jumping to that location will likely result is some kind of undefined behavior.
You can load your bootloader into BOCHS which has a reasonable debugger that understands 16-bit real mode. You would be able to step through the code and determine exactly what CS is and where it jumps to.
What you are probably trying to accomplish can be done with the following code.
This is a simple alteration of my previous Stackoverflow answer to a different question. To get an understanding of what this code is doing, please see my previous answer.
In a nutshell, the BIOS reads a single disk sector (512 bytes) from the disk starting at physical memory address 0x7C00. If you want other sectors to be loaded you must write code that loads them into memory, and then jump to that code after loading.
In this example the first stage is a bootloader that loads a single sector second stage from sector 2 of the disk (the sector right after the boot sector). In this example I am going to load the second sector right after the first at physical address 0x07e00 via segment:offset pair 0x7e0:0x0000 . (0x07e0<<4)+0x0000 = 0x07e00.
bootload.asm
bits 16
ORG 0x7c00 ; Bootloader starts at physical address 0x07c00
; At start bootloader sets DL to boot drive
; Since we specified an ORG(offset) of 0x7c00 we should make sure that
; Data Segment (DS) is set accordingly. The DS:Offset that would work
; in this case is DS=0 . That would map to segment:offset 0x0000:0x7c00
; which is physical memory address (0x0000<<4)+0x7c00 . We can't rely on
; DS being set to what we expect upon jumping to our code so we set it
; explicitly
xor ax, ax
mov ds, ax ; DS=0
cli ; Turn off interrupts for SS:SP update
; to avoid a problem with buggy 8088 CPUs
mov ss, ax ; SS = 0x0000
mov sp, 0x7c00 ; SP = 0x7c00
; We'll set the stack starting just below
; where the bootloader is at 0x0:0x7c00. The
; stack can be placed anywhere in usable and
; unused RAM.
sti ; Turn interrupts back on
reset: ; Resets floppy drive
xor ax,ax ; AH = 0 = Reset floppy disk
int 0x13
jc reset ; If carry flag was set, try again
mov ax,0x07e0 ; When we read the sector, we are going to read to
; address 0x07e0:0x0000 (phys address 0x07e00)
; right after the bootloader in memory
mov es,ax ; Set ES with 0x07e0
xor bx,bx ; Offset to read sector to
floppy:
mov ah,0x2 ; 2 = Read floppy
mov al,0x1 ; Reading one sector
mov ch,0x0 ; Track(Cylinder) 1
mov cl,0x2 ; Sector 2
mov dh,0x0 ; Head 1
int 0x13
jc floppy ; If carry flag was set, try again
jmp 0x07e0:0x0000 ; Jump to 0x7e0:0x0000 setting CS to 0x07e0
; IP to 0 which is code in second stage
; (0x07e0<<4)+0x0000 = 0x07e00 physical address
times 510 - ($ - $$) db 0 ; Fill the rest of sector with 0
dw 0xAA55 ; This is the boot signature
The second stage will be loaded by INT 13h/AH=2h right after the bootloader in memory, starting at physical address 0x07e00.
stage2.asm
BITS 16
; ORG needs to be set to the offset of the far jump used to
; reach us. Jump was 0x7e0:0x0000 so ORG = Offset = 0x0000.
ORG 0x0000
main:
; Set DS = CS
mov ax, cs
mov ds, ax
; Set to graphics mode 0x13 (320x200x256)
mov ax, 13h
int 10h
; Set ES to the VGA video segment at 0xA000
mov ax, 0xa000
mov es, ax
vga:
; Draw pixel in middle of screen
mov ax, [ycoord]
mov bx, [xcoord]
mov cx, 320
mul cx
add ax, bx
mov di, ax
mov dl, [color]
mov [es:di],dl
; Put processor in an endless loop
cli
.endloop:
hlt
jmp .endloop
; Put Data after the code
xcoord DW 160
ycoord DW 100
color DB 0x0D ; One of the magenta shades in VGA palette
The code above is a slightly altered version of your VGA code, as yours had bugs. Your VGA code didn't properly set the ES segment to 0xA000 which is the start of the VGA graphics memory; it didn't properly de-reference the variables (you used their addresses and not the values);the size of the coordinates were a BYTE instead of a WORD; defined values in variables with ASCII character values. I also moved the data after the code.
I modified the code to draw a pixel in the middle of the 320x200 display and then loop infinitely to end the program.
On Linux (or on Windows with Chrysocome DD) using NASM to assemble, you could generate a 720K bootdisk with these commands:
dd if=/dev/zero of=disk.img bs=1024 count=720
nasm -f bin bootload.asm -o bootload.bin
dd if=bootload.bin of=disk.img conv=notrunc
nasm -f bin stage2.asm -o stage2.bin
dd if=stage2.bin of=disk.img bs=512 seek=1 conv=notrunc
This builds bootload.bin
and places it into the first sector of the disk image, and then builds stage2.bin
and places it in sector 2 of the disk image. The disk image is called disk.img
.
You should be able to test it with QEMU with something like:
qemu-system-i386 -fda disk.img
More information on DD usage can be found in one of my other Stackoverflow answers. Coincidentally that answer was for a question you had last year.