2019-06-02 00:34:24 +03:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <lib/libc.h>
|
2019-06-02 00:48:33 +03:00
|
|
|
#include <drivers/disk.h>
|
2019-06-02 00:34:24 +03:00
|
|
|
#include <lib/real.h>
|
2020-01-22 07:02:12 +03:00
|
|
|
#include <lib/blib.h>
|
2020-04-15 14:21:44 +03:00
|
|
|
#include <lib/part.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>
|
2019-06-02 00:34:24 +03:00
|
|
|
|
2020-01-23 03:48:35 +03:00
|
|
|
#define BLOCK_SIZE_IN_SECTORS 16
|
2020-10-18 07:35:20 +03:00
|
|
|
#define BLOCK_SIZE (sector_size * BLOCK_SIZE_IN_SECTORS)
|
2019-06-02 00:34:24 +03:00
|
|
|
|
2020-01-23 03:48:35 +03:00
|
|
|
#define CACHE_INVALID (~((uint64_t)0))
|
|
|
|
|
2020-03-28 06:02:26 +03:00
|
|
|
static uint8_t *cache = NULL;
|
2020-01-23 03:48:35 +03:00
|
|
|
static uint64_t cached_block = CACHE_INVALID;
|
2019-06-02 00:34:24 +03:00
|
|
|
|
2020-09-25 23:36:26 +03:00
|
|
|
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;
|
2020-09-25 23:36:26 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct dap *dap = NULL;
|
2019-06-02 00:34:24 +03:00
|
|
|
|
2020-10-18 07:35:20 +03:00
|
|
|
static int cache_block(int drive, uint64_t block, int sector_size) {
|
2020-01-23 03:48:35 +03:00
|
|
|
if (block == cached_block)
|
2019-06-03 01:14:32 +03:00
|
|
|
return 0;
|
|
|
|
|
2020-09-25 23:36:26 +03:00
|
|
|
if (!dap) {
|
|
|
|
dap = conv_mem_alloc(sizeof(struct dap));
|
|
|
|
dap->size = 16;
|
|
|
|
dap->count = BLOCK_SIZE_IN_SECTORS;
|
|
|
|
}
|
|
|
|
|
2020-03-28 06:02:26 +03:00
|
|
|
if (!cache)
|
2020-09-20 13:03:44 +03:00
|
|
|
cache = conv_mem_alloc_aligned(BLOCK_SIZE, 16);
|
2020-03-28 06:02:26 +03:00
|
|
|
|
2020-09-25 23:36:26 +03:00
|
|
|
dap->segment = rm_seg(cache);
|
|
|
|
dap->offset = rm_off(cache);
|
|
|
|
dap->lba = block * BLOCK_SIZE_IN_SECTORS;
|
2019-06-03 01:14:32 +03:00
|
|
|
|
|
|
|
struct rm_regs r = {0};
|
|
|
|
r.eax = 0x4200;
|
|
|
|
r.edx = drive;
|
2020-09-25 23:36:26 +03:00
|
|
|
r.esi = (uint32_t)rm_off(dap);
|
|
|
|
r.ds = rm_seg(dap);
|
2019-06-03 01:14:32 +03:00
|
|
|
|
|
|
|
rm_int(0x13, &r, &r);
|
|
|
|
|
|
|
|
if (r.eflags & EFLAGS_CF) {
|
|
|
|
int ah = (r.eax >> 8) & 0xff;
|
2020-09-25 23:36:26 +03:00
|
|
|
panic("Disk error %x. Drive %x, LBA %x.\n", ah, drive, dap->lba);
|
2019-06-03 01:14:32 +03:00
|
|
|
}
|
|
|
|
|
2020-01-23 03:48:35 +03:00
|
|
|
cached_block = block;
|
2019-06-02 00:34:24 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-06-02 12:17:49 +03:00
|
|
|
|
2019-06-03 01:14:32 +03:00
|
|
|
int read(int drive, void *buffer, uint64_t loc, uint64_t count) {
|
2020-10-18 07:35:20 +03:00
|
|
|
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) {
|
|
|
|
int ah = (r.eax >> 8) & 0xff;
|
|
|
|
panic("Disk error %x. Drive %x.\n", ah, drive);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sector_size = drive_params.bytes_per_sect;
|
|
|
|
|
2019-06-03 01:14:32 +03:00
|
|
|
uint64_t progress = 0;
|
|
|
|
while (progress < count) {
|
2020-01-23 03:48:35 +03:00
|
|
|
uint64_t block = (loc + progress) / BLOCK_SIZE;
|
2019-06-03 01:14:32 +03:00
|
|
|
|
|
|
|
int ret;
|
2020-10-18 07:35:20 +03:00
|
|
|
if ((ret = cache_block(drive, block, sector_size)))
|
2019-06-03 01:14:32 +03:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
uint64_t chunk = count - progress;
|
2020-01-23 03:48:35 +03:00
|
|
|
uint64_t offset = (loc + progress) % BLOCK_SIZE;
|
|
|
|
if (chunk > BLOCK_SIZE - offset)
|
|
|
|
chunk = BLOCK_SIZE - offset;
|
2019-06-03 01:14:32 +03:00
|
|
|
|
2020-03-28 06:02:26 +03:00
|
|
|
memcpy(buffer + progress, &cache[offset], chunk);
|
2019-06-03 01:14:32 +03:00
|
|
|
progress += chunk;
|
2019-06-02 12:17:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-01-22 03:55:40 +03:00
|
|
|
|
2020-04-15 14:21:44 +03:00
|
|
|
int read_partition(int drive, struct part *part, void *buffer, uint64_t loc, uint64_t count) {
|
2020-01-23 03:48:35 +03:00
|
|
|
return read(drive, buffer, loc + (part->first_sect * 512), count);
|
2020-01-22 03:55:40 +03:00
|
|
|
}
|