Skip to content

Commit

Permalink
feat(ata): add bounds check and missing header
Browse files Browse the repository at this point in the history
Add bounds check to IO functions and missing header file.
  • Loading branch information
FedorLap2006 committed May 26, 2023
1 parent c566d8e commit 49b166b
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 18 deletions.
75 changes: 57 additions & 18 deletions drivers/ata.c
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
#include "depthos/dev.h"
#include "depthos/heap.h"
#include "depthos/idt.h"
#include <depthos/assert.h>
#include <depthos/ata.h>
#include <depthos/bitmap.h>
#include <depthos/dev.h>
#include <depthos/errno.h>
#include <depthos/heap.h>
#include <depthos/idt.h>
#include <depthos/logging.h>
#include <depthos/ports.h>
#include <depthos/strconv.h>
#include <depthos/string.h>

struct ata_dev_impl {
struct ata_port *port;
struct ata_identify *info;
int drive;
};

#if CONFIG_ATA_LOG_ENABLE == 1
#define ata_log(...) ata_log(__VA_ARGS__);
#define ata_log(...) klogf(__VA_ARGS__);
#else
#define ata_log(...)
#endif

#define BOUNDS_CHECK(dev, sector, n) \
if (sector >= IMPL(dev)->info->current_sector_capacity) { \
ata_log("trying to access with out-of-bounds sector: %d >= %d", sector, \
IMPL(dev)->info->current_sector_capacity); \
return 0; \
} else if (sector + n >= IMPL(dev)->info->current_sector_capacity) { \
ata_log("trying to access with partially in-bounds sector: %d + %d >= %d", \
sector, n, IMPL(dev)->info->current_sector_capacity); \
n = IMPL(dev)->info->current_sector_capacity - sector; \
}
// #define BOUNDS_CHECK(dev, sector, n) assert(sector + n <
// IMPL(dev)->info->current_sector_capacity);

