New user - New road ahead.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
StillTrying
Posts: 13
Joined: Fri May 15, 2015 9:18 am

New user - New road ahead.

Post by StillTrying »

Hello all,

Been lurking and admiring for a while now, was put off joining by a guy in an IRC who said I wouldn't make much progress learning and getting 'RTFM' on each question. Everyone seems nice enough and I'm in dire need of help so I've had to take the plunge.

I have a quick question regarding Virtual Machine BIOS and disk image structure.

I tried OS dev a while back, years ago I was about 15. I was going to sign up due to a problem I was having. Alas, 7 years later I still got stuck in the same spot and it's really been pulling my teeth out.

I cannot for the life of me load a sector from an image into memory on a VM.

Here is my code to read the second sector on disk, should know it like the back of your hand:

Code: Select all

mov	ax, 0x1000		; we are going to read sector to into address 0x1000:0
mov	es, ax;
xor	bx, bx;
mov	ah, 0x02		; read floppy sector function
mov	al, 1			; read 1 sector
mov	ch, 0			; we are reading the second sector past us, so its still on track 1
mov	cl, 2			; sector to read (The second sector)
mov	dh, 0			; head number
mov	dl, [start_drive]	; drive number. Remember Drive 0 is floppy drive.
int	0x13			; call BIOS - Read the sector
jc     .Reset;
mov	si, load_ok;
call 	Print;
jmp   0x1000:0		; jump to execute the sector!
As far as I can tell the VM doesn't triple fault, it hangs. VirtualBox doesn't give me much debug data, I've tried Bochs with my image but that doesn't get off the start line.

It prints out the message right before jumping to the next sector, when it reaches the other side, it's supposed to print again saying we're in the next sector, but rather it seems it passes the Print function, and goes straight to halt. Here is my sector 2:

Code: Select all

; Sector 2 - Loader continued

bits 16;

jmp kernel_main;

Print:
	lodsb			; load next byte from string from SI to AL
	or	al, al		; Test for null terminator
	jz	.Done;
	mov	ah, 0eh;
	int	10h
	jmp	Print		; Repeat until done
.Done:
	ret;

kernel_main:
    mov     	si, kernel_msg;
    call    	Print;
    cli;
    hlt;

kernel_msg db "Kernel loaded at 0x1000:0",0;

times 512 - ($-$$) db 0;
Hopefully my code is okay. Now this is where my question comes into play:

VirtualBox allows me to plug the binary file from nasm ( For instance nasm -o boot.bin ) directly into the floppy drive source. It loaded, and the messages printed out. This has lead me to believe that the VM BIOS is able to see the image, and use it's own function(13hF2 ) to load the first sector on the disk ( Which would be the only one at this point ) to 0x7c00. All good and gravy.

So now my image is basically made from 2 sectors, being 512 bytes each, and concatenated in series to produce a 1024 binary file.

Is my image format flawed? I thought it was safe to assume if I had made my second file exactly 512 bytes long I would of essentially made the second sector, for the boot sector to load it with int 13h.

I even wrote my own hex viewer ( As a break away from the assembly, I thought I may have been missing something ) and everything seems okay, I saw the 55 AA at the end of the first sector, then started the code from the second file, padded with zeros to the end. I copied by bytes into a converter and the instructions came out crystal saying it is doing exactly what it should be doing.

int 13hF2 is supposed to set the carry if it fails, doesn't fail. So success, right? I'm not so sure, AL is supposed to hold the amount of sectors actually read, when I test against it, it fails, didn't read the sector.



I've just realised how long I have been writing for. I'm completely stumped believe me I've been trying. I'll have a smoke a leave it with you.

Rob.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: New user - New road ahead.

Post by Brendan »

Hi,
StillTrying wrote:int 13hF2 is supposed to set the carry if it fails, doesn't fail. So success, right? I'm not so sure, AL is supposed to hold the amount of sectors actually read, when I test against it, it fails, didn't read the sector.
For some BIOSs, AL is only set when there's an error. I wouldn't rely on AL being set for either case (success or fail).

The only thing I can see wrong with anything you wrote (including the code) is that normally (especially for floppy) you'd want to retry several times and then give up and display a nice descriptive error message (so the end user can figure out what the problem is). However this is almost entirely unnecessary for virtual machines.

This implies that the problem is in something you didn't provide. For a simple/random (and potentially unlikely) example, maybe "[start_drive]" wasn't set correctly, causing the (correct looking) code that loads a sector to attempt to load from something that isn't even a disk drive.

