Hello, I've recently gotten started trying to make a little hobby OS, and I've wanted to do something a little more useful than printing out 'Hello, World!', so I tried to write
a tiny bootsector that is supposed to read the next sector on the hard drive (I'm running it in qemu so my file appears as that). However it always gives me the
'failed to read sector' message, is there a way that I can treat a disk as a "flat" bunch of numbered sectors? Am I approaching this completely wrong?
Help would be very much appreciated.
I guess I should mention this is done in Assembly using nasm on an Ubuntu machine, being tested on qemu.
http://pastebin.com/FVjEm5iN (bootload.asm)
~ I'm sorry for the noob question
Loading Sectors in Real Mode (Using the BIOS)
-
- Posts: 15
- Joined: Thu Jan 20, 2011 4:19 pm
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Loading Sectors in Real Mode (Using the BIOS)
Please set your registers before using them (DS/ES/SS/SP). Actually calling the bios helps too.
Re: Loading Sectors in Real Mode (Using the BIOS)
You want function 2, not function 1, to read sectors. You also have to specify what sectors you want to read. Google "Ralf Brown's Interrupt List."
-
- Posts: 15
- Joined: Thu Jan 20, 2011 4:19 pm
Re: Loading Sectors in Real Mode (Using the BIOS)
*facepalm* thanks, added the call to the BIOS and it at least says it works (need to play around with it to test).
What should I initialize the pointers to? 0?
What should I initialize the pointers to? 0?
Re: Loading Sectors in Real Mode (Using the BIOS)
Yes. It is possible that your BIOS, or other BIOSes where your OS might run on is a bit bogus and doesn't set them to zero by default. Programming and especially OS programming is very explicit - you should not assume things. When booting you should set at least your data segment, extra segment and stack segment to 0. I recommend that you also set your code segment and other extra segments (fs and gs) to zero. Besides setting segment register you should also set up a stack.ajtgarber wrote:*facepalm* thanks, added the call to the BIOS and it at least says it works (need to play around with it to test).
What should I initialize the pointers to? 0?
Also other assumptions in your code should be avoided:
Code: Select all
mov ah, 0x02 ; read sector
mov al, 1
mov ch, 1 ; track
mov cl, 1 ; sector
mov dh, 1 ; head
mov dl, 0x80 ; read from first hd
mov bx, 0x7E00
- The sector number is 1 based, so you are reading your masterboot again, which is not very useful
The track and head numbers are NOT one based, they are zero based.
You want to load the the physical address 0x7e00, which is fine, but you are assuming the es register is set to 0. Do not assume, set it manually.
Bietje
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Loading Sectors in Real Mode (Using the BIOS)
Actually, the BIOS is more likely bogus (or predates the relevant boot standards) if it does set all segments to zero.or other BIOSes where your OS might run on is a bit bogus and doesn't set them to zero by default.
Re: Loading Sectors in Real Mode (Using the BIOS)
Yep, it's called LBA (linear block address). Also check RBIL INT13/AH=42h, that's what you need.ajtgarber wrote:is there a way that I can treat a disk as a "flat" bunch of numbered sectors?
Re: Loading Sectors in Real Mode (Using the BIOS)
here is the boot sector code i am using for my OS (it's simple as the floppy has no actual file system yet, i read code raw from pre-defined sectors. i've got it commented, hopefully it's easy to understand.
and, proof it actually works
booting my own "OS" in an 8086 PC emulator i wrote myself.. when it's time to geek out, i spare no expenses.
Code: Select all
org 7C00h
jmp entry
nop
;BIOS parameter block data
oem db 'MT86',0,0,0,0 ;8-byte OEM identifier
bytespersect dw 512
sectperclust db 1 ;no real FAT filesystem on disk yet, this value is irrelevant
reservedsect dw 1 ;so is this one
numoffats db 1 ;and this one
rootentries dw 0 ;yep, you guessed it. irrelevant!
totalsects dw 2880 ;ditto
descriptor db 0F0h ;media descriptor (0F0h = 1.44 MB floppy)
sectsperfat dw 2 ;irrelevant for now
spt db 18, 0 ;sectors per track
heads db 2 ;what it says
hiddensects dw 0,0 ;32-bit, but meaningless value on a floppy
totalsects2 dw 0,0 ;same deal
entry:
mov ax, cs
mov ds, ax ;our variables are right here in the code segment, so change ds to cs
mov si, offset banner
call printmsg ;print "loading" message
mov ax, 0E00h ;the sector after the boot sector contains the MT86 OS
mov es, ax ;multi-tasking code, and it needs to be loaded into 0E00h:0000h
mov bx, 0 ;offset 0
mov [retry], 0
read1:
cmp [retry], 8 ;if we've retried 8 times due to errors,
je loadfail ;then we throw in the towel
mov ah, 2 ;int 13h function 2 = read sector(s)
mov al, 1 ;we want one sector
mov cl, [sect]
mov ch, [cyl]
mov dh, [head]
int 13h ;do the call
inc [retry]
jc read1
inc [sect]
mov ax, 1000h ;the rest of the data on this disk is the main kernel,
mov es, ax ;and we want it at 1000h:0000h
mov bx, 0 ;offset 0
mov [retry], 0
read:
cmp [retry], 8
je loadfail
push bx ;save our current destination offset on the stack, in case a buggy BIOS destroys BX
mov ah, 2
mov al, 1
mov cl, [sect]
mov ch, [cyl]
mov dh, [head]
int 13h
pop bx ;pop offset back into BX
inc [retry]
jc read
mov [retry], 0 ;if successful read, reset the retry count for the next sector
mov ah, 0Eh ;print a dot after each sector is read to indicate progress
mov al, '.'
int 10h
add bx, 512 ;increase destination offset with each new sector read
dec [readcount]
cmp [readcount], 0 ;have we read all the sectors we wanted to now?
jz done ;then finished with disk reads...
inc [sect] ;increment current sector
mov al, [sect]
cmp al, [spt] ;is it now higher than our max sector value?
ja inchead ;then go wrap it around and increment the head
jmp read ;otherwise, read next sector
inchead:
mov [sect], 1 ;reset current sector number
inc [head] ;increment current head
mov al, [head]
cmp al, [heads] ;has it reached the maximum?
je inccyl ;go wrap it around and increment the cylinder
jmp read ;otherwise, read next sector
inccyl:
mov [head], 0 ;reset current head
inc [cyl] ;increment cylinder
jmp read ;read next sector
done: ;now jump to the kernel entry point 1000h:0100h
mov ax, 1000h ;set up segments and stack
mov ss, ax
mov sp, 0000h
mov ds, ax
mov es, ax
push ax ;we'll use the CS:IP push and retf trick
mov ax, 100h
push ax
retf
printmsg: ;enter with near offset to ASCII-Z string in SI
cld
nextchar:
lodsb
cmp al, 0
jz printdone
mov ah, 0Eh
int 10h
jmp nextchar
printdone:
ret
loadfail:
mov si, offset error
call printmsg
hlt
sect db 2
head db 0
cyl db 0
retry db 0
readcount db 32 ;number of sectors to read when loading kernel
banner db 'Loading MT86 kernel', 0
error db 'disk error!',13,10,13,10,'System halted.', 0
and, proof it actually works
booting my own "OS" in an 8086 PC emulator i wrote myself.. when it's time to geek out, i spare no expenses.