disk: Add logic to determine fastest transfer size

This commit is contained in:
mintsuki 2021-08-22 16:27:06 +02:00
parent dadca8fe17
commit 049601814a
4 changed files with 75 additions and 7 deletions

View File

@ -8,7 +8,9 @@
# include <efi.h>
#endif
#include <lib/blib.h>
#include <lib/print.h>
#include <mm/pmm.h>
#include <sys/cpu.h>
#if bios == 1
@ -33,9 +35,56 @@ struct dap {
static struct dap dap = {0};
#define XFER_BUF_SIZE 16384
#define XFER_BUF_SIZE 65536
static void *xfer_buf = NULL;
static size_t fastest_xfer_size(struct volume *volume) {
if (xfer_buf == NULL)
xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
size_t fastest_size = 1;
uint64_t last_speed = (uint64_t)-1;
static const size_t xfer_sizes[] = { 1, 2, 4, 8, 16, 24, 32, 48, 64, 128 };
for (size_t i = 0; i < SIZEOF_ARRAY(xfer_sizes); i++) {
if (xfer_sizes[i] * volume->sector_size > XFER_BUF_SIZE) {
break;
}
dap.size = 16;
dap.count = xfer_sizes[i];
dap.segment = rm_seg(xfer_buf);
dap.offset = rm_off(xfer_buf);
dap.lba = 0;
struct rm_regs r = {0};
r.eax = 0x4200;
r.edx = volume->drive;
r.esi = (uint32_t)rm_off(&dap);
r.ds = rm_seg(&dap);
uint64_t start_timestamp = rdtsc();
rm_int(0x13, &r, &r);
uint64_t end_timestamp = rdtsc();
if (r.eflags & EFLAGS_CF) {
int ah = (r.eax >> 8) & 0xff;
printv("Disk error %x. Drive %x", ah, volume->drive);
continue;
}
uint64_t speed = (end_timestamp - start_timestamp) / xfer_sizes[i];
if (speed < last_speed) {
last_speed = speed;
fastest_size = xfer_sizes[i];
}
}
return fastest_size;
}
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");
@ -111,6 +160,8 @@ void disk_create_index(void) {
}
}
block.fastest_xfer_size = 8;
volume_count++;
for (int part = 0; ; part++) {
@ -170,6 +221,8 @@ void disk_create_index(void) {
block->index = hdd_indices++;
}
block->fastest_xfer_size = fastest_xfer_size(block);
if (gpt_get_guid(&block->guid, block)) {
block->guid_valid = true;
}
@ -321,6 +374,8 @@ void disk_create_index(void) {
block.first_sect = 0;
block.sect_count = block_io->Media->LastBlock + 1;
block.fastest_xfer_size = 8;
for (int part = 0; ; part++) {
struct volume trash = {0};
int ret = part_get(&trash, &block, part);
@ -382,6 +437,9 @@ void disk_create_index(void) {
block->guid_valid = true;
}
// TODO: get fastest xfer size also for UEFI?
block->fastest_xfer_size = 8;
volume_index[volume_index_i++] = block;
for (int part = 0; ; part++) {

View File

@ -20,6 +20,8 @@ struct volume {
int drive;
#endif
size_t fastest_xfer_size;
int index;
bool is_optical;

View File

@ -11,8 +11,6 @@
#include <mm/pmm.h>
#include <fs/file.h>
#define BLOCK_SIZE_IN_SECTORS 8
enum {
CACHE_NOT_READY = 0,
CACHE_READY
@ -26,11 +24,11 @@ static bool cache_block(struct volume *volume, uint64_t block) {
if (volume->cache == NULL)
volume->cache =
ext_mem_alloc(BLOCK_SIZE_IN_SECTORS * volume->sector_size);
ext_mem_alloc(volume->fastest_xfer_size * volume->sector_size);
if (!disk_read_sectors(volume, volume->cache,
volume->first_sect + block * BLOCK_SIZE_IN_SECTORS,
BLOCK_SIZE_IN_SECTORS))
volume->first_sect + block * volume->fastest_xfer_size,
volume->fastest_xfer_size))
return false;
volume->cache_status = CACHE_READY;
@ -44,7 +42,7 @@ bool volume_read(struct volume *volume, void *buffer, uint64_t loc, uint64_t cou
panic("Attempted volume_read() on pxe");
}
uint64_t block_size = BLOCK_SIZE_IN_SECTORS * volume->sector_size;
uint64_t block_size = volume->fastest_xfer_size * volume->sector_size;
uint64_t progress = 0;
while (progress < count) {
@ -154,6 +152,7 @@ static int gpt_get_part(struct volume *ret, struct volume *volume, int partition
ret->efi_handle = volume->efi_handle;
#elif bios == 1
ret->drive = volume->drive;
ret->fastest_xfer_size = volume->fastest_xfer_size;
#endif
ret->index = volume->index;
ret->is_optical = volume->is_optical;
@ -214,6 +213,7 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
ret->efi_handle = extended_part->efi_handle;
#elif bios == 1
ret->drive = extended_part->drive;
ret->fastest_xfer_size = extended_part->fastest_xfer_size;
#endif
ret->index = extended_part->index;
ret->is_optical = extended_part->is_optical;
@ -292,6 +292,7 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
extended_part.efi_handle = volume->efi_handle;
#elif bios == 1
extended_part.drive = volume->drive;
extended_part.fastest_xfer_size = volume->fastest_xfer_size;
#endif
extended_part.index = volume->index;
extended_part.is_optical = volume->is_optical;
@ -318,6 +319,7 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
ret->efi_handle = volume->efi_handle;
#elif bios == 1
ret->drive = volume->drive;
ret->fastest_xfer_size = volume->fastest_xfer_size;
#endif
ret->index = volume->index;
ret->is_optical = volume->is_optical;

View File

@ -154,6 +154,12 @@ static inline void wrmsr(uint32_t msr, uint64_t value) {
: "memory");
}
inline uint64_t rdtsc(void) {
uint32_t edx, eax;
asm volatile ("rdtsc" : "=a" (eax), "=d" (edx));
return ((uint64_t)edx << 32) | eax;
}
#define write_cr(reg, val) ({ \
asm volatile ("mov %0, %%cr" reg :: "r" (val) : "memory"); \
})