diff --git a/aux/qemu_amd64.sh b/aux/qemu_amd64.sh index cca9eab..ee702ec 100755 --- a/aux/qemu_amd64.sh +++ b/aux/qemu_amd64.sh @@ -2,4 +2,4 @@ set -x -qemu-system-x86_64 -M q35 -m 4G -serial stdio -enable-kvm -cdrom mop3.iso -smp 4 $@ +qemu-system-x86_64 -M pc -m 4G -serial stdio -enable-kvm -cdrom mop3.iso -smp 4 -boot d $@ diff --git a/aux/qemu_amd64_debug.sh b/aux/qemu_amd64_debug.sh index 1321e07..3c50d26 100755 --- a/aux/qemu_amd64_debug.sh +++ b/aux/qemu_amd64_debug.sh @@ -2,4 +2,4 @@ set -x -qemu-system-x86_64 -M q35 -m 4G -serial stdio -cdrom mop3.iso -smp 1 -s -S $@ +qemu-system-x86_64 -M pc -m 4G -serial stdio -cdrom mop3.iso -smp 1 -s -S -boot d $@ diff --git a/ce/interp.c b/ce/interp.c index 87b7612..f789858 100644 --- a/ce/interp.c +++ b/ce/interp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +273,27 @@ static void quit1 (struct context* context) { static void cls (struct context* context) { cprintf (context, ANSIQ_CUR_HOME ANSIQ_SCR_CLR_ALL); } +static void mkvol (struct context* context, const char* volume, const char* str_fs_type, + const char* device) { + int fs_type; + + if (strcmp (str_fs_type, "tar") == 0) { + fs_type = FS_TARFS; + } else if (strcmp (str_fs_type, "fat16") == 0) { + fs_type = FS_FAT16; + } else if (strcmp (str_fs_type, "fat32") == 0) { + fs_type = FS_FAT32; + } else { + cprintf (context, "Unknown filesystem '%s'\n", str_fs_type); + return; + } + + int ret = create_volume (volume, fs_type, device); + + if (ret < 0) + cprintf (context, "Could not create volume: %s\n", str_status[-ret]); +} + static void help (struct context* context) { cprintf (context, "Available commands:\n"); cprintf (context, "help\n"); @@ -284,6 +306,7 @@ static void help (struct context* context) { cprintf (context, "edit \n"); cprintf (context, "terminfo\n"); cprintf (context, "cls\n"); + cprintf (context, "mkvol \n"); cprintf (context, "quit\n"); } @@ -309,7 +332,10 @@ static void execute_cmd (struct ast_cmd* cmd, struct context* context) { } else if (strcmp (cmd->name, "cat") == 0) { cat (context, cmd->args, cmd->arg_count); } else if (strcmp (cmd->name, "ls") == 0) { - ls (context, cmd->args[0]); + if (cmd->args[0] != NULL) + ls (context, cmd->args[0]); + else + cprintf (context, "No directory path provided\n"); } else if (strcmp (cmd->name, "quit") == 0) { quit1 (context); } else if (strcmp (cmd->name, "mkfile") == 0) { @@ -319,11 +345,19 @@ static void execute_cmd (struct ast_cmd* cmd, struct context* context) { } else if (strcmp (cmd->name, "rm") == 0) { rm (context, cmd->args, cmd->arg_count); } else if (strcmp (cmd->name, "edit") == 0) { - edit (context, cmd->args[0]); + if (cmd->args[0] != NULL) + edit (context, cmd->args[0]); + else + cprintf (context, "No file path provided\n"); } else if (strcmp (cmd->name, "terminfo") == 0) { terminfo (context); } else if (strcmp (cmd->name, "cls") == 0) { cls (context); + } else if (strcmp (cmd->name, "mkvol") == 0) { + if ((cmd->args[0] != NULL) && (cmd->args[1] != NULL) && (cmd->args[2] != NULL)) + mkvol (context, cmd->args[0], cmd->args[1], cmd->args[2]); + else + cprintf (context, "No volume key, filesystem type or device key provided\n"); } else { char volume[VOLUME_MAX]; const char* path; diff --git a/include/devices.h b/include/devices.h index 70525f4..54ae3f5 100644 --- a/include/devices.h +++ b/include/devices.h @@ -11,6 +11,7 @@ /* drive devices */ #define XDRV_TYPE_RAMDRV 0 #define XDRV_TYPE_PARTDRV 1 +#define XDRV_TYPE_IDEDRV 2 #define XDRV_GET_SIZE 0 #define XDRV_GET_SECTOR_SIZE 1 #define XDRV_GET_DEVICE_TYPE 2 diff --git a/include/fs_types.h b/include/fs_types.h new file mode 100644 index 0000000..1009000 --- /dev/null +++ b/include/fs_types.h @@ -0,0 +1,8 @@ +#ifndef _FS_TYPES_H +#define _FS_TYPES_H + +#define FS_TARFS 0 +#define FS_FAT16 1 +#define FS_FAT32 2 + +#endif // _FS_TYPES_H diff --git a/include/status.h b/include/status.h index ef603a7..bfebe2b 100644 --- a/include/status.h +++ b/include/status.h @@ -23,5 +23,7 @@ #define ST_PARTITION_ERROR 19 #define ST_CREATE_DIR_ERROR 20 #define ST_REMOVE_ERROR 21 +#define ST_XDRV_READ_ERROR 22 +#define ST_XDRV_WRITE_ERROR 23 #endif // _M_STATUS_H diff --git a/include/syscall_defs.h b/include/syscall_defs.h index 0922e7f..d33c71a 100644 --- a/include/syscall_defs.h +++ b/include/syscall_defs.h @@ -29,5 +29,6 @@ #define SYS_KILL 26 #define SYS_CREATE_DIR 27 #define SYS_REMOVE 28 +#define SYS_CREATE_VOLUME 29 #endif // _M_SYSCALL_DEFS_H diff --git a/kernel/amd64/bootmain.c b/kernel/amd64/bootmain.c index 87a950f..13e8c34 100644 --- a/kernel/amd64/bootmain.c +++ b/kernel/amd64/bootmain.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -60,13 +61,13 @@ void bootmain (void) { vfs_init (); struct device* ramdisk = device_find ("RD"); - vfs_create_volume ("RD", VFS_TARFS, ramdisk, false); + vfs_create_volume ("RD", FS_TARFS, ramdisk, false); struct device* temp = device_find ("TEMP"); device_probe_partitions (temp); struct device* tempp0 = device_find ("TEMPp0"); - vfs_create_volume ("TEMP", VFS_FAT32, tempp0, true); + vfs_create_volume ("TEMP", FS_FAT32, tempp0, true); proc_pid_alloc_init (); procgroup_pgid_alloc_init (); diff --git a/kernel/amd64/io.h b/kernel/amd64/io.h index f3d490c..0704eee 100644 --- a/kernel/amd64/io.h +++ b/kernel/amd64/io.h @@ -4,13 +4,21 @@ #include void outb (uint16_t port, uint8_t v); + void outw (uint16_t port, uint16_t v); + void outl (uint16_t port, uint32_t v); + void outsw (uint16_t port, const void* addr, int cnt); + uint8_t inb (uint16_t port); + uint16_t inw (uint16_t port); + uint32_t inl (uint16_t port); + void insw (uint16_t port, void* addr, int cnt); + void io_wait (void); #endif // _KERNEL_AMD64_IO_H diff --git a/kernel/device/idedrv.c b/kernel/device/idedrv.c new file mode 100644 index 0000000..20cee03 --- /dev/null +++ b/kernel/device/idedrv.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IDE_REG_DATA 0x00 +#define IDE_REG_ERROR 0x01 +#define IDE_REG_SECCOUNT 0x02 +#define IDE_REG_LBA0 0x03 +#define IDE_REG_LBA1 0x04 +#define IDE_REG_LBA2 0x05 +#define IDE_REG_DRIVE 0x06 +#define IDE_REG_STATUS 0x07 +#define IDE_REG_CMD 0x07 + +#define IDE_BSY 0x80 +#define IDE_DRDY 0x40 +#define IDE_DF 0x20 +#define IDE_ERR 0x01 +#define IDE_DRQ 0x08 + +#define IDE_CMD_READ28 0x20 +#define IDE_CMD_WRITE28 0x30 +#define IDE_CMD_READ48 0x24 +#define IDE_CMD_WRITE48 0x34 +#define IDE_CMD_FLUSH48 0xEA +#define IDE_CMD_FLUSH28 0xE7 +#define IDE_CMD_IDENTIFY 0xEC + +static bool ide_wait (uint16_t io, uint32_t timeout, bool drq, bool errcheck) { + uint32_t i = 0; + uint8_t status; + + for (;;) { + status = inb (io + IDE_REG_STATUS); + + if (!(status & IDE_BSY)) + break; + + if (++i >= timeout) + return false; + } + + if (drq) { + i = 0; + while (!(status & IDE_DRQ)) { + if (status & IDE_ERR) + return false; + + status = inb (io + IDE_REG_STATUS); + + if (status == 0xFF) + return true; + + if (++i >= timeout) + return false; + } + } + + if (errcheck && (status & (IDE_DF | IDE_ERR))) + return false; + + return true; +} + +#pragma clang optimize off +static void ide_delay (uint16_t ctrl) { + inb (ctrl); + inb (ctrl); + inb (ctrl); + inb (ctrl); +} +#pragma clang optimize on + +void ide_probe (uint16_t io, uint16_t ctrl, uint8_t devno, struct ide_probe* probe) { + probe->flags = 0; + probe->sector_count = 0; + probe->sector_size = 0; + + uint16_t identify_buffer[256]; + + uint8_t status = inb (io + IDE_REG_STATUS); + + if (status == 0xFF) + return; + + outb (io + IDE_REG_DRIVE, 0xA0 | (devno << 4)); + ide_delay (ctrl); + + outb (io + IDE_REG_SECCOUNT, 0); + outb (io + IDE_REG_LBA0, 0); + outb (io + IDE_REG_LBA1, 0); + outb (io + IDE_REG_LBA2, 0); + + outb (io + IDE_REG_CMD, IDE_CMD_IDENTIFY); + + status = inb (io + IDE_REG_STATUS); + + if (status == 0) + return; + + if (!ide_wait (io, 100000, true, true)) { + return; + } + + insw (io + IDE_REG_DATA, identify_buffer, 256); + + probe->flags |= IDE_PROBE_AVAIL; + + if ((identify_buffer[106] & 0xC000) == 0x4000) { + if (identify_buffer[106] & (1 << 12)) { + uint32_t words_per_sector = + (uint32_t)identify_buffer[117] | ((uint32_t)identify_buffer[118] << 16); + probe->sector_size = (size_t)words_per_sector * 2; + } + } + + if ((identify_buffer[83] & (1 << 10)) != 0) + probe->flags |= IDE_PROBE_LBA48; + + if ((probe->flags & IDE_PROBE_LBA48)) { + probe->sector_count = + (size_t)((uint64_t)identify_buffer[100] | ((uint64_t)identify_buffer[101] << 16) | + ((uint64_t)identify_buffer[102] << 32) | ((uint64_t)identify_buffer[103] << 48)); + } else { + probe->sector_count = + (size_t)((uint64_t)identify_buffer[60] | ((uint64_t)identify_buffer[61] << 16)); + } + + probe->io = io; + probe->ctrl = ctrl; + probe->devno = devno; + + if (probe->sector_size == 0) + probe->sector_size = 512; +} + +static void ide_prepare (struct idedrv* idedrv, size_t sector, uint16_t sector_count) { + if (idedrv->lba48) { + outb (idedrv->io + IDE_REG_DRIVE, 0x40 | (idedrv->devno << 4)); + ide_delay (idedrv->ctrl); + + outb (idedrv->io + IDE_REG_SECCOUNT, (sector_count >> 8) & 0xFF); + outb (idedrv->io + IDE_REG_LBA0, (sector >> 24) & 0xFF); + outb (idedrv->io + IDE_REG_LBA1, (sector >> 32) & 0xFF); + outb (idedrv->io + IDE_REG_LBA2, (sector >> 40) & 0xFF); + + outb (idedrv->io + IDE_REG_SECCOUNT, sector_count & 0xFF); + outb (idedrv->io + IDE_REG_LBA0, sector & 0xFF); + outb (idedrv->io + IDE_REG_LBA1, (sector >> 8) & 0xFF); + outb (idedrv->io + IDE_REG_LBA2, (sector >> 16) & 0xFF); + } else { + outb (idedrv->io + IDE_REG_DRIVE, 0xE0 | (idedrv->devno << 4) | ((sector >> 24) & 0xFF)); + ide_delay (idedrv->ctrl); + + uint8_t count = (sector_count == 256) ? 0 : (uint8_t)sector_count; + outb (idedrv->io + IDE_REG_SECCOUNT, count); + outb (idedrv->io + IDE_REG_LBA0, sector & 0xFF); + outb (idedrv->io + IDE_REG_LBA1, (sector >> 8) & 0xFF); + outb (idedrv->io + IDE_REG_LBA2, (sector >> 16) & 0xFF); + } +} + +bool idedrv_init (struct device* device, void* arg) { + struct idedrv_init* init = arg; + + struct idedrv* idedrv = malloc (sizeof (*idedrv)); + + if (idedrv == NULL) + return false; + + idedrv->lba48 = init->lba48; + idedrv->sector_count = init->sector_count; + idedrv->sector_size = init->sector_size; + idedrv->io = init->io; + idedrv->ctrl = init->ctrl; + idedrv->devno = init->devno; + + device->udata = idedrv; + + return true; +} + +void idedrv_fini (struct device* device) { + struct idedrv* idedrv = device->udata; + + free (idedrv); +} + +int idedrv_read (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, void* a1, + void* a2, void* a3, void* a4) { + (void)proc, (void)rctx, (void)a4; + + if (a1 == NULL || a2 == NULL || a3 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t sector = *(size_t*)a1; + size_t sector_count = *(size_t*)a2; + uint16_t* buffer = a3; + + struct idedrv* idedrv = device->udata; + + if (sector + sector_count > idedrv->sector_count) + return -ST_OOB_ERROR; + + ide_prepare (idedrv, sector, sector_count); + + uint8_t cmd = idedrv->lba48 ? IDE_CMD_READ48 : IDE_CMD_READ28; + outb (idedrv->io + IDE_REG_CMD, cmd); + + for (uint16_t s = 0; s < sector_count; s++) { + if (!ide_wait (idedrv->io, 100000, true, true)) + return -ST_XDRV_READ_ERROR; + + insw (idedrv->io + IDE_REG_DATA, buffer + (s * (idedrv->sector_size / 2)), + idedrv->sector_size / 2); + } + + return ST_OK; +} + +int idedrv_write (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, void* a1, + void* a2, void* a3, void* a4) { + (void)proc, (void)rctx, (void)a4; + + if (a1 == NULL || a2 == NULL || a3 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t sector = *(size_t*)a1; + size_t sector_count = *(size_t*)a2; + uint16_t* buffer = a3; + + struct idedrv* idedrv = device->udata; + + if (sector + sector_count > idedrv->sector_count) + return -ST_OOB_ERROR; + + ide_prepare (idedrv, sector, sector_count); + + uint8_t cmd = idedrv->lba48 ? IDE_CMD_WRITE48 : IDE_CMD_WRITE28; + outb (idedrv->io + IDE_REG_CMD, cmd); + + for (uint16_t s = 0; s < sector_count; s++) { + if (!ide_wait (idedrv->io, 100000, true, true)) + return -ST_XDRV_WRITE_ERROR; + + outsw (idedrv->io + IDE_REG_DATA, buffer + (s * (idedrv->sector_size / 2)), + idedrv->sector_size / 2); + } + + cmd = idedrv->lba48 ? IDE_CMD_FLUSH48 : IDE_CMD_FLUSH28; + outb (idedrv->io + IDE_REG_CMD, cmd); + ide_wait (idedrv->io, 100000, false, true); + + return ST_OK; +} + +int idedrv_get_device_type (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4) { + (void)proc, (void)rctx, (void)device, (void)a2, (void)a3, (void)a4; + + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + int* device_type = (int*)a1; + + *device_type = XDRV_TYPE_IDEDRV; + + return ST_OK; +} + +int idedrv_get_sector_size (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4) { + (void)proc, (void)rctx, (void)a2, (void)a3, (void)a4; + + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t* secsize = (size_t*)a1; + + struct idedrv* idedrv = device->udata; + + *secsize = idedrv->sector_size; + + return ST_OK; +} + +int idedrv_get_size (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4) { + (void)proc, (void)rctx, (void)a2, (void)a3, (void)a4; + + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + size_t* size = (size_t*)a1; + + struct idedrv* idedrv = device->udata; + + *size = idedrv->sector_size * idedrv->sector_count; + + return ST_OK; +} diff --git a/kernel/device/idedrv.h b/kernel/device/idedrv.h new file mode 100644 index 0000000..d6311f2 --- /dev/null +++ b/kernel/device/idedrv.h @@ -0,0 +1,58 @@ +#ifndef _KERNEL_DEVICE_IDEDRV_H +#define _KERNEL_DEVICE_IDEDRV_H + +#include +#include +#include + +#define IDE_PROBE_AVAIL (1 << 0) +#define IDE_PROBE_LBA48 (1 << 1) + +struct device; + +struct idedrv_init { + bool lba48; + size_t sector_count; + size_t sector_size; + uint16_t io, ctrl; + uint8_t devno; +}; + +struct idedrv { + bool lba48; + size_t sector_count; + size_t sector_size; + uint16_t io, ctrl; + uint8_t devno; +}; + +struct ide_probe { + uint16_t flags; + size_t sector_count; + size_t sector_size; + uint16_t io, ctrl; + uint8_t devno; +}; + +bool idedrv_init (struct device* device, void* arg); + +void idedrv_fini (struct device* device); + +int idedrv_read (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, void* a1, + void* a2, void* a3, void* a4); + +int idedrv_write (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, void* a1, + void* a2, void* a3, void* a4); + +int idedrv_get_device_type (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4); + +int idedrv_get_sector_size (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4); + +int idedrv_get_size (struct device* device, struct proc* proc, struct reschedule_ctx* rctx, + void* a1, void* a2, void* a3, void* a4); + +void ide_probe (uint16_t io, uint16_t ctrl, uint8_t devno, struct ide_probe* probe); + +#endif // _KERNEL_DEVICE_IDEDRV_H diff --git a/kernel/device/pci.c b/kernel/device/pci.c index 22df0a0..9ffc503 100644 --- a/kernel/device/pci.c +++ b/kernel/device/pci.c @@ -1,20 +1,94 @@ #include #include +#include +#include +#include #include +#include #include -static uint32_t pci_read32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { +static const struct pci_driver_info pci_driver_infos[] = { + {.class = 0x01, .subclass = 0x01, .init = &pci_ide_init}, +}; + +static spin_lock_t pci_lock = SPIN_LOCK_INIT; + +uint32_t pci_read32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | - (offset & 0xFc) | ((uint32_t)0x80000000); + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + outl (PCI_CONFIG_ADDR, addr); - return inl (PCI_CONFIG_DATA); + uint32_t r = inl (PCI_CONFIG_DATA); + + spin_unlock (&pci_lock); + + return r; } -static void pci_write32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) { +void pci_write32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) { uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | - (offset & 0xFc) | ((uint32_t)0x80000000); + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + outl (PCI_CONFIG_ADDR, addr); outl (PCI_CONFIG_DATA, value); + + spin_unlock (&pci_lock); +} + +uint16_t pci_read16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + + outl (PCI_CONFIG_ADDR, addr); + uint16_t r = inw (PCI_CONFIG_DATA + (offset & 2)); + + spin_unlock (&pci_lock); + + return r; +} + +void pci_write16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t value) { + uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + + outl (PCI_CONFIG_ADDR, addr); + outw (PCI_CONFIG_DATA + (offset & 2), value); + + spin_unlock (&pci_lock); +} + +uint8_t pci_read8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + + outl (PCI_CONFIG_ADDR, addr); + uint8_t r = inb (PCI_CONFIG_DATA + (offset & 3)); + + spin_unlock (&pci_lock); + + return r; +} + +void pci_write8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t value) { + uint32_t addr = (uint32_t)((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000); + + spin_lock (&pci_lock); + + outl (PCI_CONFIG_ADDR, addr); + outb (PCI_CONFIG_DATA + (offset & 3), value); + + spin_unlock (&pci_lock); } static void pci_check_bus (uint8_t bus, pci_cb_func_t cb); @@ -28,20 +102,20 @@ static void pci_check_func (uint8_t bus, uint8_t slot, uint8_t func, pci_cb_func uint32_t reg8 = pci_read32 (bus, slot, func, PCI_REVISION_ID); - struct pci_dev pci_dev = { + struct pci_info pci_info = { .bus = bus, .slot = slot, .func = func, .vendor = vendor, .device = ((uint16_t)(reg0 >> 16)), - .classcode = ((uint8_t)(reg8 >> 24)), + .class = ((uint8_t)(reg8 >> 24)), .subclass = ((uint8_t)(reg8 >> 16)), }; - cb (pci_dev); + cb (pci_info); /* PCI 2 PCI bridge */ - if (pci_dev.classcode == 0x06 && pci_dev.subclass == 0x04) { + if (pci_info.class == 0x06 && pci_info.subclass == 0x04) { uint32_t reg18 = pci_read32 (bus, slot, func, 0x18); uint8_t secondary = (uint8_t)(reg18 >> 8); pci_check_bus (secondary, cb); @@ -112,13 +186,21 @@ static void pci_string_identifiers (uint16_t vendor_id, uint16_t device_id, uint } } -static void pci_discovery_cb (struct pci_dev pci_dev) { +static void pci_discovery_cb (struct pci_info pci_info) { const char *vname, *dname, *cname; - pci_string_identifiers (pci_dev.vendor, pci_dev.device, pci_dev.classcode, pci_dev.subclass, + pci_string_identifiers (pci_info.vendor, pci_info.device, pci_info.class, pci_info.subclass, &vname, &dname, &cname); - DEBUG ("PCI DEVICE: %04x:%04x at %02d:%02d:%02d / %s; %s; %s\n", pci_dev.vendor, pci_dev.device, - pci_dev.bus, pci_dev.slot, pci_dev.func, vname, dname, cname); + DEBUG ("PCI DEVICE: %04x:%04x %02x:%02x at %03d:%03d:%03d / %s; %s; %s\n", pci_info.vendor, + pci_info.device, pci_info.class, pci_info.subclass, pci_info.bus, pci_info.slot, + pci_info.func, vname, dname, cname); + + for (size_t driver = 0; driver < lengthof (pci_driver_infos); driver++) { + if (pci_driver_infos[driver].class == pci_info.class && + pci_driver_infos[driver].subclass == pci_info.subclass) { + pci_driver_infos[driver].init (pci_info); + } + } } void pci_init (void) { pci_enumerate (&pci_discovery_cb); } diff --git a/kernel/device/pci.h b/kernel/device/pci.h index 15166c6..3950171 100644 --- a/kernel/device/pci.h +++ b/kernel/device/pci.h @@ -1,6 +1,7 @@ #ifndef _KERNEL_DEVICE_PCI_H #define _KERNEL_DEVICE_PCI_H +#include #include #define PCI_CONFIG_ADDR 0xCF8 @@ -20,16 +21,6 @@ #define PCI_BIST 0x0F #define PCI_BAR0 0x10 -struct pci_dev { - uint8_t bus; - uint8_t slot; - uint8_t func; - uint16_t vendor; - uint16_t device; - uint8_t classcode; - uint8_t subclass; -}; - struct pci_vendor { uint16_t id; const char* name; @@ -47,10 +38,28 @@ struct pci_class { const char* name; }; -typedef void (*pci_cb_func_t) (struct pci_dev pci_dev); +struct pci_driver_info { + uint8_t class; + uint8_t subclass; + bool (*init) (struct pci_info pci_info); +}; + +typedef void (*pci_cb_func_t) (struct pci_info pci_info); void pci_init (void); +uint32_t pci_read32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset); + +void pci_write32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value); + +uint16_t pci_read16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset); + +void pci_write16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t value); + +uint8_t pci_read8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset); + +void pci_write8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t value); + extern const struct pci_vendor pci_vendors[]; extern const struct pci_device_id pci_device_names[]; diff --git a/kernel/device/pci_ide.c b/kernel/device/pci_ide.c new file mode 100644 index 0000000..10b6cb4 --- /dev/null +++ b/kernel/device/pci_ide.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static atomic_int ide_counter = 0; + +static const char* progif_msg[] = { + [0x00] = "ISA Compatibility mode-only controller", + [0x05] = "PCI native mode-only controller", + [0x0A] = + "ISA Compatibility mode controller, supports both channels switched to PCI native mode", + [0x0F] = + "PCI native mode controller, supports both channels switched to ISA compatibility mode", + [0x80] = "ISA Compatibility mode-only controller, supports bus mastering", + [0x85] = "PCI native mode-only controller, supports bus mastering", + [0x8A] = + "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering", + [0x8F] = + "PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering", +}; + +static void ide_make_device (struct ide_probe probe) { + DEBUG ("Found IDE drive: io=%x ctrl=%x no=%u sector=%zu count=%zu\n", probe.io, probe.ctrl, + probe.devno, probe.sector_size, probe.sector_count); + + char device_key[fieldsizeof (struct device, key)]; + snprintf (device_key, sizeof (device_key), "IDE%d", atomic_fetch_add (&ide_counter, 1)); + + device_op_func_t ops[] = { + [XDRV_GET_SIZE] = &idedrv_get_size, + [XDRV_GET_SECTOR_SIZE] = &idedrv_get_sector_size, + [XDRV_GET_DEVICE_TYPE] = &idedrv_get_device_type, + [XDRV_READ] = &idedrv_read, + [XDRV_WRITE] = &idedrv_write, + }; + + struct idedrv_init init = { + .lba48 = ((probe.flags & IDE_PROBE_LBA48) != 0), + .sector_count = probe.sector_count, + .sector_size = probe.sector_size, + .io = probe.io, + .ctrl = probe.ctrl, + .devno = probe.devno, + }; + device_create (device_key, ops, lengthof (ops), &idedrv_init, &idedrv_fini, &init); +} + +bool pci_ide_init (struct pci_info pci_info) { + struct ide_probe probe; + + uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF); + + DEBUG ("progif: %s\n", progif_msg[progif]); + + switch (progif) { + case 0x80: + ide_probe (0x1F0, 0x3F6, 0, &probe); + + if ((probe.flags & IDE_PROBE_AVAIL)) + ide_make_device (probe); + + ide_probe (0x1F0, 0x3F6, 1, &probe); + + if ((probe.flags & IDE_PROBE_AVAIL)) + ide_make_device (probe); + + ide_probe (0x170, 0x376, 0, &probe); + + if ((probe.flags & IDE_PROBE_AVAIL)) + ide_make_device (probe); + + ide_probe (0x170, 0x376, 1, &probe); + + if ((probe.flags & IDE_PROBE_AVAIL)) + ide_make_device (probe); + + break; + default: + DEBUG ("PCI unsupported progif=%02x\n", progif); + return false; + } + + return true; +} diff --git a/kernel/device/pci_ide.h b/kernel/device/pci_ide.h new file mode 100644 index 0000000..573700a --- /dev/null +++ b/kernel/device/pci_ide.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_DEVICE_PCI_IDE_H +#define _KERNEL_DEVICE_PCI_IDE_H + +#include +#include + +bool pci_ide_init (struct pci_info pci_info); + +#endif // _KERNEL_DEVICE_PCI_IDE_H diff --git a/kernel/device/pci_info.h b/kernel/device/pci_info.h new file mode 100644 index 0000000..51bea9a --- /dev/null +++ b/kernel/device/pci_info.h @@ -0,0 +1,16 @@ +#ifndef _KERNEL_DEVICE_PCI_INFO_H +#define _KERNEL_DEVICE_PCI_INFO_H + +#include + +struct pci_info { + uint8_t bus; + uint8_t slot; + uint8_t func; + uint16_t vendor; + uint16_t device; + uint8_t class; + uint8_t subclass; +}; + +#endif // _KERNEL_DEVICE_PCI_INFO_H diff --git a/kernel/device/src.mk b/kernel/device/src.mk index cf93965..05aaeb9 100644 --- a/kernel/device/src.mk +++ b/kernel/device/src.mk @@ -12,10 +12,14 @@ o += device/device.o \ ifeq ($(platform),amd64) c += device/ps2_kb.c \ + device/idedrv.c \ device/pci.c \ - device/pci_defs.c + device/pci_defs.c \ + device/pci_ide.c o += device/ps2_kb.o \ + device/idedrv.o \ device/pci.o \ - device/pci_defs.o + device/pci_defs.o \ + device/pci_ide.o endif diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 98152f1..657e08a 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,7 @@ int vfs_create_volume (const char* key, int fs_type, struct device* back_device, volume->lock = SPIN_LOCK_INIT; switch (volume->fs_type) { - case VFS_TARFS: + case FS_TARFS: volume->driver_ops.mount = &tarfs_mount; volume->driver_ops.format = &tarfs_format; volume->driver_ops.describe = &tarfs_describe; @@ -64,7 +65,7 @@ int vfs_create_volume (const char* key, int fs_type, struct device* back_device, volume->driver_ops.create_dir = &tarfs_create_dir; volume->driver_ops.remove = &tarfs_remove; break; - case VFS_FAT16: + case FS_FAT16: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.format = &fatfs16_format; volume->driver_ops.describe = &fatfs_describe; @@ -75,7 +76,7 @@ int vfs_create_volume (const char* key, int fs_type, struct device* back_device, volume->driver_ops.create_dir = &fatfs_create_dir; volume->driver_ops.remove = &fatfs_remove; break; - case VFS_FAT32: + case FS_FAT32: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.format = &fatfs32_format; volume->driver_ops.describe = &fatfs_describe; diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 096d926..a39ab67 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -17,10 +18,6 @@ #define VFS_KERNEL ((struct proc*)0x123) -#define VFS_TARFS 0 -#define VFS_FAT16 1 -#define VFS_FAT32 2 - struct vfs_volume; struct vfs_volume { diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 800dd17..a4e31ef 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -646,6 +646,46 @@ DEFINE_SYSCALL (sys_remove) { return SYSRESULT (ret); } +/* int create_volume (char* key, int fs_type, char* device_key) */ +DEFINE_SYSCALL (sys_create_volume) { + uintptr_t uvaddr_key = a1; + int type = (int)a2; + uintptr_t uvaddr_device_key = a3; + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->procgroup->lock); + + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_key); + + if (out_paddr == 0) { + spin_unlock (&proc->procgroup->lock); + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + } + + const char* key = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_device_key); + + if (out_paddr == 0) { + spin_unlock (&proc->procgroup->lock); + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + } + + const char* device_key = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + spin_unlock (&proc->procgroup->lock); + + struct device* device = device_find (device_key); + + if (device == NULL) + return SYSRESULT (-ST_NOT_FOUND); + + return SYSRESULT (vfs_create_volume (key, type, device, false)); +} + static syscall_handler_func_t handler_table[] = { [SYS_QUIT] = &sys_quit, [SYS_TEST] = &sys_test, @@ -675,6 +715,7 @@ static syscall_handler_func_t handler_table[] = { [SYS_KILL] = &sys_kill, [SYS_CREATE_DIR] = &sys_create_dir, [SYS_REMOVE] = &sys_remove, + [SYS_CREATE_VOLUME] = &sys_create_volume, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libsystem/str_status.h b/libsystem/str_status.h index 025b31f..8f591ec 100644 --- a/libsystem/str_status.h +++ b/libsystem/str_status.h @@ -24,6 +24,10 @@ static const char* str_status[] = { [ST_FORMAT_ERROR] = "filesystem formatting error", [ST_NOT_DRV] = "not a drive device", [ST_PARTITION_ERROR] = "partition error", + [ST_CREATE_DIR_ERROR] = "directory creation error", + [ST_REMOVE_ERROR] = "remove error", + [ST_XDRV_READ_ERROR] = "drive read error", + [ST_XDRV_WRITE_ERROR] = "drive write error", }; #endif // _LIBSYSTEM_STR_STATUS_H diff --git a/libsystem/system.c b/libsystem/system.c index 696345f..47b07a7 100644 --- a/libsystem/system.c +++ b/libsystem/system.c @@ -82,3 +82,7 @@ int kill (int pid) { return (int)do_syscall (SYS_KILL, pid); } int create_dir (const char* path) { return (int)do_syscall (SYS_CREATE_DIR, path); } int remove (const char* path) { return (int)do_syscall (SYS_REMOVE, path); } + +int create_volume (const char* key, int fs_type, const char* device_key) { + return (int)do_syscall (SYS_CREATE_VOLUME, key, fs_type, device_key); +} diff --git a/libsystem/system.h b/libsystem/system.h index 638059e..99c0d42 100644 --- a/libsystem/system.h +++ b/libsystem/system.h @@ -90,4 +90,7 @@ int create_dir (const char* path); /* Remove filesystem entry */ int remove (const char* path); +/* mount a volume */ +int create_volume (const char* key, int fs_type, const char* device_key); + #endif // _LIBMSL_M_SYSTEM_H diff --git a/testing/make_test_drive.sh b/testing/make_test_drive.sh new file mode 100755 index 0000000..51c7cc6 --- /dev/null +++ b/testing/make_test_drive.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# 50MiB +dd if=/dev/zero of=./test_drive.img bs=512 count=102400 +mkfs.vfat -F 32 ./test_drive.img