From b74ef85cce1ceb5840e9f3bdc43558b75740b83b Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sun, 27 Mar 2022 16:38:14 +0200 Subject: kernel/vfs: partial ATA drive support --- Makefile | 5 ++--- src/init/shell.c | 2 +- src/kernel/arch/i386/ata.c | 48 ++++++++++++++++++++++++++++++------------ src/kernel/arch/i386/ata.h | 3 +++ src/kernel/vfs/root.c | 52 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index bce95f6..3d913d4 100644 --- a/Makefile +++ b/Makefile @@ -22,13 +22,12 @@ endef all: out/boot.iso check boot: all out/hdd - qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -serial stdio \ - -drive file=out/hdd,format=raw,media=disk + qemu-system-i386 -drive file=out/boot.iso,format=raw,media=disk $(QFLAGS) -serial stdio test: all @# pipes for the serial @mkfifo out/qemu.in out/qemu.out 2> /dev/null || true - qemu-system-i386 -cdrom out/boot.iso $(QFLAGS) -serial pipe:out/qemu & + qemu-system-i386 -drive file=out/boot.iso,format=raw,media=disk $(QFLAGS) -serial pipe:out/qemu & @# for some reason the first sent character doesn't go through to the shell @# the empty echo takes care of that, so the next echos will work just fine @echo > out/qemu.in diff --git a/src/init/shell.c b/src/init/shell.c index 0113866..5612f35 100644 --- a/src/init/shell.c +++ b/src/init/shell.c @@ -46,7 +46,7 @@ static int readline(char *buf, size_t max) { static void cmd_cat_ls(const char *args, bool ls) { int fd; - static char buf[256]; + static char buf[512]; int len; // first used for strlen(args), then length of buffer if (!args) args = "/"; diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c index 9224ed6..b546c07 100644 --- a/src/kernel/arch/i386/ata.c +++ b/src/kernel/arch/i386/ata.c @@ -15,6 +15,9 @@ static struct { } ata_drives[4]; enum { + DATA = 0, + FEAT = 1, + SCNT = 2, LBAlo = 3, LBAmid = 4, LBAhi = 5, @@ -112,20 +115,39 @@ static bool ata_identify(int drive) { } void ata_init(void) { - tty_const("\n"); for (int i = 0; i < 4; i++) { - tty_const("probing drive "); - _tty_var(i); ata_detecttype(i); - if (ata_drives[i].type != DEV_UNKNOWN) { - if (ata_identify(i)) { - tty_const(" - "); - _tty_var(ata_drives[i].sectors); - tty_const(" sectors (512b)"); - } else { - tty_const(" identify failed"); - } - } - tty_const("\n"); + if (ata_drives[i].type == DEV_PATA) + ata_identify(i); } } + +bool ata_available(int drive) { + return ata_drives[drive].type != DEV_UNKNOWN; +} + +int ata_read(int drive, uint32_t lba, void *buf) { + assert(ata_drives[drive].type == DEV_PATA); + int iobase = ata_iobase(drive); + + ata_driveselect(drive, lba); + port_out8(iobase + FEAT, 0); // supposedly pointless + port_out8(iobase + SCNT, 1); // sector count + port_out8(iobase + LBAlo, lba); + port_out8(iobase + LBAmid, lba >> 8); + port_out8(iobase + LBAhi, lba >> 16); + port_out8(iobase + CMD, 0x20); // READ SECTORS + + for (;;) { // TODO separate polling function + uint8_t v = port_in8(iobase + STATUS); + if (v & 0x80) continue; // still BSY, continue + if (v & 0x40) break; // RDY, break + // TODO check for ERR + } + + uint16_t *b = buf; + for (int i = 0; i < 256; i++) + b[i] = port_in16(iobase); + + return 512; +} diff --git a/src/kernel/arch/i386/ata.h b/src/kernel/arch/i386/ata.h index 9137cdb..82f4f81 100644 --- a/src/kernel/arch/i386/ata.h +++ b/src/kernel/arch/i386/ata.h @@ -1,4 +1,7 @@ #pragma once +#include #include void ata_init(void); +bool ata_available(int drive); +int ata_read(int drive, uint32_t lba, void *buf); diff --git a/src/kernel/vfs/root.c b/src/kernel/vfs/root.c index 9833330..e881ff2 100644 --- a/src/kernel/vfs/root.c +++ b/src/kernel/vfs/root.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,10 +6,15 @@ #include #include +// TODO move to arch/ + enum { HANDLE_ROOT, HANDLE_TTY, HANDLE_VGA, + HANDLE_ATA_ROOT, + HANDLE_ATA, + _SKIP = HANDLE_ATA + 4, }; static bool exacteq(struct vfs_request *req, const char *str) { @@ -49,18 +55,29 @@ static void req_preprocess(struct vfs_request *req, int max_len) { int vfs_root_handler(struct vfs_request *req) { switch (req->type) { case VFSOP_OPEN: - if (exacteq(req, "/")) return HANDLE_ROOT; - if (exacteq(req, "/tty")) return HANDLE_TTY; - if (exacteq(req, "/vga")) return HANDLE_VGA; + if (exacteq(req, "/")) return HANDLE_ROOT; + if (exacteq(req, "/tty")) return HANDLE_TTY; + if (exacteq(req, "/vga")) return HANDLE_VGA; + if (exacteq(req, "/ata/")) return HANDLE_ATA_ROOT; + + if (exacteq(req, "/ata/0")) + return ata_available(0) ? HANDLE_ATA+0 : -1; + if (exacteq(req, "/ata/1")) + return ata_available(1) ? HANDLE_ATA+1 : -1; + if (exacteq(req, "/ata/2")) + return ata_available(2) ? HANDLE_ATA+2 : -1; + if (exacteq(req, "/ata/3")) + return ata_available(3) ? HANDLE_ATA+3 : -1; + return -1; case VFSOP_READ: switch (req->id) { case HANDLE_ROOT: { // TODO document directory read format - const char *src = "tty\0vga\0"; + const char src[] = "tty\0vga\0ata/"; if (req->output.len < 0) return 0; // is this needed? TODO make that a size_t or something - int len = min((size_t) req->output.len, strlen(src) + 1); + int len = min((size_t) req->output.len, sizeof(src)); virt_cpy_to(req->caller->pages, req->output.buf, src, len); return len; } @@ -79,6 +96,30 @@ int vfs_root_handler(struct vfs_request *req) { vga + req->offset, req->output.len); return req->output.len; } + case HANDLE_ATA_ROOT: { + // TODO offset + char list[8] = {}; + size_t len = 0; + for (int i = 0; i < 4; i++) { + if (ata_available(i)) { + list[len] = '0' + i; + len += 2; + } + } + len = min((size_t) req->output.len, len); + virt_cpy_to(req->caller->pages, req->output.buf, list, len); + return len; + } + case HANDLE_ATA: case HANDLE_ATA+1: + case HANDLE_ATA+2: case HANDLE_ATA+3: { + if (req->offset < 0) return 0; + char buf[512]; + uint32_t sector = req->offset / 512; + int len = min(req->output.len, 512 - (req->offset & 511)); + ata_read(req->id - HANDLE_ATA, sector, buf); + virt_cpy_to(req->caller->pages, req->output.buf, buf, len); + return len; + } default: panic_invalid_state(); } @@ -100,6 +141,7 @@ int vfs_root_handler(struct vfs_request *req) { req->input.buf, req->input.len); return req->input.len; } + case HANDLE_ATA_ROOT: return -1; default: panic_invalid_state(); } -- cgit v1.2.3