Implement an ATA driver, Add vfsmount/vfsunmount syscalls
This commit is contained in:
@ -219,13 +219,27 @@ int32_t littlefs_fetchdirent(struct VfsMountPoint *vmp, const char *path, IoctlD
|
||||
|
||||
int portlfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) {
|
||||
VfsMountPoint *vmp = c->context;
|
||||
vmp->backingsd->read(vmp->backingsd, buffer, size, block * LITTLEFS_BLOCK_SIZE + off);
|
||||
|
||||
uint64_t byteaddr = (uint64_t)block * c->block_size + off;
|
||||
ptrdiff_t sector = byteaddr / vmp->backingsd->sectorsize;
|
||||
ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize;
|
||||
|
||||
int32_t ret = vmp->backingsd->read(vmp->backingsd, (const uint8_t *)buffer, sector, sector_off, size);
|
||||
if (ret != E_OK)
|
||||
return LFS_ERR_IO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int portlfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) {
|
||||
VfsMountPoint *vmp = c->context;
|
||||
vmp->backingsd->write(vmp->backingsd, buffer, size, block * LITTLEFS_BLOCK_SIZE + off);
|
||||
|
||||
uint64_t byteaddr = (uint64_t)block * c->block_size + off;
|
||||
ptrdiff_t sector = byteaddr / vmp->backingsd->sectorsize;
|
||||
ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize;
|
||||
|
||||
int32_t ret = vmp->backingsd->write(vmp->backingsd, (const uint8_t *)buffer, sector, sector_off, size);
|
||||
if (ret != E_OK)
|
||||
return LFS_ERR_IO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "fs/littlefs/lfs.h"
|
||||
#include "sysdefs/ioctl.h"
|
||||
|
||||
#define LITTLEFS_BLOCK_SIZE 4096
|
||||
#define LITTLEFS_BLOCK_SIZE 512
|
||||
|
||||
struct VfsMountPoint;
|
||||
struct VfsObj;
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#define GDT_PRESENT 0x80
|
||||
#define GDT_TSS 0x89
|
||||
|
||||
#define KSTACK (1024*4*4096)
|
||||
#define KSTACK (1024*2*4096)
|
||||
ALIGNED(16) static uint8_t kernelstack[KSTACK];
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -26,3 +26,21 @@ uint32_t io_in32(uint16_t port) {
|
||||
void io_out32(uint16_t port, uint32_t value) {
|
||||
asm volatile("outl %%eax, %%dx" :: "d"(port), "a"(value));
|
||||
}
|
||||
|
||||
void io_ins16(uint16_t port, void *addr, int cnt) {
|
||||
asm volatile(
|
||||
"cld; rep insw"
|
||||
: "+D"(addr), "+c"(cnt)
|
||||
: "d"(port)
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
void io_outs16(uint16_t port, const void *addr, int cnt) {
|
||||
asm volatile(
|
||||
"cld; rep outsw"
|
||||
: "+S"(addr), "+c"(cnt)
|
||||
: "d"(port)
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
@ -12,4 +12,7 @@ void io_out16(uint16_t port, uint16_t value);
|
||||
uint32_t io_in32(uint16_t port);
|
||||
void io_out32(uint16_t port, uint32_t value);
|
||||
|
||||
void io_ins16(uint16_t port, void *addr, int cnt);
|
||||
void io_outs16(uint16_t port, const void *addr, int cnt);
|
||||
|
||||
#endif // HAL_IO_H_
|
||||
|
||||
@ -14,37 +14,6 @@
|
||||
#include "dev/dev.h"
|
||||
#include "randcrypto/randcrypto.h"
|
||||
|
||||
const char *human_size(uint64_t bytes, char *buf, size_t bufsize) {
|
||||
static const char *units[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
|
||||
int unit = 0;
|
||||
|
||||
// Scale down until value fits nicely
|
||||
uint64_t rem = 0;
|
||||
while (bytes >= 1024 && unit < (int)(sizeof(units)/sizeof(units[0])) - 1) {
|
||||
rem = bytes % 1024;
|
||||
bytes /= 1024;
|
||||
unit++;
|
||||
}
|
||||
|
||||
if (unit == 0) {
|
||||
// Just bytes
|
||||
ksnprintf(buf, bufsize, "%llu %s", (unsigned long long)bytes, units[unit]);
|
||||
} else {
|
||||
// Show one decimal place without using floats
|
||||
// Multiply remainder by 10 to get first decimal digit
|
||||
uint64_t frac = (rem * 10 + 512) / 1024; // rounded
|
||||
if (frac == 10) { // handle carry, e.g. 1023.9 -> 1024.0
|
||||
bytes++;
|
||||
frac = 0;
|
||||
}
|
||||
|
||||
if (frac > 0) ksnprintf(buf, bufsize, "%llu.%llu %s", (unsigned long long)bytes, (unsigned long long)frac, units[unit]);
|
||||
else ksnprintf(buf, bufsize, "%llu %s", (unsigned long long)bytes, units[unit]);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void log_bootinfo(void) {
|
||||
char buf[100];
|
||||
LOG("kmain", "Memory total = %s\n", human_size(BOOT_INFO.memmap_total, buf, sizeof(buf)));
|
||||
|
||||
223
kernel/storedev/atasd.c
Normal file
223
kernel/storedev/atasd.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "atasd.h"
|
||||
#include "storedev.h"
|
||||
#include "hal/hal.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
#include "errors.h"
|
||||
#include "hshtb.h"
|
||||
#include "vfs/vfs.h"
|
||||
|
||||
#define ATA_REG_DATA 0x1f0
|
||||
#define ATA_REG_ERROR 0x1f1
|
||||
#define ATA_REG_SECCOUNT0 0x1f2
|
||||
#define ATA_REG_LBA0 0x1f3
|
||||
#define ATA_REG_LBA1 0x1f4
|
||||
#define ATA_REG_LBA2 0x1f5
|
||||
#define ATA_REG_DRIVE 0x1f6
|
||||
#define ATA_REG_STATUS 0x1f7
|
||||
#define ATA_REG_COMMAND 0x1f7
|
||||
#define ATA_REG_CTRL 0x3f6
|
||||
|
||||
#define ATA_BSY 0x80
|
||||
#define ATA_DRDY 0x40
|
||||
#define ATA_DF 0x20
|
||||
#define ATA_ERR 0x01
|
||||
#define ATA_DRQ 0x08
|
||||
|
||||
#define ATA_CMD_READ_PIO_EXT 0x24
|
||||
#define ATA_CMD_WRITE_PIO_EXT 0x34
|
||||
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
|
||||
#define ATA_MASTER 0x00
|
||||
#define ATA_SLAVE 0x01
|
||||
|
||||
int ata_wait(uint32_t timeout, bool require_drq, int checkerr) {
|
||||
uint32_t i = 0;
|
||||
uint8_t st;
|
||||
for(;;) {
|
||||
st = io_in8(ATA_REG_STATUS);
|
||||
if (!(st & ATA_BSY))
|
||||
break;
|
||||
if (++i >= timeout)
|
||||
return -1;
|
||||
}
|
||||
if (require_drq) {
|
||||
i = 0;
|
||||
while (!(st & ATA_DRQ)) {
|
||||
if (st & ATA_ERR)
|
||||
return -1;
|
||||
st = io_in8(ATA_REG_STATUS);
|
||||
if (++i >= timeout)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (checkerr && (st & (ATA_DF | ATA_ERR)))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ata_delay400ns(void) {
|
||||
io_in8(ATA_REG_CTRL);
|
||||
io_in8(ATA_REG_CTRL);
|
||||
io_in8(ATA_REG_CTRL);
|
||||
io_in8(ATA_REG_CTRL);
|
||||
}
|
||||
|
||||
// caller must synchronize
|
||||
uint64_t ata_probesize_bytes(int devno) {
|
||||
uint16_t identifydata[0x100];
|
||||
|
||||
io_out8(ATA_REG_DRIVE, 0xA0 | (devno << 4));
|
||||
ata_delay400ns();
|
||||
|
||||
io_out8(ATA_REG_SECCOUNT0, 0);
|
||||
io_out8(ATA_REG_LBA0, 0);
|
||||
io_out8(ATA_REG_LBA1, 0);
|
||||
io_out8(ATA_REG_LBA2, 0);
|
||||
|
||||
io_out8(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
||||
|
||||
if (ata_wait(100000, false, 0) < 0)
|
||||
return 0;
|
||||
|
||||
uint8_t st = io_in8(ATA_REG_STATUS);
|
||||
if (st == 0)
|
||||
return 0;
|
||||
|
||||
if (ata_wait(100000, true, 1) < 0)
|
||||
return 0;
|
||||
|
||||
io_ins16(ATA_REG_DATA, identifydata, 256);
|
||||
|
||||
bool lba48 = (identifydata[83] & (1<<10)) != 0;
|
||||
if (lba48) {
|
||||
uint64_t sectors = (uint64_t)identifydata[100]
|
||||
| ((uint64_t)identifydata[101] << 16)
|
||||
| ((uint64_t)identifydata[102] << 32)
|
||||
| ((uint64_t)identifydata[103] << 48);
|
||||
return sectors * (uint64_t)STOREDEV_ATASD_SECTORSIZE;
|
||||
} else {
|
||||
uint64_t sectors = (uint64_t)identifydata[60]
|
||||
| ((uint64_t)identifydata[61] << 16);
|
||||
return sectors * (uint64_t)STOREDEV_ATASD_SECTORSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ata_probe1(int drive) {
|
||||
io_out8(ATA_REG_DRIVE, 0xA0 | (drive << 4));
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
uint8_t status = io_in8(ATA_REG_STATUS);
|
||||
if (status != 0 && status != 0xFF)
|
||||
return true; // got something
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ata_probe(void) {
|
||||
if (ata_probe1(ATA_MASTER)) {
|
||||
uint64_t probesize = ata_probesize_bytes(ATA_MASTER);
|
||||
|
||||
char hs[20];
|
||||
LOG("ata", "found ATA Master, size = %s\n", human_size(probesize, hs, sizeof(hs)));
|
||||
|
||||
AtaSdInitExtra extra = {
|
||||
.devno = ATA_MASTER,
|
||||
.capacity = probesize,
|
||||
};
|
||||
StoreDev *sd = storedev_create(STOREDEV_ATASD, (void *)&extra);
|
||||
}
|
||||
}
|
||||
|
||||
void ata_setup(int devno, uint16_t sectors, uint64_t lba) {
|
||||
io_out8(ATA_REG_CTRL, 0x02);
|
||||
|
||||
io_out8(ATA_REG_DRIVE, 0x40 | (devno << 4));
|
||||
ata_delay400ns();
|
||||
|
||||
io_out8(ATA_REG_SECCOUNT0, (sectors >> 8) & 0xFF);
|
||||
io_out8(ATA_REG_LBA0, (lba >> 24) & 0xFF);
|
||||
io_out8(ATA_REG_LBA1, (lba >> 32) & 0xFF);
|
||||
io_out8(ATA_REG_LBA2, (lba >> 40) & 0xFF);
|
||||
|
||||
io_out8(ATA_REG_SECCOUNT0, sectors & 0xFF);
|
||||
io_out8(ATA_REG_LBA0, (uint8_t)(lba & 0xFF));
|
||||
io_out8(ATA_REG_LBA1, (uint8_t)((lba >> 8) & 0xFF));
|
||||
io_out8(ATA_REG_LBA2, (uint8_t)((lba >> 16) & 0xFF));
|
||||
|
||||
}
|
||||
|
||||
int32_t atasd_init(struct StoreDev *sd, void *extra) {
|
||||
AtaSdInitExtra *e = (AtaSdInitExtra *)extra;
|
||||
sd->sd.atasd.devno = e->devno;
|
||||
sd->sd.atasd.capacity = e->capacity;
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t atasd_read(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size) {
|
||||
int32_t ret;
|
||||
spinlock_acquire(&sd->spinlock);
|
||||
|
||||
AtaSd *ata = &sd->sd.atasd;
|
||||
|
||||
uint64_t lba = (uint64_t)(sector * (ptrdiff_t)sd->sectorsize + off) / (uint64_t)STOREDEV_ATASD_SECTORSIZE;
|
||||
size_t sectors = size / STOREDEV_ATASD_SECTORSIZE;
|
||||
if (size % STOREDEV_ATASD_SECTORSIZE) sectors++;
|
||||
|
||||
ata_setup(ata->devno, sectors, lba);
|
||||
io_out8(ATA_REG_COMMAND, ATA_CMD_READ_PIO_EXT);
|
||||
|
||||
for (size_t s = 0; s < sectors; s++) {
|
||||
if (ata_wait(100000, true, 1) < 0) { ret = E_BADIO; goto done; }
|
||||
io_ins16(ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2);
|
||||
}
|
||||
|
||||
ret = E_OK;
|
||||
|
||||
done:
|
||||
spinlock_release(&sd->spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t atasd_write(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size) {
|
||||
int32_t ret;
|
||||
spinlock_acquire(&sd->spinlock);
|
||||
|
||||
AtaSd *ata = &sd->sd.atasd;
|
||||
|
||||
uint64_t lba = (uint64_t)(sector * (ptrdiff_t)sd->sectorsize + off) / (uint64_t)STOREDEV_ATASD_SECTORSIZE;
|
||||
size_t sectors = size / STOREDEV_ATASD_SECTORSIZE;
|
||||
if (size % STOREDEV_ATASD_SECTORSIZE) sectors++;
|
||||
|
||||
ata_setup(ata->devno, sectors, lba);
|
||||
io_out8(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT);
|
||||
|
||||
for (size_t s = 0; s < sectors; s++) {
|
||||
if (ata_wait(100000, true, 1) < 0) { ret = E_BADIO; goto done; }
|
||||
io_outs16(ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2);
|
||||
}
|
||||
|
||||
io_out8(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH_EXT);
|
||||
if (ata_wait(100000, false, 1) < 0) { ret = E_BADIO; goto done; }
|
||||
|
||||
ret = E_OK;
|
||||
|
||||
done:
|
||||
spinlock_release(&sd->spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t atasd_cleanup(struct StoreDev *sd) {
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
size_t atasd_capacity(struct StoreDev *sd) {
|
||||
size_t c = 0;
|
||||
spinlock_acquire(&sd->spinlock);
|
||||
c = sd->sd.atasd.capacity;
|
||||
spinlock_release(&sd->spinlock);
|
||||
return c;
|
||||
}
|
||||
30
kernel/storedev/atasd.h
Normal file
30
kernel/storedev/atasd.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef STOREDEV_ATASD_H_
|
||||
#define STOREDEV_ATASD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define STOREDEV_ATASD_SECTORSIZE 512
|
||||
|
||||
struct StoreDev;
|
||||
|
||||
typedef struct {
|
||||
int devno;
|
||||
size_t capacity;
|
||||
} AtaSdInitExtra;
|
||||
|
||||
typedef struct {
|
||||
int devno;
|
||||
size_t capacity;
|
||||
} AtaSd;
|
||||
|
||||
int32_t atasd_init(struct StoreDev *sd, void *extra);
|
||||
int32_t atasd_read(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t atasd_write(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t atasd_cleanup(struct StoreDev *sd);
|
||||
size_t atasd_capacity(struct StoreDev *sd);
|
||||
|
||||
void ata_probe(void);
|
||||
|
||||
#endif // STOREDEV_ATASD_H_
|
||||
@ -23,16 +23,18 @@ int32_t ramsd_init(struct StoreDev *sd, void *extra) {
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t ramsd_read(struct StoreDev *sd, uint8_t *const buffer, size_t n, size_t off) {
|
||||
int32_t ramsd_read(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size) {
|
||||
RamSd *ramsd = &sd->sd.ramsd;
|
||||
spinlock_acquire(&sd->spinlock);
|
||||
hal_memcpy(buffer, sd->sd.ramsd.buffer + off, MIN(n, sd->sd.ramsd.capacity - off));
|
||||
hal_memcpy(buffer, ramsd->buffer + (sector * sd->sectorsize + off), size);
|
||||
spinlock_release(&sd->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t ramsd_write(struct StoreDev *sd, const uint8_t *const buffer, size_t n, size_t off) {
|
||||
int32_t ramsd_write(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size) {
|
||||
RamSd *ramsd = &sd->sd.ramsd;
|
||||
spinlock_acquire(&sd->spinlock);
|
||||
hal_memcpy(sd->sd.ramsd.buffer + off, buffer, MIN(n, sd->sd.ramsd.capacity - off));
|
||||
hal_memcpy(ramsd->buffer + (sector * sd->sectorsize + off), buffer, size);
|
||||
spinlock_release(&sd->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define STOREDEV_RAMSD_SECTORSIZE 512
|
||||
|
||||
struct StoreDev;
|
||||
|
||||
typedef struct {
|
||||
@ -17,8 +19,8 @@ typedef struct {
|
||||
} RamSdInitExtra;
|
||||
|
||||
int32_t ramsd_init(struct StoreDev *sd, void *extra);
|
||||
int32_t ramsd_read(struct StoreDev *sd, uint8_t *const buffer, size_t n, size_t off);
|
||||
int32_t ramsd_write(struct StoreDev *sd, const uint8_t *const buffer, size_t n, size_t off);
|
||||
int32_t ramsd_read(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t ramsd_write(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t ramsd_cleanup(struct StoreDev *sd);
|
||||
size_t ramsd_capacity(struct StoreDev *sd);
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "errors.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "ramsd.h"
|
||||
#include "atasd.h"
|
||||
#include "util/util.h"
|
||||
#include "dev/dev.h"
|
||||
#include "hshtb.h"
|
||||
@ -19,16 +20,20 @@ void storedev_init(void) {
|
||||
STOREDEV_LIST.head = NULL;
|
||||
|
||||
LOG("storedev", "init\n");
|
||||
|
||||
ata_probe();
|
||||
}
|
||||
|
||||
void storedev_register_dev_entry(StoreDev *sd, int32_t sdtype) {
|
||||
char uniq[5];
|
||||
randcrypto_gen_uniqid(uniq, 4);
|
||||
|
||||
char key[20];
|
||||
hal_memset(key, 0, sizeof(key));
|
||||
|
||||
if (sdtype == STOREDEV_RAMSD) {
|
||||
char uniq[5];
|
||||
randcrypto_gen_uniqid(uniq, 4);
|
||||
ksprintf(key, "ramsd-%s", uniq);
|
||||
} else if (sdtype == STOREDEV_ATASD) {
|
||||
ksprintf(key, "atasd-%s", sd->sd.atasd.devno == 0x00 ? "mst" : "slv");
|
||||
}
|
||||
|
||||
spinlock_acquire(&DEVTABLE.spinlock);
|
||||
@ -70,18 +75,29 @@ StoreDev *storedev_create(int32_t sdtype, void *extra) {
|
||||
sd->read = &ramsd_read;
|
||||
sd->write = &ramsd_write;
|
||||
sd->capacity = &ramsd_capacity;
|
||||
|
||||
int32_t err = sd->init(sd, extra);
|
||||
if (err != E_OK) {
|
||||
spinlock_release(&STOREDEV_LIST.spinlock);
|
||||
return NULL;
|
||||
}
|
||||
LL_APPEND(STOREDEV_LIST.head, sd);
|
||||
sd->sectorsize = STOREDEV_RAMSD_SECTORSIZE;
|
||||
} break;
|
||||
case STOREDEV_ATASD: {
|
||||
spinlock_init(&sd->spinlock);
|
||||
sd->sdtype = STOREDEV_ATASD;
|
||||
sd->init = &atasd_init;
|
||||
sd->cleanup = &atasd_cleanup;
|
||||
sd->read = &atasd_read;
|
||||
sd->write = &atasd_write;
|
||||
sd->capacity = &atasd_capacity;
|
||||
sd->sectorsize = STOREDEV_ATASD_SECTORSIZE;
|
||||
} break;
|
||||
default:
|
||||
spinlock_release(&STOREDEV_LIST.spinlock);
|
||||
return NULL;
|
||||
}
|
||||
int32_t err = sd->init(sd, extra);
|
||||
if (err != E_OK) {
|
||||
dlfree(sd);
|
||||
spinlock_release(&STOREDEV_LIST.spinlock);
|
||||
return NULL;
|
||||
}
|
||||
LL_APPEND(STOREDEV_LIST.head, sd);
|
||||
spinlock_release(&STOREDEV_LIST.spinlock);
|
||||
|
||||
storedev_register_dev_entry(sd, sdtype);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <stddef.h>
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "ramsd.h"
|
||||
#include "atasd.h"
|
||||
#include "compiler/attr.h"
|
||||
#include "dev/dev.h"
|
||||
|
||||
@ -12,25 +13,28 @@
|
||||
|
||||
enum {
|
||||
STOREDEV_RAMSD,
|
||||
STOREDEV_ATASD,
|
||||
};
|
||||
|
||||
UNUSED static const char *storedev_strings[] = {
|
||||
"RAMSD",
|
||||
"RAMSD", "ATASD"
|
||||
};
|
||||
|
||||
typedef struct StoreDev {
|
||||
uint32_t _magic;
|
||||
struct StoreDev *next;
|
||||
int32_t sdtype;
|
||||
size_t sectorsize;
|
||||
|
||||
int32_t (*init)(struct StoreDev *sd, void *extra);
|
||||
int32_t (*read)(struct StoreDev *sd, uint8_t *const buffer, size_t n, size_t off);
|
||||
int32_t (*write)(struct StoreDev *sd, const uint8_t *const buffer, size_t n, size_t off);
|
||||
int32_t (*read)(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t (*write)(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t sector, ptrdiff_t off, size_t size);
|
||||
int32_t (*cleanup)(struct StoreDev *sd);
|
||||
size_t (*capacity)(struct StoreDev *sd);
|
||||
|
||||
union {
|
||||
RamSd ramsd;
|
||||
AtaSd atasd;
|
||||
} sd;
|
||||
SpinLock spinlock;
|
||||
} StoreDev;
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "sched.h"
|
||||
#include "devctl.h"
|
||||
#include "randcrypto.h"
|
||||
#include "vfs.h"
|
||||
|
||||
int32_t SYSCALL1(sys_debugprint, string) {
|
||||
char *p = (char *)string;
|
||||
@ -27,4 +28,6 @@ SyscallFn SYSCALL_TABLE[SYSCALLS_MAX] = {
|
||||
[SYS_SCHEDRELEASE] = &sys_schedrelease,
|
||||
[SYS_DEVCTL] = &sys_devctl,
|
||||
[SYS_RAND] = &sys_rand,
|
||||
[SYS_VFSMOUNT] = &sys_vfsmount,
|
||||
[SYS_VFSUNMOUNT] = &sys_vfsunmount,
|
||||
};
|
||||
|
||||
63
kernel/syscall/vfs.c
Normal file
63
kernel/syscall/vfs.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/hal.h"
|
||||
#include "syscall.h"
|
||||
#include "vfs.h"
|
||||
#include "errors.h"
|
||||
#include "sysdefs/devctl.h"
|
||||
#include "vfs/vfs.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "dev/dev.h"
|
||||
#include "proc/proc.h"
|
||||
#include "storedev/storedev.h"
|
||||
|
||||
int32_t SYSCALL4(sys_vfsmount, mountpoint1, fstypestr1, devid1, format1) {
|
||||
int32_t ret = E_OK;
|
||||
char *mountpoint = (char *)mountpoint1;
|
||||
char *fstypestr = (char *)fstypestr1;
|
||||
Dev_t *dev = (Dev_t *)devid1;
|
||||
bool format = (bool)format1;
|
||||
|
||||
if (mountpoint == NULL) { ret = E_INVALIDARGUMENT; goto done; }
|
||||
if (fstypestr == NULL) { ret = E_INVALIDARGUMENT; goto done; }
|
||||
if (dev == NULL) { ret = E_INVALIDARGUMENT; goto done; }
|
||||
|
||||
if (*dev >= PROC_DEVHANDLES_MAX) { ret = E_INVALIDARGUMENT; goto done; }
|
||||
|
||||
int32_t fstype;
|
||||
|
||||
if (hal_strcmp(fstypestr, "LittleFS") == 0) {
|
||||
fstype = VFS_LITTLEFS;
|
||||
} else {
|
||||
ret = E_INVALIDARGUMENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc = PROCS.current;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
Dev *dp = proc->devs[*dev];
|
||||
if (dp == NULL) { ret = E_NOENTRY; goto done; }
|
||||
|
||||
StoreDev *sd = (StoreDev *)dp->extra;
|
||||
if (sd != NULL && sd->_magic != STOREDEV_MAGIC) { ret = E_NOENTRY; goto done; }
|
||||
|
||||
ret = vfs_mount(mountpoint, fstype, sd, format);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t SYSCALL1(sys_vfsunmount, mountpoint1) {
|
||||
int32_t ret = E_OK;
|
||||
char *mountpoint = (char *)mountpoint1;
|
||||
|
||||
if (mountpoint == NULL) { ret = E_INVALIDARGUMENT; goto done; }
|
||||
|
||||
ret = vfs_unmount(mountpoint);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
11
kernel/syscall/vfs.h
Normal file
11
kernel/syscall/vfs.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef SYSCALL_VFS_H_
|
||||
#define SYSCALL_VFS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "syscall.h"
|
||||
|
||||
int32_t SYSCALL4(sys_vfsmount, mountpoint1, fstypestr1, devid1, format1);
|
||||
int32_t SYSCALL1(sys_vfsunmount, mountpoint1);
|
||||
|
||||
#endif // SYSCALL_VFS_H_
|
||||
@ -1,3 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "kprintf.h"
|
||||
#include "util.h"
|
||||
|
||||
char *util_get_filename(char *path) {
|
||||
@ -13,3 +16,33 @@ char *util_get_filename(char *path) {
|
||||
return lastslash;
|
||||
}
|
||||
|
||||
const char *human_size(uint64_t bytes, char *buf, size_t bufsize) {
|
||||
static const char *units[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
|
||||
int unit = 0;
|
||||
|
||||
// Scale down until value fits nicely
|
||||
uint64_t rem = 0;
|
||||
while (bytes >= 1024 && unit < (int)(sizeof(units)/sizeof(units[0])) - 1) {
|
||||
rem = bytes % 1024;
|
||||
bytes /= 1024;
|
||||
unit++;
|
||||
}
|
||||
|
||||
if (unit == 0) {
|
||||
// Just bytes
|
||||
ksnprintf(buf, bufsize, "%llu %s", (unsigned long long)bytes, units[unit]);
|
||||
} else {
|
||||
// Show one decimal place without using floats
|
||||
// Multiply remainder by 10 to get first decimal digit
|
||||
uint64_t frac = (rem * 10 + 512) / 1024; // rounded
|
||||
if (frac == 10) { // handle carry, e.g. 1023.9 -> 1024.0
|
||||
bytes++;
|
||||
frac = 0;
|
||||
}
|
||||
|
||||
if (frac > 0) ksnprintf(buf, bufsize, "%llu.%llu %s", (unsigned long long)bytes, (unsigned long long)frac, units[unit]);
|
||||
else ksnprintf(buf, bufsize, "%llu %s", (unsigned long long)bytes, units[unit]);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
#ifndef UTIL_UTIL_H_
|
||||
#define UTIL_UTIL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define _DIV_ROUNDUP(num, div) ((num + div - 1) / div)
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
@ -74,5 +77,6 @@
|
||||
var = tmp, tmp = (var ? var->next : NULL), (idx)++)
|
||||
|
||||
char *util_get_filename(char *path);
|
||||
const char *human_size(uint64_t bytes, char *buf, size_t bufsize);
|
||||
|
||||
#endif // UTIL_UTIL_H_
|
||||
|
||||
@ -25,11 +25,11 @@ void vfs_init_littlefs(VfsMountPoint *mp, bool format) {
|
||||
cfg->sync = &portlfs_sync;
|
||||
cfg->block_size = LITTLEFS_BLOCK_SIZE;
|
||||
cfg->block_count = mp->backingsd->capacity(mp->backingsd) / LITTLEFS_BLOCK_SIZE;
|
||||
cfg->read_size = 64;
|
||||
cfg->prog_size = 64;
|
||||
cfg->read_size = LITTLEFS_BLOCK_SIZE;
|
||||
cfg->prog_size = LITTLEFS_BLOCK_SIZE;
|
||||
cfg->block_cycles = 16;
|
||||
cfg->cache_size = 64;
|
||||
cfg->lookahead_size = 64;
|
||||
cfg->cache_size = LITTLEFS_BLOCK_SIZE;
|
||||
cfg->lookahead_size = LITTLEFS_BLOCK_SIZE;
|
||||
cfg->read_buffer = NULL;
|
||||
cfg->prog_buffer = NULL;
|
||||
cfg->lookahead_buffer = NULL;
|
||||
|
||||
Reference in New Issue
Block a user