AHCI write support
This commit is contained in:
@@ -222,8 +222,8 @@ struct ahci_command_table_entry {
|
||||
|
||||
uint32_t ahci_irq(void *ctx);
|
||||
|
||||
// TODO: accept block device instead of port registers
|
||||
void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect, uint64_t lba);
|
||||
void ahci_sata_write(struct ahci_port_registers *port, const void *buf, uint32_t nsect, uint64_t lba);
|
||||
|
||||
void ahci_port_start(struct ahci_port_registers *port);
|
||||
void ahci_port_stop(struct ahci_port_registers *port);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define ATA_CMD_READ_PIO_EX 0x24
|
||||
#define ATA_CMD_READ_DMA 0xC8
|
||||
#define ATA_CMD_READ_DMA_EX 0x25
|
||||
#define ATA_CMD_WRITE_DMA_EX 0x35
|
||||
|
||||
#define ATA_SR_BUSY (1 << 7)
|
||||
#define ATA_SR_DRQ (1 << 3)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
menuentry "yggdrasil" {
|
||||
multiboot /boot/loader
|
||||
module /boot/kernel kernel
|
||||
module /boot/initrd.img initrd
|
||||
}
|
||||
+27
-4
@@ -48,6 +48,19 @@ static ssize_t ahci_blk_read(struct blkdev *blk, void *buf, size_t off, size_t c
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ahci_blk_write(struct blkdev *blk, const void *buf, size_t off, size_t count) {
|
||||
_assert(blk && blk->dev_data);
|
||||
_assert(!(off & 511));
|
||||
_assert(!(count & 511));
|
||||
|
||||
size_t nsect = count / 512;
|
||||
size_t lba = off / 512;
|
||||
|
||||
ahci_sata_write((struct ahci_port_registers *) blk->dev_data, buf, nsect, lba);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int ahci_add_port_dev(struct ahci_port_registers *port) {
|
||||
void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
@@ -56,6 +69,7 @@ static int ahci_add_port_dev(struct ahci_port_registers *port) {
|
||||
|
||||
blk->dev_data = port;
|
||||
blk->read = ahci_blk_read;
|
||||
blk->write = ahci_blk_write;
|
||||
|
||||
ent->dev = blk;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
@@ -84,7 +98,8 @@ uint32_t ahci_irq(void *ctx) {
|
||||
return IRQ_UNHANDLED;
|
||||
}
|
||||
|
||||
void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect, uint64_t lba) {
|
||||
static void ahci_sata_access(struct ahci_port_registers *port, void *buf, uint32_t nsect, uint64_t lba, uint8_t dir) {
|
||||
kdebug("%s access to AHCI drive\n", dir ? "Write" : "Read");
|
||||
port->p_is = -1;
|
||||
|
||||
int cmd = ahci_alloc_cmd(port);
|
||||
@@ -101,7 +116,7 @@ void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect,
|
||||
size_t prd_count = (byte_count + 8191) / 8192;
|
||||
|
||||
if (prd_count > 8) {
|
||||
panic("Read operation uses too many PRDT entries\n");
|
||||
panic("Too many PRDT entries\n");
|
||||
}
|
||||
|
||||
size_t bytes_left = byte_count;
|
||||
@@ -135,11 +150,11 @@ void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect,
|
||||
|
||||
_assert(!bytes_left);
|
||||
|
||||
// Prepare read command
|
||||
// Prepare command
|
||||
struct ahci_fis_reg_h2d *fis_reg_h2d = &cmd_table->fis_reg_h2d;
|
||||
memset(fis_reg_h2d, 0, sizeof(struct ahci_fis_reg_h2d));
|
||||
fis_reg_h2d->type = FIS_REG_H2D;
|
||||
fis_reg_h2d->cmd = ATA_CMD_READ_DMA_EX;
|
||||
fis_reg_h2d->cmd = dir ? ATA_CMD_WRITE_DMA_EX : ATA_CMD_READ_DMA_EX;
|
||||
fis_reg_h2d->cmd_port = 1 << 7;
|
||||
fis_reg_h2d->lba0 = lba & 0xFF;
|
||||
fis_reg_h2d->lba1 = (lba >> 8) & 0xFF;
|
||||
@@ -178,6 +193,14 @@ void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect,
|
||||
}
|
||||
}
|
||||
|
||||
void ahci_sata_read(struct ahci_port_registers *port, void *buf, uint32_t nsect, uint64_t lba) {
|
||||
ahci_sata_access(port, buf, nsect, lba, 0);
|
||||
}
|
||||
|
||||
void ahci_sata_write(struct ahci_port_registers *port, const void *buf, uint32_t nsect, uint64_t lba) {
|
||||
ahci_sata_access(port, (void *) buf, nsect, lba, 1);
|
||||
}
|
||||
|
||||
static void ahci_sata_port_identify(struct ahci_port_registers *port) {
|
||||
port->p_is = -1;
|
||||
|
||||
|
||||
@@ -89,6 +89,20 @@ int blk_mount_auto(struct vfs_node *at, struct blkdev *blk, const char *opt) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t blk_part_write(struct blkdev *dev, const void *buf, size_t off, size_t count) {
|
||||
struct blk_part *part = (struct blk_part *) dev->dev_data;
|
||||
size_t part_size_bytes = part->lba_size * 512;
|
||||
size_t part_off_bytes = part->lba_start * 512;
|
||||
|
||||
if (off >= part_size_bytes) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t l = MIN(part_size_bytes - off, count);
|
||||
|
||||
return blk_write(part->device, buf, off + part_off_bytes, l);
|
||||
}
|
||||
|
||||
static ssize_t blk_part_read(struct blkdev *dev, void *buf, size_t off, size_t count) {
|
||||
struct blk_part *part = (struct blk_part *) dev->dev_data;
|
||||
size_t part_size_bytes = part->lba_size * 512;
|
||||
@@ -129,6 +143,7 @@ static int blk_enumerate_mbr(struct blkdev *dev, uint8_t *head) {
|
||||
|
||||
blk->dev_data = part;
|
||||
blk->read = blk_part_read;
|
||||
blk->write = blk_part_write;
|
||||
blk->ent_parent = dev->ent;
|
||||
|
||||
ent->dev = blk;
|
||||
@@ -174,6 +189,7 @@ static int blk_enumerate_gpt(struct blkdev *dev, uint8_t *head) {
|
||||
|
||||
blk->dev_data = part;
|
||||
blk->read = blk_part_read;
|
||||
blk->write = blk_part_write;
|
||||
blk->ent_parent = dev->ent;
|
||||
|
||||
ent->dev = blk;
|
||||
|
||||
@@ -22,7 +22,7 @@ int ext2_alloc_block(fs_t *ext2, uint32_t *block_no) {
|
||||
for (size_t i = 0; i < sb->block_group_count; ++i) {
|
||||
if (sb->block_group_descriptor_table[i].free_blocks > 0) {
|
||||
// Found a free block here
|
||||
kdebug("Allocating a block in group #%zu\n", i);
|
||||
kdebug("Allocating a block in group #%u\n", i);
|
||||
|
||||
if ((res = ext2_read_block(ext2,
|
||||
sb->block_group_descriptor_table[i].block_usage_bitmap_block,
|
||||
@@ -244,7 +244,7 @@ int ext2_alloc_inode(fs_t *ext2, uint32_t *ino) {
|
||||
for (size_t i = 0; i < sb->block_group_count; ++i) {
|
||||
if (sb->block_group_descriptor_table[i].free_inodes > 0) {
|
||||
// Found a block group with free inodes
|
||||
kdebug("Allocating an inode inside block group #%zu\n", i);
|
||||
kdebug("Allocating an inode inside block group #%u\n", i);
|
||||
|
||||
// Read inode usage bitmap
|
||||
if ((res = ext2_read_block(ext2,
|
||||
|
||||
Reference in New Issue
Block a user