Page 1 of 1

Reading floppy by offset?

Posted: Wed Jan 25, 2017 3:42 pm
by monobogdan
Hello.

Now, i'm writing cool open source os. And so, i'm implement 50% of drivers(keyboard, display).

But i'm stuck how to read floppy by offset.

For example, i'm want to read MBR:

Code: Select all

dskread(0, 512); // First argument - offset, second - size
Or for example read 200 from start of disk:

Code: Select all

dskread(200, 200); // First argument - offset, second - size
How to do it's?

I know about int 13h, but i don't know how to use it's for reading BY OFFSET.

Re: Reading floppy by offset?

Posted: Wed Jan 25, 2017 4:09 pm
by BrightLight
You can't. Sector-based devices, including floppy disks, CDs/DVDs, hard disks, USB mass storage devices, etc..., are meant to be addressed as sectors and not byte offsets. If you want to read 200 bytes from offset 200, you have to find out which sector does offset 200 start at, and then the offset into that sector and how many sectors to load. All of this can be done with basic mathematical equations which you should, as an OS developer, be able to conclude with your own head. You then write a routine which does all this, and internally uses INT 0x13 (or your own floppy driver) to actually read physical sectors.

Re: Reading floppy by offset?

Posted: Wed Jan 25, 2017 10:03 pm
by Brendan
Hi,
monobogdan wrote:How to do it's?

I know about int 13h, but i don't know how to use it's for reading BY OFFSET.
You need to:
  • Determine the media format (e.g. if it's "standard 1440 KiB floppy" or something else). This will tell you the geometry of the floppy disk (how many sectors per track, how many heads and how many cylinders).
  • Write a "LBA to CHS conversion" routine (which depends on the geometry of the floppy disk)
I'd recommend having a "wrapper function" for this, where that wrapper:
  • does the "LBA to CHS conversion"
  • breaks larger reads/writes into smaller pieces at track boundaries (because some BIOSs have trouble reading/writing past track boundaries)
  • calls "int 0x13" for each smaller piece
  • handles the "retry N times if error" stuff, possibly including:
    • breaking multi-sector reads/writes into "one sector at a time" to increase the chance of success
    • resetting the device between (some) retries, not necessarily every time (e.g. maybe every 2nd time you retry)
Note that there are 2 ways to detect the geometry of the floppy disk. The first way is to use a clever test sequence, where each test is designed to split the possibilities until only one possibility remains. This can always work (for all floppy disks, including non-standard floppy disk formats); but requires a native floppy driver.

The second way is to rely on the existence of a correct "BPB" in the first sector. This fails when the density is wrong (e.g. "low density" 360 KiB floppy when you're expecting "high density") because you can't read the BPB in that case; and it fails when there isn't a correct BPB for any reason; and it fails for all cases where a BPB can't describe the floppy format (e.g. advanced formats that use 512-byte sectors for the first track, then larger sectors for remaining tracks to waste less space/increase capacity).

Also note that floppy disks are very slow and also relatively small; and this combination makes caching very effective. Don't forget that seeking can cost more than reading an entire track, so pre-fetching entire tracks or cylinders into your cache in the background (when floppy drive isn't busy and your heads are already on that track) can dramatically improve performance by avoiding "future seeks".

Unfortunately; while the hardware is designed for "read/write in background" (using DMA and IRQs) the BIOS is not; and while the hardware is designed to notify you when a disk is changed the BIOS is not. This means that for efficient pre-fetching; and for cache management (including discarding cached data when the floppy disk is removed/changed); and for detecting media properly; you need to write your own driver. Essentially; (even for a "real mode single-tasking OS") the BIOS is a worthless piece of trash that should not be used for anything other than the boot loader.


Cheers,

Brendan

Re: Reading floppy by offset?

Posted: Wed Jan 25, 2017 11:56 pm
by Antti
Brendan wrote:and while the hardware is designed to notify you when a disk is changed the BIOS is not
There is rudimentary support for "disk changed" because it was an essential part of operating floppy disks. You will not get a notify message via IPC, or course, and it is not asynchronous.

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 1:15 am
by monobogdan
omarrx024 wrote:You can't. Sector-based devices, including floppy disks, CDs/DVDs, hard disks, USB mass storage devices, etc..., are meant to be addressed as sectors and not byte offsets. If you want to read 200 bytes from offset 200, you have to find out which sector does offset 200 start at, and then the offset into that sector and how many sectors to load. All of this can be done with basic mathematical equations which you should, as an OS developer, be able to conclude with your own head. You then write a routine which does all this, and internally uses INT 0x13 (or your own floppy driver) to actually read physical sectors.
Hello, thanks for you reply.

Okay. Single sector is 512 bytes.

For read from offset 200 i need to calculate needed sector. But now i don't know how to do this(it's not hard, but now i have no idea).

