From: Tulio A M Mendes Date: Sun, 8 Feb 2026 10:51:54 +0000 (-0300) Subject: storage: add ATA PIO + persistfs mounted at /persist X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=b65c12d09ef35e3db143c2c8113e4ee52f75af12;p=AdrOS.git storage: add ATA PIO + persistfs mounted at /persist --- diff --git a/Makefile b/Makefile index 0238493..02b67ab 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,9 @@ $(INITRD_IMG): $(MKINITRD) $(USER_ELF) $(ECHO_ELF) run: iso @rm -f serial.log qemu.log + @test -f disk.img || dd if=/dev/zero of=disk.img bs=1M count=4 2>/dev/null @qemu-system-i386 -boot d -cdrom adros-$(ARCH).iso -m 128M -display none \ + -drive file=disk.img,if=ide,format=raw \ -serial file:serial.log -monitor none -no-reboot -no-shutdown \ $(QEMU_DFLAGS) diff --git a/include/ata_pio.h b/include/ata_pio.h new file mode 100644 index 0000000..fa76bb2 --- /dev/null +++ b/include/ata_pio.h @@ -0,0 +1,12 @@ +#ifndef ATA_PIO_H +#define ATA_PIO_H + +#include +#include + +int ata_pio_init_primary_master(void); +int ata_pio_read28(uint32_t lba, uint8_t* buf512); +int ata_pio_write28(uint32_t lba, const uint8_t* buf512); +uint32_t ata_pio_sector_size(void); + +#endif diff --git a/include/errno.h b/include/errno.h index fb82c75..44ba576 100644 --- a/include/errno.h +++ b/include/errno.h @@ -10,6 +10,7 @@ #define EFAULT 14 #define EEXIST 17 #define ENOMEM 12 +#define ENODEV 19 #define ENOTDIR 20 #define EINVAL 22 #define ENOSPC 28 diff --git a/include/persistfs.h b/include/persistfs.h new file mode 100644 index 0000000..0414a19 --- /dev/null +++ b/include/persistfs.h @@ -0,0 +1,8 @@ +#ifndef PERSISTFS_H +#define PERSISTFS_H + +#include "fs.h" + +fs_node_t* persistfs_create_root(void); + +#endif diff --git a/src/drivers/ata_pio.c b/src/drivers/ata_pio.c new file mode 100644 index 0000000..6c33b93 --- /dev/null +++ b/src/drivers/ata_pio.c @@ -0,0 +1,151 @@ +#include "ata_pio.h" + +#include "errno.h" +#include "io.h" + +#if defined(__i386__) + +// Primary ATA bus I/O ports +#define ATA_IO_BASE 0x1F0 +#define ATA_CTRL_BASE 0x3F6 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 + +#define ATA_CMD_READ_SECTORS 0x20 +#define ATA_CMD_WRITE_SECTORS 0x30 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DF 0x20 +#define ATA_SR_DSC 0x10 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_ERR 0x01 + +static inline void io_wait_400ns(void) { + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); +} + +static int ata_wait_not_busy(void) { + for (int i = 0; i < 1000000; i++) { + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if ((st & ATA_SR_BSY) == 0) return 0; + } + return -EIO; +} + +static int ata_wait_drq(void) { + for (int i = 0; i < 1000000; i++) { + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if (st & ATA_SR_ERR) return -EIO; + if (st & ATA_SR_DF) return -EIO; + if ((st & ATA_SR_BSY) == 0 && (st & ATA_SR_DRQ)) return 0; + } + return -EIO; +} + +uint32_t ata_pio_sector_size(void) { + return 512; +} + +int ata_pio_init_primary_master(void) { + // Select drive: 0xA0 = master, CHS mode bits set, LBA bit cleared + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), 0xA0); + io_wait_400ns(); + + if (ata_wait_not_busy() < 0) return -EIO; + + // IDENTIFY + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_IDENTIFY); + + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if (st == 0) return -ENODEV; + + if (ata_wait_drq() < 0) return -EIO; + + // Read 256 words (512 bytes) identify data and discard. + for (int i = 0; i < 256; i++) { + (void)inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); + } + + return 0; +} + +int ata_pio_read28(uint32_t lba, uint8_t* buf512) { + if (!buf512) return -EFAULT; + if (lba & 0xF0000000U) return -EINVAL; + + if (ata_wait_not_busy() < 0) return -EIO; + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); + io_wait_400ns(); + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_READ_SECTORS); + + if (ata_wait_drq() < 0) return -EIO; + + uint16_t* w = (uint16_t*)buf512; + for (int i = 0; i < 256; i++) { + w[i] = inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); + } + + io_wait_400ns(); + return 0; +} + +int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { + if (!buf512) return -EFAULT; + if (lba & 0xF0000000U) return -EINVAL; + + if (ata_wait_not_busy() < 0) return -EIO; + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); + io_wait_400ns(); + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_WRITE_SECTORS); + + if (ata_wait_drq() < 0) return -EIO; + + const uint16_t* w = (const uint16_t*)buf512; + for (int i = 0; i < 256; i++) { + outw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA), w[i]); + } + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_CACHE_FLUSH); + (void)ata_wait_not_busy(); + io_wait_400ns(); + return 0; +} + +#else + +uint32_t ata_pio_sector_size(void) { return 512; } +int ata_pio_init_primary_master(void) { return -ENOSYS; } +int ata_pio_read28(uint32_t lba, uint8_t* buf512) { (void)lba; (void)buf512; return -ENOSYS; } +int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { (void)lba; (void)buf512; return -ENOSYS; } + +#endif diff --git a/src/kernel/init.c b/src/kernel/init.c index afb5749..c6a7dc3 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -8,6 +8,7 @@ #include "tmpfs.h" #include "devfs.h" #include "tty.h" +#include "persistfs.h" #include "uart_console.h" #include "hal/mm.h" @@ -69,6 +70,11 @@ int init_start(const struct boot_info* bi) { (void)vfs_mount("/dev", dev); } + fs_node_t* persist = persistfs_create_root(); + if (persist) { + (void)vfs_mount("/persist", persist); + } + int user_ret = arch_platform_start_userspace(bi); if (bi && cmdline_has_token(bi->cmdline, "ring3")) { diff --git a/src/kernel/persistfs.c b/src/kernel/persistfs.c new file mode 100644 index 0000000..76d7f50 --- /dev/null +++ b/src/kernel/persistfs.c @@ -0,0 +1,89 @@ +#include "persistfs.h" + +#include "ata_pio.h" +#include "errno.h" +#include "heap.h" +#include "utils.h" + +// Minimal on-disk persistent storage: +// - LBA0 reserved +// - LBA1 holds one 512-byte file called "counter" (first 4 bytes are the counter value) + +#define PERSISTFS_LBA_COUNTER 1U + +static fs_node_t g_root; +static fs_node_t g_counter; +static uint32_t g_ready = 0; + +static uint32_t persist_counter_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + (void)node; + if (!buffer) return 0; + if (!g_ready) return 0; + + uint8_t sec[512]; + if (ata_pio_read28(PERSISTFS_LBA_COUNTER, sec) < 0) return 0; + + if (offset >= 512U) return 0; + if (offset + size > 512U) size = 512U - offset; + + memcpy(buffer, sec + offset, size); + return size; +} + +static uint32_t persist_counter_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { + (void)node; + if (!buffer) return 0; + if (!g_ready) return 0; + + if (offset >= 512U) return 0; + if (offset + size > 512U) size = 512U - offset; + + uint8_t sec[512]; + if (ata_pio_read28(PERSISTFS_LBA_COUNTER, sec) < 0) return 0; + + memcpy(sec + offset, buffer, size); + + if (ata_pio_write28(PERSISTFS_LBA_COUNTER, sec) < 0) return 0; + return size; +} + +static struct fs_node* persist_root_finddir(struct fs_node* node, const char* name) { + (void)node; + if (!name || name[0] == 0) return 0; + if (strcmp(name, "counter") == 0) return &g_counter; + return 0; +} + +fs_node_t* persistfs_create_root(void) { + if (!g_ready) { + if (ata_pio_init_primary_master() == 0) { + g_ready = 1; + } else { + g_ready = 0; + } + + memset(&g_root, 0, sizeof(g_root)); + strcpy(g_root.name, "persist"); + g_root.flags = FS_DIRECTORY; + g_root.inode = 1; + g_root.length = 0; + g_root.read = 0; + g_root.write = 0; + g_root.open = 0; + g_root.close = 0; + g_root.finddir = &persist_root_finddir; + + memset(&g_counter, 0, sizeof(g_counter)); + strcpy(g_counter.name, "counter"); + g_counter.flags = FS_FILE; + g_counter.inode = 2; + g_counter.length = 512; + g_counter.read = &persist_counter_read; + g_counter.write = &persist_counter_write; + g_counter.open = 0; + g_counter.close = 0; + g_counter.finddir = 0; + } + + return g_ready ? &g_root : 0; +} diff --git a/user/init.c b/user/init.c index 5f798cc..d128756 100644 --- a/user/init.c +++ b/user/init.c @@ -1187,6 +1187,46 @@ void _start(void) { sys_write(1, "[init] /dev/null OK\n", (uint32_t)(sizeof("[init] /dev/null OK\n") - 1)); } + // B1: persistent storage smoke. Value should increment across reboots (disk.img). + { + int fd = sys_open("/persist/counter", 0); + if (fd < 0) { + sys_write(1, "[init] /persist/counter open failed\n", + (uint32_t)(sizeof("[init] /persist/counter open failed\n") - 1)); + sys_exit(1); + } + + (void)sys_lseek(fd, 0, SEEK_SET); + uint8_t b[4] = {0, 0, 0, 0}; + int rd = sys_read(fd, b, 4); + if (rd != 4) { + sys_write(1, "[init] /persist/counter read failed\n", + (uint32_t)(sizeof("[init] /persist/counter read failed\n") - 1)); + sys_exit(1); + } + + uint32_t v = (uint32_t)b[0] | ((uint32_t)b[1] << 8) | ((uint32_t)b[2] << 16) | ((uint32_t)b[3] << 24); + v++; + b[0] = (uint8_t)(v & 0xFF); + b[1] = (uint8_t)((v >> 8) & 0xFF); + b[2] = (uint8_t)((v >> 16) & 0xFF); + b[3] = (uint8_t)((v >> 24) & 0xFF); + + (void)sys_lseek(fd, 0, SEEK_SET); + int wr = sys_write(fd, b, 4); + if (wr != 4) { + sys_write(1, "[init] /persist/counter write failed\n", + (uint32_t)(sizeof("[init] /persist/counter write failed\n") - 1)); + sys_exit(1); + } + + (void)sys_close(fd); + + sys_write(1, "[init] /persist/counter=", (uint32_t)(sizeof("[init] /persist/counter=") - 1)); + write_int_dec((int)v); + sys_write(1, "\n", 1); + } + { int fd = sys_open("/dev/tty", 0); if (fd < 0) {