109 lines
3.2 KiB
C
109 lines
3.2 KiB
C
//
|
|
// Created by rick on 06-02-21.
|
|
//
|
|
|
|
#include <fs/mbr.h>
|
|
#include <types.h>
|
|
#include <drivers/ide.h>
|
|
#include <libc/kprintf.h>
|
|
#include <fs/blockdev.h>
|
|
#include <libc/libc.h>
|
|
#include <mem/malloc.h>
|
|
#include <attributes.h>
|
|
|
|
typedef struct {
|
|
uint8_t bootable;
|
|
uint8_t starting_head;
|
|
uint8_t starting_sector: 6;
|
|
uint16_t starting_cylinder: 10;
|
|
uint8_t system_id;
|
|
uint8_t ending_head;
|
|
uint8_t ending_sector: 6;
|
|
uint16_t ending_cylinder: 10;
|
|
uint32_t start_lba;
|
|
uint32_t num_lbas;
|
|
} packed mbr_partition_table_entry;
|
|
|
|
typedef struct {
|
|
uint32_t unique_id;
|
|
uint16_t reserved;
|
|
mbr_partition_table_entry entries[4];
|
|
uint8_t signature[2];
|
|
} packed mbr_table;
|
|
|
|
typedef struct {
|
|
const block_device *device;
|
|
uint32_t start_lba;
|
|
} mbr_block_driver_info;
|
|
|
|
uint8_t mbr_block_dev_access(const block_device *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
|
if (!device->flags.present || lba > device->num_lba) {
|
|
return BLOCK_DEV_ACCESS_ERR;
|
|
}
|
|
const mbr_block_driver_info *info = device->device_info;
|
|
const uint32_t actual_lba = info->start_lba + lba;
|
|
if (actual_lba > info->device->num_lba) {
|
|
return BLOCK_DEV_ACCESS_ERR;
|
|
}
|
|
|
|
// delegate to backing driver
|
|
return info->device->access(info->device, direction, actual_lba, sectors, target);
|
|
}
|
|
|
|
uint8_t used mbr_check_device(const block_device *device, uint8_t *first_sector) {
|
|
mbr_table table;
|
|
memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table));
|
|
if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian
|
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
|
}
|
|
|
|
if (table.reserved != 0x0000 && table.reserved != 0x5A5A) {
|
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
if (table.entries[i].num_lbas > device->num_lba || table.entries[i].start_lba > device->num_lba) {
|
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
if (table.entries[i].system_id == 0) continue;
|
|
|
|
mbr_block_driver_info *info = malloc(sizeof(mbr_block_driver_info));
|
|
info->device = device;
|
|
info->start_lba = table.entries[i].start_lba;
|
|
|
|
block_device logical_device = {
|
|
.flags.present = 1,
|
|
|
|
.num_lba = table.entries[i].num_lbas,
|
|
.block_size = device->block_size,
|
|
.access = mbr_block_dev_access,
|
|
.device_info = info,
|
|
};
|
|
|
|
sprintf(logical_device.identifier, "%sp%d", device->identifier, i);
|
|
|
|
block_dev_register(&logical_device);
|
|
|
|
}
|
|
|
|
return BLOCK_DEV_DRIVER_CHECK_OK;
|
|
}
|
|
|
|
void mbr_read_from_ide(uint8_t ide_drive) {
|
|
char *mbr_data = malloc(0x200);
|
|
ide_access(0, ide_drive, 0, 1, mbr_data);
|
|
mbr_partition_table_entry *entry = (mbr_partition_table_entry *) (mbr_data + 0x1BE);
|
|
printf("Start at %d, count: %d\n", entry->start_lba, entry->num_lbas);
|
|
free(mbr_data);
|
|
}
|
|
|
|
BLOCK_DEV_DRIVER(200) = {
|
|
.name = "mbr",
|
|
.flags.root_only = 1,
|
|
.check_device = mbr_check_device,
|
|
.free_device = NULL, // todo
|
|
};
|