rulimine/stage23/drivers/disk.s2.c

175 lines
4.3 KiB
C
Raw Normal View History

2021-03-02 12:23:43 +03:00
#if defined(bios)
#include <stdint.h>
#include <stddef.h>
2019-06-02 00:48:33 +03:00
#include <drivers/disk.h>
2020-11-02 12:17:20 +03:00
#include <lib/libc.h>
#include <lib/real.h>
2020-01-22 07:02:12 +03:00
#include <lib/blib.h>
2020-05-10 01:38:27 +03:00
#include <lib/print.h>
2020-09-20 13:03:44 +03:00
#include <mm/pmm.h>
struct dap {
2019-06-02 00:48:33 +03:00
uint16_t size;
uint16_t count;
uint16_t offset;
uint16_t segment;
uint64_t lba;
};
static struct dap *dap = NULL;
#define XFER_BUF_SIZE 16384
static void *xfer_buf = NULL;
bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count) {
if (count * volume->sector_size > XFER_BUF_SIZE)
panic("XFER");
if (xfer_buf == NULL)
xfer_buf = conv_mem_alloc_aligned(XFER_BUF_SIZE, 16);
if (dap == NULL) {
dap = conv_mem_alloc(sizeof(struct dap));
dap->size = 16;
}
dap->count = count;
2020-03-28 06:02:26 +03:00
dap->segment = rm_seg(xfer_buf);
dap->offset = rm_off(xfer_buf);
dap->lba = block;
struct rm_regs r = {0};
r.eax = 0x4200;
r.edx = volume->drive;
r.esi = (uint32_t)rm_off(dap);
r.ds = rm_seg(dap);
rm_int(0x13, &r, &r);
if (r.eflags & EFLAGS_CF) {
int ah = (r.eax >> 8) & 0xff;
switch (ah) {
case 0x0c:
return false;
default:
panic("Disk error %x. Drive %x, LBA %x.",
ah, volume->drive, dap->lba);
}
}
if (buf != NULL)
memcpy(buf, xfer_buf, count * volume->sector_size);
return true;
}
2021-03-02 12:23:43 +03:00
size_t disk_create_index(struct volume **ret) {
struct volume *volume_index;
size_t volume_count = 0, volume_index_i = 0;
for (uint8_t drive = 0x80; drive; drive++) {
struct rm_regs r = {0};
struct bios_drive_params drive_params;
r.eax = 0x4800;
r.edx = drive;
r.ds = rm_seg(&drive_params);
r.esi = rm_off(&drive_params);
drive_params.buf_size = sizeof(struct bios_drive_params);
rm_int(0x13, &r, &r);
if (r.eflags & EFLAGS_CF)
continue;
print("Found BIOS drive %x\n", drive);
print(" ... %X total %u-byte sectors\n",
drive_params.lba_count, drive_params.bytes_per_sect);
volume_count++;
struct volume block;
block.drive = drive;
block.sector_size = drive_params.bytes_per_sect;
block.first_sect = 0;
block.sect_count = drive_params.lba_count;
// The medium could not be present (e.g.: CD-ROMs)
// Do a test run to see if we can actually read it
if (!disk_read_sectors(&block, NULL, 0, 1)) {
print(" ... Ignoring drive...\n");
continue;
}
2021-03-02 12:23:43 +03:00
for (int part = 0; ; part++) {
struct volume p;
int ret = part_get(&p, &block, part);
if (ret == END_OF_TABLE || ret == INVALID_TABLE)
break;
if (ret == NO_PARTITION)
continue;
volume_count++;
}
}
volume_index = ext_mem_alloc(sizeof(struct volume) * volume_count);
for (uint8_t drive = 0x80; drive; drive++) {
struct rm_regs r = {0};
struct bios_drive_params drive_params;
r.eax = 0x4800;
r.edx = drive;
r.ds = rm_seg(&drive_params);
r.esi = rm_off(&drive_params);
drive_params.buf_size = sizeof(struct bios_drive_params);
rm_int(0x13, &r, &r);
if (r.eflags & EFLAGS_CF)
continue;
struct volume *block = &volume_index[volume_index_i++];
block->drive = drive;
block->partition = -1;
block->sector_size = drive_params.bytes_per_sect;
block->first_sect = 0;
block->sect_count = drive_params.lba_count;
// The medium could not be present (e.g.: CD-ROMs)
// Do a test run to see if we can actually read it
if (!disk_read_sectors(block, NULL, 0, 1)) {
continue;
}
2021-03-02 12:23:43 +03:00
if (gpt_get_guid(&block->guid, block)) {
block->guid_valid = true;
}
for (int part = 0; ; part++) {
struct volume p;
int ret = part_get(&p, block, part);
if (ret == END_OF_TABLE || ret == INVALID_TABLE)
break;
if (ret == NO_PARTITION)
continue;
volume_index[volume_index_i++] = p;
}
}
*ret = volume_index;
return volume_count;
}
#endif