MBR
MBR
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?
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?
-
- Member
- Posts: 5562
- Joined: Mon Mar 25, 2013 7:01 pm
Re: MBR
In most cases, yes. Some old BIOSes have a setting to choose the emulation type instead of automatically detecting it.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?
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: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?
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 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?
Re: MBR
So I added something like that at the end of my bootsector:
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:
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.
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
Code: Select all
ata0-master: type=disk, path="matos.raw", mode=flat, model="Boot drive"
...
boot: disk
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.
-
- Member
- Posts: 5562
- Joined: Mon Mar 25, 2013 7:01 pm
Re: MBR
I'm sure some PCs will reject your partition table: you can't have a partition that starts at LBA 0.Matt1223 wrote:It tested it and now my system boots from the USB HDD emulation on every PC I have at home.
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:I cannot, however, get it to boot as a disc on bochs for some reason.
Correct. It only applies to fields that are bigger than a single byte.Matt1223 wrote:However, little endian desn't make sense when the value is only 6 bits wide I think...
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 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.
Re: MBR
I'll correct it.Octocontrabass wrote:I'm sure some PCs will reject your partition table: you can't have a partition that starts at LBA 0.
That solved the issue. Thank you.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?
Re: MBR
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:
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!
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
Re: MBR
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.)
Re: MBR
So It should work fine if I change the buffer adress to 0x0000:0x0000, right?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.)
-
- Member
- Posts: 5562
- Joined: Mon Mar 25, 2013 7:01 pm
Re: MBR
No, that will overwrite the IVT, the BDA, and your bootloader. You're still using those.
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: MBR
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.
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.
Re: MBR
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:
For some reason I'm now getting error no matter haw many blocks I want to transfer.
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
-
- Member
- Posts: 5562
- Joined: Mon Mar 25, 2013 7:01 pm
Re: MBR
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.
Perhaps there's a bug elsewhere in your code, or maybe your disk is too small.
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: MBR
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.
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.
Re: MBR
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.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?
I'm dealing with a code that I wrote few years ago so there are a lot of surprises everywhere.
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: MBR
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:
This code does read 127 sectors from disk into memory. If I comment out these 2 lines that set SS:SP: then I get an error similar to what you originally saw:
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.
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
Code: Select all
; mov ss,ax
; mov sp,0x7c00
Code: Select all
>>PANIC<< IO write(0x01f0): current command is 20h
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.