mirror of
https://github.com/limine-bootloader/limine
synced 2024-12-11 09:14:38 +03:00
disk: Move caching code to part.c from disk.c
This commit is contained in:
parent
0ec053710c
commit
3e4b4a6b9b
@ -2,6 +2,8 @@
|
||||
#define __DRIVERS__DISK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <lib/part.h>
|
||||
|
||||
struct bios_drive_params {
|
||||
@ -15,8 +17,7 @@ struct bios_drive_params {
|
||||
uint32_t edd;
|
||||
} __attribute__((packed));
|
||||
|
||||
int disk_get_sector_size(int drive);
|
||||
int disk_read(int drive, void *buffer, uint64_t loc, uint64_t count);
|
||||
size_t disk_create_index(struct volume **ret);
|
||||
bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count);
|
||||
|
||||
#endif
|
||||
|
@ -9,14 +9,6 @@
|
||||
#include <lib/print.h>
|
||||
#include <mm/pmm.h>
|
||||
|
||||
#define BLOCK_SIZE_IN_SECTORS 16
|
||||
#define BLOCK_SIZE (sector_size * BLOCK_SIZE_IN_SECTORS)
|
||||
|
||||
#define CACHE_INVALID (~((uint64_t)0))
|
||||
|
||||
static uint8_t *cache = NULL;
|
||||
static uint64_t cached_block = CACHE_INVALID;
|
||||
|
||||
struct dap {
|
||||
uint16_t size;
|
||||
uint16_t count;
|
||||
@ -27,26 +19,30 @@ struct dap {
|
||||
|
||||
static struct dap *dap = NULL;
|
||||
|
||||
static int cache_block(int drive, uint64_t block, int sector_size) {
|
||||
if (block == cached_block)
|
||||
return 0;
|
||||
#define XFER_BUF_SIZE 16384
|
||||
static void *xfer_buf = NULL;
|
||||
|
||||
if (!dap) {
|
||||
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 = BLOCK_SIZE_IN_SECTORS;
|
||||
}
|
||||
|
||||
if (!cache)
|
||||
cache = conv_mem_alloc_aligned(BLOCK_SIZE, 16);
|
||||
dap->count = count;
|
||||
|
||||
dap->segment = rm_seg(cache);
|
||||
dap->offset = rm_off(cache);
|
||||
dap->lba = block * BLOCK_SIZE_IN_SECTORS;
|
||||
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 = drive;
|
||||
r.edx = volume->drive;
|
||||
r.esi = (uint32_t)rm_off(dap);
|
||||
r.ds = rm_seg(dap);
|
||||
|
||||
@ -54,56 +50,12 @@ static int cache_block(int drive, uint64_t block, int sector_size) {
|
||||
|
||||
if (r.eflags & EFLAGS_CF) {
|
||||
int ah = (r.eax >> 8) & 0xff;
|
||||
panic("Disk error %x. Drive %x, LBA %x.", ah, drive, dap->lba);
|
||||
panic("Disk error %x. Drive %x, LBA %x.", ah, volume->drive, dap->lba);
|
||||
}
|
||||
|
||||
cached_block = block;
|
||||
memcpy(buf, xfer_buf, count * volume->sector_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_get_sector_size(int 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) {
|
||||
int ah = (r.eax >> 8) & 0xff;
|
||||
panic("Disk error %x. Drive %x.", ah, drive);
|
||||
}
|
||||
|
||||
return drive_params.bytes_per_sect;
|
||||
}
|
||||
|
||||
int disk_read(int drive, void *buffer, uint64_t loc, uint64_t count) {
|
||||
int sector_size = disk_get_sector_size(drive);
|
||||
|
||||
uint64_t progress = 0;
|
||||
while (progress < count) {
|
||||
uint64_t block = (loc + progress) / BLOCK_SIZE;
|
||||
|
||||
int ret;
|
||||
if ((ret = cache_block(drive, block, sector_size)))
|
||||
return ret;
|
||||
|
||||
uint64_t chunk = count - progress;
|
||||
uint64_t offset = (loc + progress) % BLOCK_SIZE;
|
||||
if (chunk > BLOCK_SIZE - offset)
|
||||
chunk = BLOCK_SIZE - offset;
|
||||
|
||||
memcpy(buffer + progress, &cache[offset], chunk);
|
||||
progress += chunk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t disk_create_index(struct volume **ret) {
|
||||
|
@ -84,7 +84,7 @@ void entry(uint8_t _boot_drive, int boot_from) {
|
||||
switch (boot_from) {
|
||||
case BOOT_FROM_HDD:
|
||||
case BOOT_FROM_CD: {
|
||||
struct volume boot_volume;
|
||||
struct volume boot_volume = {0};
|
||||
volume_get_by_coord(&boot_volume, boot_drive, -1);
|
||||
struct volume part = boot_volume;
|
||||
for (int i = 0; ; i++) {
|
||||
|
@ -46,7 +46,7 @@ void stage3_entry(int boot_from) {
|
||||
switch (boot_from) {
|
||||
case BOOT_FROM_HDD:
|
||||
case BOOT_FROM_CD: {
|
||||
struct volume boot_volume;
|
||||
struct volume boot_volume = {0};
|
||||
volume_get_by_coord(&boot_volume, boot_drive, -1);
|
||||
struct volume part = boot_volume;
|
||||
for (int i = 0; ; i++) {
|
||||
|
@ -22,7 +22,7 @@ struct echfs_identity_table {
|
||||
#define FILE_TYPE 0
|
||||
#define DIR_TYPE 1
|
||||
|
||||
static int read_block(struct echfs_file_handle *file, void *buf, uint64_t block, uint64_t offset, uint64_t count) {
|
||||
static bool read_block(struct echfs_file_handle *file, void *buf, uint64_t block, uint64_t offset, uint64_t count) {
|
||||
return volume_read(&file->part, buf, (file->alloc_map[block] * file->block_size) + offset, count);
|
||||
}
|
||||
|
||||
|
@ -98,11 +98,7 @@ static int fat32_read_cluster_from_map(struct fat32_context* context, uint32_t c
|
||||
const uint32_t offset = cluster % (FAT32_SECTOR_SIZE / 4);
|
||||
|
||||
uint32_t clusters[FAT32_SECTOR_SIZE / sizeof(uint32_t)];
|
||||
int r = volume_read(&context->part, &clusters[0], (context->fat_start_lba + sector) * FAT32_SECTOR_SIZE, sizeof(clusters));
|
||||
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
volume_read(&context->part, &clusters[0], (context->fat_start_lba + sector) * FAT32_SECTOR_SIZE, sizeof(clusters));
|
||||
|
||||
*out = clusters[offset] & 0x0FFFFFFF;
|
||||
return 0;
|
||||
@ -143,10 +139,7 @@ static bool read_cluster_chain(struct fat32_context *context,
|
||||
chunk = block_size - offset;
|
||||
|
||||
uint64_t base = (context->data_start_lba + (cluster_chain[block] - 2)) * block_size;
|
||||
int r = volume_read(&context->part, buf + progress, base + offset, chunk);
|
||||
|
||||
if (r)
|
||||
return false;
|
||||
volume_read(&context->part, buf + progress, base + offset, chunk);
|
||||
|
||||
progress += chunk;
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ struct volume {
|
||||
drive_t drive;
|
||||
int partition;
|
||||
int sector_size;
|
||||
int cache_status;
|
||||
uint8_t *cache;
|
||||
uint64_t cached_block;
|
||||
uint64_t first_sect;
|
||||
uint64_t sect_count;
|
||||
bool guid_valid;
|
||||
@ -38,6 +41,6 @@ int part_get(struct volume *part, struct volume *volume, int partition);
|
||||
bool volume_get_by_guid(struct volume *part, struct guid *guid);
|
||||
bool volume_get_by_coord(struct volume *part, drive_t drive, int partition);
|
||||
|
||||
int volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count);
|
||||
bool volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count);
|
||||
|
||||
#endif
|
||||
|
@ -11,14 +11,55 @@
|
||||
#include <mm/pmm.h>
|
||||
#include <fs/file.h>
|
||||
|
||||
size_t volume_get_sector_size(struct volume *volume) {
|
||||
#if defined (bios)
|
||||
return disk_get_sector_size(volume->drive);
|
||||
#elif defined (uefi)
|
||||
(void)volume;
|
||||
return -1;
|
||||
#endif
|
||||
#define BLOCK_SIZE_IN_SECTORS 8
|
||||
|
||||
enum {
|
||||
CACHE_NOT_READY = 0,
|
||||
CACHE_READY
|
||||
};
|
||||
|
||||
static bool cache_block(struct volume *volume, uint64_t block) {
|
||||
if (volume->cache_status == CACHE_READY && block == volume->cached_block)
|
||||
return true;
|
||||
|
||||
volume->cache_status = CACHE_NOT_READY;
|
||||
|
||||
if (volume->cache == NULL)
|
||||
volume->cache =
|
||||
ext_mem_alloc_aligned(BLOCK_SIZE_IN_SECTORS * volume->sector_size,
|
||||
4096);
|
||||
|
||||
if (!disk_read_sectors(volume, volume->cache,
|
||||
volume->first_sect + block * BLOCK_SIZE_IN_SECTORS,
|
||||
BLOCK_SIZE_IN_SECTORS))
|
||||
return false;
|
||||
|
||||
volume->cache_status = CACHE_READY;
|
||||
volume->cached_block = block;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool volume_read(struct volume *volume, void *buffer, uint64_t loc, uint64_t count) {
|
||||
uint64_t block_size = BLOCK_SIZE_IN_SECTORS * volume->sector_size;
|
||||
|
||||
uint64_t progress = 0;
|
||||
while (progress < count) {
|
||||
uint64_t block = (loc + progress) / block_size;
|
||||
|
||||
if (!cache_block(volume, block))
|
||||
return false;
|
||||
|
||||
uint64_t chunk = count - progress;
|
||||
uint64_t offset = (loc + progress) % block_size;
|
||||
if (chunk > block_size - offset)
|
||||
chunk = block_size - offset;
|
||||
|
||||
memcpy(buffer + progress, &volume->cache[offset], chunk);
|
||||
progress += chunk;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct gpt_table_header {
|
||||
@ -61,7 +102,7 @@ struct gpt_entry {
|
||||
bool gpt_get_guid(struct guid *guid, struct volume *volume) {
|
||||
struct gpt_table_header header = {0};
|
||||
|
||||
int sector_size = volume_get_sector_size(volume);
|
||||
int sector_size = volume->sector_size;
|
||||
|
||||
// read header, located after the first block
|
||||
volume_read(volume, &header, sector_size * 1, sizeof(header));
|
||||
@ -81,7 +122,7 @@ bool gpt_get_guid(struct guid *guid, struct volume *volume) {
|
||||
static int gpt_get_part(struct volume *ret, struct volume *volume, int partition) {
|
||||
struct gpt_table_header header = {0};
|
||||
|
||||
int sector_size = volume_get_sector_size(volume);
|
||||
int sector_size = volume->sector_size;
|
||||
|
||||
// read header, located after the first block
|
||||
volume_read(volume, &header, sector_size * 1, sizeof(header));
|
||||
@ -144,10 +185,7 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
|
||||
for (int i = 0; i < partition; i++) {
|
||||
size_t entry_offset = ebr_sector * extended_part->sector_size + 0x1ce;
|
||||
|
||||
int r;
|
||||
r = volume_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
if (r)
|
||||
return r;
|
||||
volume_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
|
||||
if (entry.type != 0x0f && entry.type != 0x05)
|
||||
return END_OF_TABLE;
|
||||
@ -157,17 +195,14 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
|
||||
|
||||
size_t entry_offset = ebr_sector * extended_part->sector_size + 0x1be;
|
||||
|
||||
int r;
|
||||
r = volume_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
if (r)
|
||||
return r;
|
||||
volume_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
|
||||
if (entry.type == 0)
|
||||
return NO_PARTITION;
|
||||
|
||||
ret->drive = extended_part->drive;
|
||||
ret->partition = partition + 4;
|
||||
ret->sector_size = volume_get_sector_size(extended_part);
|
||||
ret->sector_size = extended_part->sector_size;
|
||||
ret->first_sect = extended_part->first_sect + ebr_sector + entry.first_sect;
|
||||
ret->sect_count = entry.sect_count;
|
||||
|
||||
@ -197,18 +232,16 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
|
||||
for (int i = 0; i < 4; i++) {
|
||||
size_t entry_offset = 0x1be + sizeof(struct mbr_entry) * i;
|
||||
|
||||
int r = volume_read(volume, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
if (r)
|
||||
return r;
|
||||
volume_read(volume, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
|
||||
if (entry.type != 0x0f)
|
||||
continue;
|
||||
|
||||
struct volume extended_part;
|
||||
struct volume extended_part = {0};
|
||||
|
||||
extended_part.drive = volume->drive;
|
||||
extended_part.partition = i;
|
||||
extended_part.sector_size = volume_get_sector_size(volume);
|
||||
extended_part.sector_size = volume->sector_size;
|
||||
extended_part.first_sect = entry.first_sect;
|
||||
extended_part.sect_count = entry.sect_count;
|
||||
|
||||
@ -220,16 +253,14 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
|
||||
|
||||
size_t entry_offset = 0x1be + sizeof(struct mbr_entry) * partition;
|
||||
|
||||
int r = volume_read(volume, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
if (r)
|
||||
return r;
|
||||
volume_read(volume, &entry, entry_offset, sizeof(struct mbr_entry));
|
||||
|
||||
if (entry.type == 0)
|
||||
return NO_PARTITION;
|
||||
|
||||
ret->drive = volume->drive;
|
||||
ret->partition = partition;
|
||||
ret->sector_size = volume_get_sector_size(volume);
|
||||
ret->sector_size = volume->sector_size;
|
||||
ret->first_sect = entry.first_sect;
|
||||
ret->sect_count = entry.sect_count;
|
||||
|
||||
@ -302,13 +333,3 @@ found:
|
||||
*part = volume_index[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
int volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count) {
|
||||
#if defined (bios)
|
||||
return disk_read(part->drive, buffer,
|
||||
loc + (part->first_sect * part->sector_size), count);
|
||||
#elif defined (uefi)
|
||||
(void)part; (void)buffer; (void)loc; (void)count;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ static bool parse_bios_partition(char *loc, uint8_t *drive, uint8_t *partition)
|
||||
static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
|
||||
uint8_t drive, partition;
|
||||
|
||||
struct volume volume;
|
||||
struct volume volume = {0};
|
||||
if (!parse_bios_partition(loc, &drive, &partition))
|
||||
return false;
|
||||
|
||||
@ -114,7 +114,7 @@ static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path
|
||||
if (!string_to_guid_be(&guid, guid_str))
|
||||
return false;
|
||||
|
||||
struct volume part;
|
||||
struct volume part = {0};
|
||||
if (!volume_get_by_guid(&part, &guid)) {
|
||||
if (!string_to_guid_mixed(&guid, guid_str))
|
||||
return false;
|
||||
@ -174,7 +174,7 @@ static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path)
|
||||
panic("Boot partition information is unavailable.");
|
||||
}
|
||||
|
||||
struct volume part;
|
||||
struct volume part = {0};
|
||||
if (!volume_get_by_coord(&part, boot_drive, partition))
|
||||
return false;
|
||||
|
||||
|
@ -77,7 +77,7 @@ void chainload(char *config) {
|
||||
|
||||
term_deinit();
|
||||
|
||||
struct volume p;
|
||||
struct volume p = {0};
|
||||
volume_get_by_coord(&p, drive, part);
|
||||
|
||||
volume_read(&p, (void *)0x7c00, 0, 512);
|
||||
|
Loading…
Reference in New Issue
Block a user