disk: Add logic to determine fastest transfer size
This commit is contained in:
parent
dadca8fe17
commit
049601814a
|
@ -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++) {
|
||||
|
|
|
@ -20,6 +20,8 @@ struct volume {
|
|||
int drive;
|
||||
#endif
|
||||
|
||||
size_t fastest_xfer_size;
|
||||
|
||||
int index;
|
||||
|
||||
bool is_optical;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"); \
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue