From 049601814a4074012f0afd5956e73246fa2fff2e Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sun, 22 Aug 2021 16:27:06 +0200 Subject: [PATCH] disk: Add logic to determine fastest transfer size --- stage23/drivers/disk.s2.c | 60 ++++++++++++++++++++++++++++++++++++++- stage23/lib/part.h | 2 ++ stage23/lib/part.s2.c | 14 +++++---- stage23/sys/cpu.h | 6 ++++ 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/stage23/drivers/disk.s2.c b/stage23/drivers/disk.s2.c index 523fe86a..29407211 100644 --- a/stage23/drivers/disk.s2.c +++ b/stage23/drivers/disk.s2.c @@ -8,7 +8,9 @@ # include #endif #include +#include #include +#include #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++) { diff --git a/stage23/lib/part.h b/stage23/lib/part.h index 5fbf03d9..72fa2b18 100644 --- a/stage23/lib/part.h +++ b/stage23/lib/part.h @@ -20,6 +20,8 @@ struct volume { int drive; #endif + size_t fastest_xfer_size; + int index; bool is_optical; diff --git a/stage23/lib/part.s2.c b/stage23/lib/part.s2.c index 8b53a74e..23e346cf 100644 --- a/stage23/lib/part.s2.c +++ b/stage23/lib/part.s2.c @@ -11,8 +11,6 @@ #include #include -#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; diff --git a/stage23/sys/cpu.h b/stage23/sys/cpu.h index 6e6efba3..b913ecc1 100644 --- a/stage23/sys/cpu.h +++ b/stage23/sys/cpu.h @@ -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"); \ })