#define IMPL(dev) ((struct ata_dev_impl *)dev->impl)
void ata_io_wait(struct ata_port *port,
bool alternate) { // XXX: should an IRQ be used?
Expand All @@ -32,12 +49,15 @@ static void ata_poll(struct ata_port *port, bool alternate, bool data) {
do {
v = inb(alternate ? port->ctl_base + ATA_REG_ALT_STAT
: port->io_base + ATA_REG_STAT);
// ata_log("ata wait: %x (%d)", v,
// (v & ATA_STATUS_BSY == 0 && v & ATA_STATUS_DRQ != 0));
} while (v & ATA_STATUS_BSY || (data && v & ATA_STATUS_DRQ != 0));

if (v & ATA_STATUS_ERR) {
panicf("ATA drive (ctl=%d, io=%d) is not working properly.", port->ctl_base,
ata_log("ata poll: bsy=%d drq=%d err=%d dfa=%d", (v & ATA_STATUS_BSY) != 0,
(v & ATA_STATUS_DRQ) != 0, (v & ATA_STATUS_ERR) != 0,
(v & ATA_STATUS_DFA) != 0);
} while (((v & ATA_STATUS_BSY) || (data && ((v & ATA_STATUS_DRQ) == 0))) &&
((v & ATA_STATUS_ERR) == 0) && ((v & ATA_STATUS_DFA) == 0));
ata_log("stopped polling");
if (v & ATA_STATUS_ERR || v & ATA_STATUS_DFA) {
panicf("ATA drive (ctl=%x, io=%x) is not working properly.", port->ctl_base,
port->io_base);
}
}
Expand Down Expand Up @@ -148,25 +168,29 @@ void ata_pio_prepare_transaction(struct ata_port *port, size_t lba,
outb(port->io_base + ATA_REG_CMD, write ? ATA_CMD_WRITE : ATA_CMD_READ);
}

void ata_pio_read(struct ata_port *port, uint16_t *buf, size_t lba,
uint8_t sector_count) {

int ata_pio_read(struct ata_port *port, uint16_t *buf, size_t lba,
uint8_t sector_count) {
ata_poll(port, false, false);
ata_pio_prepare_transaction(port, lba, sector_count, false);
ata_log("ata: reading %ld sectors at %ld", sector_count, lba);
for (int i = 0; i < sector_count; i++) {
ata_poll(port, false, true);

ata_poll(port, false, true); // TODO: error logging
ata_log("began reading");
for (int j = 0; j < 256; j++) {
buf[i * 256 + j] = inw(port->io_base + ATA_REG_DATA);
}
ata_log("stopped reading");
ata_io_wait(port, false);
}
return 0;
}

void ata_pio_write(struct ata_port *port, uint16_t *buf, size_t lba,
uint8_t sector_count) {
ata_pio_prepare_transaction(port, lba, sector_count, true);
int ata_pio_write(struct ata_port *port, uint16_t *buf, size_t lba,
uint8_t sector_count) {
ata_poll(port, false, false);
ata_pio_prepare_transaction(port, lba, sector_count, true);
ata_poll(port, false, false); // TODO: error logging

uint8_t sec = 0;
for (int i = 0; i < sector_count; i++) {
Expand All @@ -178,10 +202,14 @@ void ata_pio_write(struct ata_port *port, uint16_t *buf, size_t lba,
ata_poll(port, false, true);
ata_log("write status: 0x%x", ata_read_status(port, false));
}
return 0;
}

int ata_write(struct device *dev, void *buf, unsigned long count,
off_t *offset) {
BOUNDS_CHECK(dev, *offset, count);
if (count == 0)
return 0;
ata_drive_select(IMPL(dev)->port, IMPL(dev)->drive);
ata_pio_write(IMPL(dev)->port, buf, *offset, count);
*offset += count;
Expand All @@ -190,9 +218,15 @@ int ata_write(struct device *dev, void *buf, unsigned long count,

int ata_read(struct device *dev, void *buf, unsigned long count,
off_t *offset) {
BOUNDS_CHECK(dev, *offset, count);
if (count == 0)
return 0;
ata_drive_select(IMPL(dev)->port, IMPL(dev)->drive);
ata_log("attempting to do a pio read. offset: %ld count: %ld", *offset,
count);
ata_pio_read(IMPL(dev)->port, buf, *offset, count);
*offset += count;
ata_log("read successful");
return count;
}

Expand Down Expand Up @@ -224,12 +258,17 @@ void ata_init() {
ata_primary_port = create_ata_port(0x3F6, 0x1F0);
ata_secondary_port = create_ata_port(0x376, 0x170);
int i = 0;
struct ata_identify *info;
#define ATA_REGDEV(P, D) \
if (ata_identify(P, D)) { \
if (info = ata_identify(P, D)) { \
char *buf = kmalloc(8); \
memset(buf, 0, 8); \
itoa(i++, 10, buf + strlen("ata")); \
memcpy(buf, "ata", strlen("ata")); \
devfs_register(buf, create_ata_device(P, D)); \
struct device *dev = create_ata_device(P, D); \
IMPL(dev)->info = info; \
dev->name = buf; \
register_device(dev); \
}

ATA_REGDEV(ata_primary_port, 0);
Expand Down
121 changes: 121 additions & 0 deletions include/depthos/ata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#pragma once

#include <depthos/dev.h>
#include <depthos/stdtypes.h>
#include <depthos/tools.h>

// typedef enum {
// ATA_DEV_UNKNOWN,
// ATA_DEV_PATA,
// ATA_DEV_SATA,
// ATA_DEV_PATAPI,
// ATA_DEV_SATAPI
// } ata_dev_t;

#define ATA_REG_DATA 0
#define ATA_REG_ERROR 1
#define ATA_REG_FEATURES 1
#define ATA_REG_SECTOR_COUNT 2
#define ATA_REG_LBA_LOW 3
#define ATA_REG_LBA_MID 4
#define ATA_REG_LBA_HI 5
#define ATA_REG_DRIVE_HEAD 6 // Drive/head register
#define ATA_REG_STAT 7
#define ATA_REG_CMD 7

#define ATA_REG_DEV_CTL 0
#define ATA_REG_ALT_STAT 0

#define ATA_STATUS_BSY 1 << 7 // Busy, prepating to send or receive data.
#define ATA_STATUS_RDY 1 << 6 // Drive is on
#define ATA_STATUS_DFA 1 << 5 // Drive fault
#define ATA_STATUS_SRV 1 << 4 // Overlapped mode service request
#define ATA_STATUS_DRQ 1 << 3 // Data is ready
#define ATA_STATUS_COR 1 << 2 // Corrected data. Always 0
#define ATA_STATUS_IDX 1 << 1 // Index. Always 0
#define ATA_STATUS_ERR 1 << 0 // Error

#define ATA_CMD_IDENTIFY 0xEC
#define ATA_CMD_FLUSH 0xE7
#define ATA_CMD_READ 0x20
#define ATA_CMD_WRITE 0x30

struct ata_identify {
struct {
uint16_t reserved1 : 1;
uint16_t obsolete1 : 1;
uint16_t response_incomplete : 1;
uint16_t obsolete2 : 3;
uint16_t fixed_device : 1;
uint16_t removable_media : 1;
uint16_t obsolete3 : 7;
uint16_t atapi : 1;
} general_info;
uint16_t num_cylinders;
uint16_t specific_configuration;
uint16_t num_heads;
uint16_t retired1[2];
uint16_t num_sectors_per_track;
uint16_t vendor_unique1[3];
char serial_number[20];
uint16_t deprecated[2];
uint16_t obsolete1;
char firmware_revision[8];
char model_number[40];
uint16_t maximum_block_transfer;
struct {
uint16_t feature_supported : 1;
uint16_t reserved : 15;
} trusted_computing;
struct {
uint16_t vendor_unique1 : 8;
uint16_t obsolete1 : 2;
uint16_t iordy_toggleable : 1;
uint16_t iordy_support : 1;
uint16_t obsolete2 : 1;
uint16_t standy_timer_support : 1;
uint16_t obsolete3 : 2;
} capabilities;
uint16_t reserved1;
uint8_t vendor_unique2[2];
uint8_t obsolete;
uint8_t pio_data_transfer_cycle_timing_mode;
uint16_t valid_fields : 3;
uint16_t reserved2 : 5;
uint16_t freefall_control_sensitivity : 8;
uint16_t num_current_cylinders;
uint16_t num_current_heads;
uint16_t current_sectors_per_track;
uint32_t current_sector_capacity;
uint8_t sectors_per_interrupt;
uint8_t multi_sectors_setting_valid : 1;
uint8_t reserved3 : 3;
uint16_t sanitize_feature_supported : 1;
uint8_t crypto_scramble_ext_command_supported : 1;
uint8_t overwrite_ext_command_supported : 1;
uint8_t block_erase_ext_command_supported : 1;
uint32_t max_addressable_sectors;
} __pack;

typedef struct ata_identify ata_identify_data_t;

struct ata_port {
uint16_t io_base, ctl_base;
uint8_t current_drive_head;
};

ata_identify_data_t *ata_identify(struct ata_port *dev, int drive);
void ata_reset(struct ata_port *dev);
void ata_drive_select(struct ata_port *dev, int drive);
int ata_get_selected_drive(struct ata_port *dev);

void ata_io_wait(struct ata_port *dev, bool alternate);
int ata_pio_read(struct ata_port *dev, uint16_t *buf, size_t lba,
uint8_t sector_count);
int ata_pio_write(struct ata_port *dev, uint16_t *buf, size_t lba,
uint8_t sector_count);

struct device *create_ata_device(struct ata_port *port, int drive);
struct ata_port *create_ata_port(uint16_t ctl, uint16_t io);

void ata_init();

0 comments on commit 49b166b

Please sign in to comment.