But if read absolute i can read it's in allocated ptr with size 512 bytes, and then clean garbage.

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 1:17 am
by monobogdan
Brendan wrote:Hi,
monobogdan wrote:How to do it's?

I know about int 13h, but i don't know how to use it's for reading BY OFFSET.
You need to:
  • Determine the media format (e.g. if it's "standard 1440 KiB floppy" or something else). This will tell you the geometry of the floppy disk (how many sectors per track, how many heads and how many cylinders).
  • Write a "LBA to CHS conversion" routine (which depends on the geometry of the floppy disk)
I'd recommend having a "wrapper function" for this, where that wrapper:
  • does the "LBA to CHS conversion"
  • breaks larger reads/writes into smaller pieces at track boundaries (because some BIOSs have trouble reading/writing past track boundaries)
  • calls "int 0x13" for each smaller piece
  • handles the "retry N times if error" stuff, possibly including:
    • breaking multi-sector reads/writes into "one sector at a time" to increase the chance of success
    • resetting the device between (some) retries, not necessarily every time (e.g. maybe every 2nd time you retry)
Note that there are 2 ways to detect the geometry of the floppy disk. The first way is to use a clever test sequence, where each test is designed to split the possibilities until only one possibility remains. This can always work (for all floppy disks, including non-standard floppy disk formats); but requires a native floppy driver.

The second way is to rely on the existence of a correct "BPB" in the first sector. This fails when the density is wrong (e.g. "low density" 360 KiB floppy when you're expecting "high density") because you can't read the BPB in that case; and it fails when there isn't a correct BPB for any reason; and it fails for all cases where a BPB can't describe the floppy format (e.g. advanced formats that use 512-byte sectors for the first track, then larger sectors for remaining tracks to waste less space/increase capacity).

Also note that floppy disks are very slow and also relatively small; and this combination makes caching very effective. Don't forget that seeking can cost more than reading an entire track, so pre-fetching entire tracks or cylinders into your cache in the background (when floppy drive isn't busy and your heads are already on that track) can dramatically improve performance by avoiding "future seeks".

Unfortunately; while the hardware is designed for "read/write in background" (using DMA and IRQs) the BIOS is not; and while the hardware is designed to notify you when a disk is changed the BIOS is not. This means that for efficient pre-fetching; and for cache management (including discarding cached data when the floppy disk is removed/changed); and for detecting media properly; you need to write your own driver. Essentially; (even for a "real mode single-tasking OS") the BIOS is a worthless piece of trash that should not be used for anything other than the boot loader.


Cheers,

Brendan
Can i using IDE IO read/write anything? E.g without BIOS interrupts?

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 7:27 am
by BrightLight
monobogdan wrote:For read from offset 200 i need to calculate needed sector. But now i don't know how to do this(it's not hard, but now i have no idea).
Sector number = Offset / 512 (for 200 this would be on sector 0.)
Offset into sector = Offset % 512 (for 200 this would be 200.)
monobogdan wrote:Can i using IDE IO read/write anything? E.g without BIOS interrupts?
IDE is an interface for hard disks and CDs/DVDs, not floppy disks. You can program the Floppy Disk Controller, though.

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 8:11 am
by Ycep
If you want to read data from 432th byte, for example, up to 921th, and storage you use has 512 byte-blocks, then you need to read both sectors, the one between 1st and 512th byte, and one between 513th and 1024th byte.
To get first sector from which you need to read, you need to divide starting byte you want to read from with block size.
To get offset of such sector, you need to get remainder of this equation above.
Iff you finished 2nd grade you should know equation for getting last sector including equation of two rows above
To get offset of ending sector, you need to get remainder of equation of finding last sector.

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 1:39 pm
by BenLunt
Might I make a suggestion. You need to be writing your OS with layers. Here is a (minimal) example, kernel only, no user-space.

