MBR

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.
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

MBR

Post by Matt1223 »

So far my OS was being booted from USB stick that was emulated as FDD. I wan't to change it now so that the USB can be emulated as HDD. It seems like all I have to do is to create a valid partition table in my boot sector (MBR). Am I right? It sound easy but I'm not sure how to make one. The problem is that I don't how to fill in informations like starting CHS, endind CHS and the size of the parition in sectors when I don't know the goemetry of the USB stick? Is a geometry of a USB stick even a thing?

Also, when I manage to make this USB HDD bootloader work, will I be able to use LBA instead of CHS in order to load kernel image from the stick?
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: MBR

Post by Octocontrabass »

Matt1223 wrote:It seems like all I have to do is to create a valid partition table in my boot sector (MBR). Am I right?
In most cases, yes. Some old BIOSes have a setting to choose the emulation type instead of automatically detecting it.
Matt1223 wrote:It sound easy but I'm not sure how to make one. The problem is that I don't how to fill in informations like starting CHS, endind CHS and the size of the parition in sectors when I don't know the goemetry of the USB stick? Is a geometry of a USB stick even a thing?
Unless your USB stick is especially small, you should translate LBA to CHS using 255 heads (not 256!) and 63 sectors per track when coming up with your partitions. USB has no concept of geometry, so the BIOS just makes something up. The geometry you get from INT 0x13 will depend on the BIOS: some will just make something up at random, while others will examine the contents of the disk to decide. (This also happens with floppy disk emulation!)
Matt1223 wrote:Also, when I manage to make this USB HDD bootloader work, will I be able to use LBA instead of CHS in order to load kernel image from the stick?
Most of the PCs I've tested allow LBA even with floppy disk emulation. (Maybe all of them - it was a while ago so I don't remember.)
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

So I added something like that at the end of my bootsector:

Code: Select all