Note: It might help to know the value that the BIOS "int 0x13, ah=0x02" function returns in AH when there's an error - this is the status code from the operation.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: New user - New road ahead.

Post by DavidCooper »

When the code in your first sector calls the routine "print" in the second sector, where is that code sitting in memory, and where does the assembler think it is when it generates a jump distance to it for the call? (That doesn't seem likely though - maybe you have a print routine in your first sector as well, but you haven't shown it.)

Edit: no, forget that - I missed the point that the first print worked. Show all your code.

What I'm now looking at is the bit " mov si, kernel_msg;" - how does that line up on the message correctly without an org directive at the top? What's the content of DS?
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
StillTrying
Posts: 13
Joined: Fri May 15, 2015 9:18 am

Re: New user - New road ahead.

Post by StillTrying »

@ Brenden

Thanks for your astute reply.

I do have a jump condition to retry for both the reset and the read. I understand about AH returning the status code, I have that test secure I believe.

Here is the full source for the first sector for both you and David's pleasure:

Code: Select all

bits	16; We are in 16 bit Real Mode

org	0x7c00; We are loaded by BIOS at 0x7C00

start:  jmp loader; jump to start

;*************************************************;
;	            BIOS Parameter Block
;*************************************************;

TIMES 0Bh-$+start DB 0

bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	DB 2
bpbRootEntries: 	DW 224
bpbTotalSectors: 	DW 2880
bpbMedia: 	        DB 0xF0
bpbSectorsPerFAT: 	DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors:       DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 	        DB 0
bsExtBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "

Print:
	lodsb				; load next byte from string from SI to AL
	or	al, al		; Test for null terminator
	jz	MoveCursor;
	mov	ah, 0eh;
	int	10h
	jmp	Print		; Repeat until done
MoveCursor:
	mov     ah, 0x02    ; Set cursor position
	mov     bh, 0x00    ; page 0
	mov     dl, 0x00    ; column 0
	mov     dh, [terminal_row];
	inc     dh;
	int     10h;
	mov     [terminal_row],dh;
	ret;					;

startup db "System loading...",0;
reset_ok db "Floppy reset - Attempting to load sector 2",0;
load_ok db "Sector 2 loaded",0;
terminal_row db 0;

start_drive db 0;

;*************************************************;
;	Bootloader Entry Point
;*************************************************;

loader:
    	mov     [start_drive], dl       ; save drive number
    	xor     ax,ax                   ; Set up segments
    	mov     ds,ax;
    	mov     es,ax;
    	cli                             ; Set up stack
    	mov     ss,ax;
    	mov     sp,0x7C00;
    	sti;
 	mov	    si, startup;
	call 	Print;
.Reset:
	mov	ah, 0			; reset floppy disk function
	mov	dl, [start_drive]	; drive 0 is floppy drive
	int	0x13			; call BIOS
	jc	.Reset			; If Carry Flag (CF) is set, there was an error. Try resetting again

	mov	si, reset_ok;
	call	Print;
	mov	ax, 0x1000		; we are going to read sector to into address 0x1000:0
	mov	es, ax;
	xor	bx, bx;

	mov	ah, 0x02		; read floppy sector function
	mov	al, 1			; read 1 sector
	mov	ch, 0			; we are reading the second sector past us, so its still on track 1
	mov	cl, 2			; sector to read (The second sector)
	mov	dh, 0			; head number
	mov	dl, [start_drive]	; drive number. Remember Drive 0 is floppy drive.
	int	0x13			; call BIOS - Read the sector
	cmp     ah,0x00;
	jne     .Reset;

	mov	si, load_ok;
	call 	Print;
	
	jmp     0x1000:0		; jump to execute the sector!


times 510 - ($-$$) db 0			; We have to be 512 bytes. Clear the rest of the bytes with 0

dw 0xAA55				; Boot Signature


@David

I am not so sure, my code is an adaptation to the BrokenThorn series, I tried the org 0x1000 too and the same thing happens.
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: New user - New road ahead.

Post by DavidCooper »

I still think it's DS not being set in your second sector - the print routine may be working but it's finding empty memory (zeros) and returning without printing anything, then it halts.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: New user - New road ahead.

Post by Brendan »

Hi,

Try changing from this:

Code: Select all

loader:
    	mov     [start_drive], dl       ; save drive number
    	xor     ax,ax                   ; Set up segments
    	mov     ds,ax
To this:

Code: Select all

loader:
    	xor     ax,ax                   ; Set up segments
    	mov     ds,ax
    	mov     [start_drive], dl       ; save drive number

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
StillTrying
Posts: 13
Joined: Fri May 15, 2015 9:18 am

Re: New user - New road ahead.

Post by StillTrying »

@David

Seen as only a few bytes of the second sector are actually code, the rest being zero's it seems very viable?

Could you give me a little tutorial on DS and when I would neet to set/change it? My segment register knowledge is very limited, I hope to learn more by using it, everything's fine in theory, but practically is a different story for me.

@Brenden

Just did your changes and fired up, still same thing. I get my 3 messages then a hang. Oh why can I never beat this step.
User avatar
TightCoderEx
Member
Member
Posts: 90
Joined: Sun Jan 13, 2013 6:24 pm
Location: Grande Prairie AB

Re: New user - New road ahead.

Post by TightCoderEx »

at kernel_main

Code: Select all

mov    ax, cs
mov    ds, ax
or

Code: Select all

mov     ax, 0x1000
mov     ds, ax
Tested using BOCH's unchanged other than setting DS as mentioned above.
Last edited by TightCoderEx on Fri May 15, 2015 11:30 am, edited 1 time in total.
StillTrying
Posts: 13
Joined: Fri May 15, 2015 9:18 am

Re: New user - New road ahead.

Post by StillTrying »

@TightCoder

I owe you a bloody pint. My heart trembled when I saw "Kernel loaded..."

This is excellent news, I can finally start to expand on my OS knowledge.

Could you explain where I went wrong?
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: New user - New road ahead.

Post by DavidCooper »

DS is used by default with SI, so until you set DS to the right segment, it can't find the message it's supposed to print.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: New user - New road ahead.

Post by kzinti »

StillTrying wrote:Could you explain where I went wrong?
You didn't initialize DS.
StillTrying
Posts: 13
Joined: Fri May 15, 2015 9:18 am

Re: New user - New road ahead.

Post by StillTrying »

@David

"so until you set DS to the right segment"

So what is the right segment to be exact? Whenever I make a jump I must set DS to whatever segment base I jump too?

Is this only for separate files, or if I make a jump that exceeds X bytes I must reset DS?
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: New user - New road ahead.

Post by DavidCooper »

StillTrying wrote: So what is the right segment to be exact? Whenever I make a jump I must set DS to whatever segment base I jump too?
You have to think about where the data you want to access is sitting. In this case the data to be printed is sitting in the second 64K block of memory that real mode can access, and if DS is zero it doesn't have the range to reach that when using SI. Most of your data accessing will be done using DS to select the right segment, though DI uses ES by default instead - this allows you to copy from one segment to another without having to keep changing the content of segment registers. CS is used for program code and SS for the stack.
Is this only for separate files, or if I make a jump that exceeds X bytes I must reset DS?
You can jump anywhere you like in memory and CS will be loaded automatically with a far jump, far call or far ret, but when that code needs to access data it always has to set DS (or ES, FS or GS) to the 64K area of memory in which that data resides. Note that memory accesses using BP use SS by default.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
glauxosdev
Member
Member
Posts: 119
Joined: Tue Jan 20, 2015 9:01 am
Libera.chat IRC: glauxosdever

Re: New user - New road ahead.

Post by glauxosdev »

You have to learn how the 16bits real mode addressing works.
segment:offset ~> absolute = segment*16+offset

There must be also an org statement, which must equal address at which is loaded the binary. For example, the boot sector is loaded at absolute 0x00007C00, so the most easy way is to set segments to 0x0000 & org to 0x7C00.

Edit: I apologize for not saying the second way: segments to 0x07C0 and org to 0x0000.

You will have to adapt this example above for every situation. So for a binary loaded at 0x00010000, which will be the segments and which the org?

Regards,
glauxosdev
Last edited by glauxosdev on Wed Jun 03, 2015 6:46 am, edited 1 time in total.
User avatar
TightCoderEx
Member
Member
Posts: 90
Joined: Sun Jan 13, 2013 6:24 pm
Location: Grande Prairie AB

Re: New user - New road ahead.

Post by TightCoderEx »

Have a look at my boot loader. A lot of stuff I've done in it, isn't necessary, but it does reinforce the concept of segmentation and I think it's documented well enough so you can follow the logic.
Attachments
boot.asm
X86 Bootloader
(8.99 KiB) Downloaded 133 times
Post Reply