Direct media access:
1. kernel app: read bytes 200d to 399d. Call media driver (DOS uses a DPB)
2. media driver: convert byte offset and length to media specs
3. media hardware driver: read all sectors needed, returning to media driver.
2. media driver: extract bytes needed
1. kernel app: buffer now filled with bytes 200d to 399d

Media access via file system:
1. kernel app: read bytes 200d to 399d. call media driver
2. media driver: open media for read access
3. file system: find file on media
4. file system: open file on filesystem
5. media hardware driver: read all sectors needed, returning to media driver.
4. media driver: extract bytes needed
3. file system: close file on filesystem
2. file system: return buffer filled
1. kernel app: buffer now filled with bytes 200d to 399d

This is a complete generic layer system, but you get the idea. if you place it in layers, your kernel app, and later your user-space app, will not care one bit what kind of media you are trying to read from. All it does is call the media driver. The media driver takes care of the rest. However, the media driver has no care what kind of file system is used. The file system takes care of the rest. etc. etc.

In your kernel, when you find a media device (hard drive), create a kernel structure for this media. This structure will describe the media, and has a driver pointer that the kernel may call. Then scan for partitions on the media. When found, there will be at least one, create a BPB (DOS calls it a BPB, BIOS Parameter Block) for this partition. This BPB will also have a file system driver pointer. Then detect the file system on the partition and place a valid file system driver pointer in that BPB.

KERNEL APP --> MEDIA STRUCTURE --> BPB --> FILE SYSTEM

The File system calls its parent (BPB) to do the reading (physical media access) which in turn calls its parent (MEDIA STRUCTURE) to extract the data which returns to the KERNEL APP.

Now you can have any type of media with any type of file system and the KERNEL APP couldn't care less what it was, knowing that it will either receive a valid buffer filled with valid data or an error code. Period.

All you have to do is write drivers for various media devices and file systems.

My kernel uses the following:
1. Every time a device is detected, a DEVICE_STRUCT is created. This structure has a general format for all devices with a pointer to specific device attributes. The DEVICE driver doesn't care about anything but the general format (about 100 bytes worth). Within this general format is a pointer to the specific device attributes and a driver for that specific device. The kernel then tries to determine what kind of device it is. If it is a PCI device, this is fairly simple.
2. The kernel then loads a driver for that device and lets the driver fill the remaining (specific device attributes) area with information. If the device is a media device, the driver then creates a BPB (again, a familiar term for the purpose of this post). The DEVICE_STRUCT->SPECIFIC_ATTRBS has a pointer to this BPB. The driver then tries to find out what type of file system is on the partition.
3. Once the driver finds a file system, it loads that file system driver (if not already loaded) and fills the BPB with more data including a pointer to this file system driver.

At this point, when the kernel needs to access the file system, a call to the DEVICE_STRUCT is made. The DEVICE_STRUCT then makes the call to the BPB which then makes the call to the file system. The kernel can make a call to any DEVICE using the exact same calling parameters, no matter the device type.

Again, this is a generic abstract of what you should really have, but I hope you get the idea.

Ben
http://www.fysnet.net/osdesign_book_series.htm

Re: Reading floppy by offset?

Posted: Thu Jan 26, 2017 4:21 pm
by monobogdan
Thanks for your replies, guys :P

May be anyone know GPLv3 or anything other license 16bit driver for FAT?

I'm want embed it in my GPLv3 OS