; MBR partition table https://wiki.osdev.org/Partition_Table
times 48 db 0 ; empty entries
db 0x80 ; bootable partition
db 0x0 ; starting head
db 0x1 ; Starting sector (Bits 6-7 are the upper two bits for the Starting Cylinder field.) (Sectors are ennumerated from 1)
db 0x0 ; Starting Cylinder
db 0x4D ; System ID ('M' for MatOS in this case) not important
; For drives bigger than 8GB, generally the CHS fields are set to Cylinder = 1023, Head = 254 or 255, Sector = 63 -- which is considered an invalid setting.
db 0xFF ; Ending Head
db 0xFF ; Ending Sector (Bits 6-7 are the upper two bits for the ending cylinder field)
db 0xFF ; Ending Cylinder
dd 0x00 ; Relative Sector (to start of partition -- also equals the partition's starting LBA value)
dd 16515072; Total Sectors in partition (- 1 ????)

; bootsector signature
dw  0xAA55
It tested it and now my system boots from the USB HDD emulation on every PC I have at home. I cannot, however, get it to boot as a disc on bochs for some reason. My os image is a 34 816 Byte file called matos.raw so I added such lines in .bxsrc file:

Code: Select all

ata0-master: type=disk, path="matos.raw", mode=flat, model="Boot drive"
...
boot: disk
Unfortuantely, once I run it bochs says there is no bootable device. Is it a problem with my .bxsrc configuration or the MBR? Or maybe I should format matos.raw file in some way?

Another thing is that I'm not sure how should the 6 bits of starting sector value in the partition table entry look like. It says here https://wiki.osdev.org/Partition_Table that every value should be little endian. However, little endian desn't make sense when the value is only 6 bits wide I think...

If I want to choose sector 1, should I write "db 0x1" or "db (0x1 << 2)" or maybe "db (0x1 << 7)". I'm confused with it.
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: MBR

Post by Octocontrabass »

Matt1223 wrote:It tested it and now my system boots from the USB HDD emulation on every PC I have at home.
I'm sure some PCs will reject your partition table: you can't have a partition that starts at LBA 0.
Matt1223 wrote:I cannot, however, get it to boot as a disc on bochs for some reason.
My copy of Bochs seems to dislike very small disk images. See if adding some padding to make it bigger helps - perhaps 128 megabytes or so?
Matt1223 wrote:However, little endian desn't make sense when the value is only 6 bits wide I think...
Correct. It only applies to fields that are bigger than a single byte.
Matt1223 wrote:If I want to choose sector 1, should I write "db 0x1" or "db (0x1 << 2)" or maybe "db (0x1 << 7)". I'm confused with it.
The sector number is the lower 6 bits, so "db 0x01" assuming your chosen cylinder is small enough. (But CHS 0/0/1 is LBA 0, and your partition can't start at LBA 0.)
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

Octocontrabass wrote:I'm sure some PCs will reject your partition table: you can't have a partition that starts at LBA 0.
I'll correct it.
Octocontrabass wrote:My copy of Bochs seems to dislike very small disk images. See if adding some padding to make it bigger helps - perhaps 128 megabytes or so?
That solved the issue. Thank you.
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

I'm having another problem with bochs now. So when I try to load my kernel I'm getting such error: "IO write(0x01f0): current command is 20h". It happens when I try to read more then 65 (why 65 ?) blocks at once, otherwise it works fine. I'm surprise that it is a problem because I read it in LBA mode. This is the code:

Code: Select all

; read kernel (in LBA mode)
; Set DS:SI -> Disk Address Packet in memory
mov ax, 0x0000
mov ds, ax
mov si, disk_adress_packet
mov ah, 0x42
; dl is set by BIOS
clc
sti
int 13h
cli
jc error
...
disk_adress_packet:
db 16 ; size of packet
db 0x00 ; reserved (0)
dw 0x007F ; number of blocks to transfer (max 007Fh for Phoenix EDD)
dd 0x00007E00; transfer buffer ; 0x0000:0x7E00; ;0x00007E00-0x0007FFFF	480.5 KiB	RAM (guaranteed free for use)	Conventional memory (kernel img at the bottom and stack at the top)
dd 3; lower 32-bits of 48-bit starting LBA
dd 0; upper 16-bits of 48-bit starting LBA
How can I deal with it and why is it happening in LBA mode? I'm supposed to be able up to 0x7F blocks at once!
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: MBR

Post by Gigasoft »

The BIOS disk functions have the limitation that the entire data buffer must reside within the specified segment. (And for floppy disks, there is an additional limitation where the lower 16 bits of the address must not overflow.)
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

Gigasoft wrote:The BIOS disk functions have the limitation that the entire data buffer must reside within the specified segment. (And for floppy disks, there is an additional limitation where the lower 16 bits of the address must not overflow.)
So It should work fine if I change the buffer adress to 0x0000:0x0000, right?
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: MBR

Post by Octocontrabass »

No, that will overwrite the IVT, the BDA, and your bootloader. You're still using those.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: MBR

Post by MichaelPetch »

Where did you place your stack? If you didn't set up your own stack when starting the bootloader, BOCHS default BIOS sets SS:SP to 0x0000:0x0000. The stack will wrap at the top of the first 64KiB segment growing down from 0x0000:0xffff. If you read too many sectors, the stack will become corrupt and the disk read interrupt will never return properly and execute some place in memory that isn't expected (likely causing a reboot, or crash of some sort). If you did set up your own stack where did you put it? Are you potentially reading sectors on top of the stack?

Setting the stack SS:SP to 0x0000:0x7c00 will make sure it is out of the way as it will grow down from beneath the bootloader in memory.
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

So I figured I'm gonna save my kernel at 0x0001:0x0000 because 0x00007E00-0x0007FFFF is a guaranteed free for use area and I will have the entire segment for my data buffer. My disk adress packet looks like this now:

Code: Select all

disk_adress_packet:
db 16 ; size of packet
db 0x00 ; reserved (0)
dw 127 ; number of blocks to transfer (max 007Fh -> 127 for Phoenix EDD)
dw 0x0000 ; transfer buffer ; 0x0001:0x0000; ;0x00007E00-0x0007FFFF	480.5 KiB	RAM (guaranteed free for use)	Conventional memory
dw 0x1000
dd 3; lower 32-bits of 48-bit starting LBA
dd 0; upper 16-bits of 48-bit starting LBA
For some reason I'm now getting error no matter haw many blocks I want to transfer.
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: MBR

Post by Octocontrabass »

That's 0x1000:0x0000, which is linear address 0x10000. That should work, as long as it's not overlapping your stack or something.

Perhaps there's a bug elsewhere in your code, or maybe your disk is too small.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: MBR

Post by MichaelPetch »

Okay, but have you moved the stack somewhere safe like beneath the bootloader at 0x0000:0x7c00 so that you don't overwrite the stack? ";0x00007E00-0x0007FFFF (guaranteed free for use)" is a misleading statement by the author of that comment.

That statement assumes that you don't have anything in that space that can get clobbered. Unfortunately BOCHS puts the stack growing downward from physical address 0x10000. In your original code reading 65 sectors would clobber the default BOCHS stack location (64 would likely be safe but still a potential problem)

As Octo pointed out if you want to put something at physical address 0x10000 you'd use a segment offset pair of 0x1000:0x0000. But realistically you are still taking a risk because while that may work with BOCHS the stack could be in the way in some other environment. I don't know why you didn't stick with what you originally had and then set SS:SP to something below the bootloader (like SS:SP=0x0000:0x7c00). If you move the stack somewhere safe where you know you won't read on top of it then overwriting the stack becomes a non issue.
Matt1223
Member
Member
Posts: 45
Joined: Mon Jul 30, 2018 2:58 am

Re: MBR

Post by Matt1223 »

MichaelPetch wrote:Okay, but have you moved the stack somewhere safe like beneath the bootloader at 0x0000:0x7c00 so that you don't overwrite the stack?
You were right. The stack was the issue. I was pretty sure my stack is at 0x7FFF0 linear adress but when I came back to the code it turned out I was setting it to 0x0007:0xFFF0. I fixed that and it works fine now.

I'm dealing with a code that I wrote few years ago so there are a lot of surprises everywhere.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: MBR

Post by MichaelPetch »

I created this simple bootloader. It sets up the segment registers and sets SS:SP to grow down beneath the bootloader moving the stack out of the way so you can read more than 65 sectors at 0x7e00:

Code: Select all

BITS 16
ORG 0x7c00

start:
    xor ax,ax
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,0x7c00

    ; read kernel (in LBA mode)
    ; Set DS:SI -> Disk Address Packet in memory
    mov si, disk_adress_packet
    mov ah, 0x42
    int 0x13
    jmp $             ; Infinite loop

disk_adress_packet:
    db 16
    db 0x00
    dw 127
    dd 0x00007E00
    dd 3
    dd 0

times 510-($-$$) db 0
dw 0xaa55

; Create ~10MB of data to create a hard disk drive image

times 10*1024*1024 db 0x00 
This code does read 127 sectors from disk into memory. If I comment out these 2 lines that set SS:SP:

Code: Select all

;    mov ss,ax
;    mov sp,0x7c00
then I get an error similar to what you originally saw:

Code: Select all

>>PANIC<< IO write(0x01f0): current command is 20h
If I reduce the 127 to 64 the error disappears and at 65 the error appears. This is a direct result of 65 sectors overwriting data on the stack. By moving the stack SS:SP to somewhere I know it won't get clobbered like 0x0000:0x7c00 I avoid the problem. QEMU puts the default stack in a different place than BOCHS and real hardware could put it anywhere. Never rely on the BIOS supplied stack if you intend to read things into memory. Reading things into memory where you don't know the location of the stack is asking for trouble if you accidentally overwrite it.

A note. If you find BOCHS won't even load a disk image check to see if there is file with a '.lock' extension in your directory and remove it.
Last edited by MichaelPetch on Thu Mar 09, 2023 5:46 pm, edited 4 times in total.
Post Reply