Files
my-kern/kernel/fs/mbr.c

109 lines
3.1 KiB
C

//
// Created by rick on 06-02-21.
//
#include "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(
.name = "mbr",
.flags.root_only = 1,
.check_device = mbr_check_device,
.free_device = NULL, // todo
);