diff --git a/include/syscall_defs.h b/include/syscall_defs.h index c3ebaf1..35cad7c 100644 --- a/include/syscall_defs.h +++ b/include/syscall_defs.h @@ -39,5 +39,7 @@ #define SYS_STREAM_READ 36 #define SYS_GET_PROC_INFO 37 #define SYS_GET_DEVICE_INFO 38 +#define SYS_GET_VOLUME_INFO 39 +#define SYS_VOLUME_DELETE 40 #endif // _M_SYSCALL_DEFS_H diff --git a/include/volume_info.h b/include/volume_info.h new file mode 100644 index 0000000..b8b55d0 --- /dev/null +++ b/include/volume_info.h @@ -0,0 +1,11 @@ +#ifndef _VOLUME_INFO_H +#define _VOLUME_INFO_H + +#include + +struct volume_info { + char volume_name[VOLUME_MAX]; + char device_key[0x100]; +}; + +#endif // _VOLUME_INFO_H diff --git a/kernel/fs/def_vfs_op.h b/kernel/fs/def_vfs_op.h index 35007a9..28826af 100644 --- a/kernel/fs/def_vfs_op.h +++ b/kernel/fs/def_vfs_op.h @@ -7,6 +7,8 @@ int name (struct vfs_volume* UNUSED volume, struct proc* UNUSED proc, \ struct reschedule_ctx* UNUSED rctx, bool UNUSED format) +#define DEFINE_VFS_UNMOUNT(name) int name (struct vfs_volume* UNUSED volume) + #define DEFINE_VFS_FORMAT(name) \ int name (struct vfs_volume* UNUSED volume, struct proc* UNUSED proc, \ struct reschedule_ctx* UNUSED rctx) diff --git a/kernel/fs/fatfs.c b/kernel/fs/fatfs.c index 596e2c7..86306b7 100644 --- a/kernel/fs/fatfs.c +++ b/kernel/fs/fatfs.c @@ -122,6 +122,14 @@ DEFINE_VFS_MOUNT (fatfs_mount) { return ST_OK; } +DEFINE_VFS_UNMOUNT (fatfs_unmount) { + struct fatfs_ctx* fatfs_ctx = volume->udata; + + free (fatfs_ctx); + + return ST_OK; +} + DEFINE_VFS_FORMAT (fatfs16_format) { uint64_t fd; diff --git a/kernel/fs/fatfs.h b/kernel/fs/fatfs.h index 582b924..91c5824 100644 --- a/kernel/fs/fatfs.h +++ b/kernel/fs/fatfs.h @@ -13,6 +13,8 @@ struct vfs_volume; DEFINE_VFS_MOUNT (fatfs_mount); +DEFINE_VFS_UNMOUNT (fatfs_unmount); + DEFINE_VFS_FORMAT (fatfs16_format); DEFINE_VFS_FORMAT (fatfs32_format); diff --git a/kernel/fs/iso9660fs.c b/kernel/fs/iso9660fs.c index 7cb4cab..32b2d54 100644 --- a/kernel/fs/iso9660fs.c +++ b/kernel/fs/iso9660fs.c @@ -145,6 +145,14 @@ DEFINE_VFS_MOUNT (iso9660fs_mount) { return ST_OK; } +DEFINE_VFS_UNMOUNT (iso9660fs_unmount) { + l9660_fs* fs_ctx = volume->udata; + + free (fs_ctx); + + return ST_OK; +} + DEFINE_VFS_FORMAT (iso9660fs_format) { return -ST_FORMAT_ERROR; } DEFINE_VFS_DESCRIBE (iso9660fs_describe) { diff --git a/kernel/fs/iso9660fs.h b/kernel/fs/iso9660fs.h index 69f17b6..362c4a7 100644 --- a/kernel/fs/iso9660fs.h +++ b/kernel/fs/iso9660fs.h @@ -13,6 +13,8 @@ struct vfs_volume; DEFINE_VFS_MOUNT (iso9660fs_mount); +DEFINE_VFS_UNMOUNT (iso9660fs_unmount); + DEFINE_VFS_FORMAT (iso9660fs_format); DEFINE_VFS_DESCRIBE (iso9660fs_describe); diff --git a/kernel/fs/tarfs.c b/kernel/fs/tarfs.c index 56a0dac..4fb073a 100644 --- a/kernel/fs/tarfs.c +++ b/kernel/fs/tarfs.c @@ -128,6 +128,14 @@ DEFINE_VFS_MOUNT (tarfs_mount) { return ret; } +DEFINE_VFS_UNMOUNT (tarfs_unmount) { + struct tarfs* tarfs = volume->udata; + + free (tarfs); + + return ST_OK; +} + DEFINE_VFS_FORMAT (tarfs_format) { return ST_OK; } DEFINE_VFS_DESCRIBE (tarfs_describe) { diff --git a/kernel/fs/tarfs.h b/kernel/fs/tarfs.h index 9f2dc8d..54704d3 100644 --- a/kernel/fs/tarfs.h +++ b/kernel/fs/tarfs.h @@ -37,6 +37,8 @@ struct vfs_volume; DEFINE_VFS_MOUNT (tarfs_mount); +DEFINE_VFS_UNMOUNT (tarfs_unmount); + DEFINE_VFS_FORMAT (tarfs_format); DEFINE_VFS_DESCRIBE (tarfs_describe); diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 9e9978b..949c43d 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -19,9 +19,46 @@ #include #include #include +#include static struct vfs_volume_table volume_table; +size_t volume_populate_volume_infos (struct volume_info* infos, size_t count) { + uint64_t fvt, fv, fd; + + if (count >= lengthof (volume_table.volume_buckets)) + count = lengthof (volume_table.volume_buckets); + + spin_lock (&volume_table.lock, &fvt); + + size_t j = 0; + + for (size_t i = 0; i < lengthof (volume_table.volume_buckets); i++) { + struct hash_node_link* hash_link = volume_table.volume_buckets[i]; + + while (hash_link != NULL && j < count) { + struct vfs_volume* volume = hash_entry (hash_link, struct vfs_volume, volume_table_link); + struct volume_info* info = &infos[j]; + + spin_lock (&volume->lock, &fv); + spin_lock (&volume->back_device->lock, &fd); + + memcpy (info->volume_name, volume->key, sizeof (info->volume_name)); + memcpy (info->device_key, volume->back_device->key, sizeof (info->device_key)); + + spin_unlock (&volume->back_device->lock, fd); + spin_unlock (&volume->lock, fv); + + hash_link = hash_link->next; + j++; + } + } + + spin_unlock (&volume_table.lock, fvt); + + return j; +} + static struct vfs_volume* vfs_find_volume (const char* volume) { uint64_t fvt; @@ -62,6 +99,7 @@ int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const cha switch (volume->fs_type) { case FS_TARFS: volume->driver_ops.mount = &tarfs_mount; + volume->driver_ops.unmount = &tarfs_unmount; volume->driver_ops.format = &tarfs_format; volume->driver_ops.describe = &tarfs_describe; volume->driver_ops.read_file = &tarfs_read_file; @@ -73,6 +111,7 @@ int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const cha break; case FS_FAT16: volume->driver_ops.mount = &fatfs_mount; + volume->driver_ops.unmount = &fatfs_unmount; volume->driver_ops.format = &fatfs16_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; @@ -84,6 +123,7 @@ int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const cha break; case FS_FAT32: volume->driver_ops.mount = &fatfs_mount; + volume->driver_ops.unmount = &fatfs_unmount; volume->driver_ops.format = &fatfs32_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; @@ -95,6 +135,7 @@ int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const cha break; case FS_ISO9660: volume->driver_ops.mount = &iso9660fs_mount; + volume->driver_ops.unmount = &iso9660fs_unmount; volume->driver_ops.format = &iso9660fs_format; volume->driver_ops.describe = &iso9660fs_describe; volume->driver_ops.read_file = &iso9660fs_read_file; @@ -128,6 +169,52 @@ int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const cha return ST_OK; } +int vfs_volume_delete (const char* key) { + uint64_t fv, fvt; + + struct hash_node_link* found_link = NULL; + size_t key_len = strlen_null (key); + uint32_t hash = hash_fnv32 (key, key_len); + + spin_lock (&volume_table.lock, &fvt); + + hash_find (&volume_table, key, key_len, hash, lengthof (volume_table.volume_buckets), + volume_buckets, struct vfs_volume, volume_table_link, key, found_link); + + if (found_link == NULL) { + spin_unlock (&volume_table.lock, fvt); + return -ST_NOT_FOUND; + } + + struct vfs_volume* volume = hash_entry (found_link, struct vfs_volume, volume_table_link); + + if (volume == NULL) { + spin_unlock (&volume_table.lock, fvt); + return -ST_NOT_FOUND; + } + + spin_lock (&volume->lock, &fv); + + if (volume->locked) { + spin_unlock (&volume->lock, fv); + spin_unlock (&volume_table.lock, fvt); + return -ST_TRY_AGAIN; + } + + hash_delete (&volume_table, key, strlen_null (key), hash, lengthof (volume_table.volume_buckets), + volume_buckets, struct vfs_volume, volume_table_link, key, found_link); + + int ret = volume->driver_ops.unmount (volume); + + spin_unlock (&volume->lock, fv); + + free (volume); + + spin_unlock (&volume_table.lock, fvt); + + return ret; +} + int vfs_volume_open (struct proc* proc, const char* volume_name, struct reschedule_ctx* rctx) { uint64_t fv; diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 1ad4db7..7d550ae 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -15,6 +15,7 @@ #include #include #include +#include struct vfs_volume; @@ -30,6 +31,8 @@ struct vfs_volume { int (*mount) (struct vfs_volume* volume, struct proc* proc, struct reschedule_ctx* rctx, bool format); + int (*unmount) (struct vfs_volume* volume); + int (*format) (struct vfs_volume* volume, struct proc* proc, struct reschedule_ctx* rctx); int (*describe) (struct vfs_volume* volume, struct proc* proc, struct reschedule_ctx* rctx, @@ -66,6 +69,8 @@ struct vfs_volume_table { int vfs_create_volume (struct proc* proc, struct reschedule_ctx* rctx, const char* key, int fs_type, struct device* back_device, bool format); +int vfs_volume_delete (const char* key); + int vfs_volume_open (struct proc* proc, const char* volume, struct reschedule_ctx* rctx); int vfs_volume_close (struct proc* proc, const char* volume, struct reschedule_ctx* rctx); @@ -98,4 +103,6 @@ void vfs_init (void); void vfs_translate (size_t fs_block, size_t fs_block_count, size_t fs_block_size, size_t device_sector_size, size_t* out_phys_sector, size_t* out_sector_count); +size_t volume_populate_volume_infos (struct volume_info* infos, size_t count); + #endif // _KERNEL_FS_VFS_H diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index f32e7f2..c30e070 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #define DEFINE_SYSCALL(name) \ @@ -1097,6 +1098,57 @@ DEFINE_SYSCALL (sys_get_device_info) { return SYSRESULT (device_populate_device_infos (infos, infos_count)); } +/* int get_volume_info (struct volume_info* infos, size_t count) */ +DEFINE_SYSCALL (sys_get_volume_info) { + uint64_t fp; + + uintptr_t uvaddr_infos = a1; + size_t infos_count = (size_t)a2; + + spin_lock (&proc->lock, &fp); + struct procgroup* procgroup = proc->procgroup; + spin_unlock (&proc->lock, fp); + + struct volume_info* infos = + sys_get_user_buffer (procgroup, uvaddr_infos, infos_count * sizeof (struct volume_info)); + + if (infos == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + return SYSRESULT (volume_populate_volume_infos (infos, infos_count)); +} + +/* int volume_delete (const char* volume) */ +DEFINE_SYSCALL (sys_volume_delete) { + uint64_t fpg, fp; + + uintptr_t uvaddr_volume = a1; + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->lock, &fp); + struct procgroup* procgroup = proc->procgroup; + spin_unlock (&proc->lock, fp); + + spin_lock (&procgroup->lock, &fpg); + out_paddr = mm_v2p (&procgroup->pd, uvaddr_volume); + spin_unlock (&procgroup->lock, fpg); + + if (out_paddr == 0) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + const char* volume = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + int ret = vfs_volume_delete (volume); + + if (ret < 0) + return SYSRESULT (ret); + + return SYSRESULT (ST_OK); +} + static syscall_handler_func_t handler_table[] = { [SYS_QUIT] = &sys_quit, [SYS_TEST] = &sys_test, @@ -1136,6 +1188,8 @@ static syscall_handler_func_t handler_table[] = { [SYS_STREAM_READ] = &sys_stream_read, [SYS_GET_PROC_INFO] = &sys_get_proc_info, [SYS_GET_DEVICE_INFO] = &sys_get_device_info, + [SYS_GET_VOLUME_INFO] = &sys_get_volume_info, + [SYS_VOLUME_DELETE] = &sys_volume_delete, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libsystem/system.c b/libsystem/system.c index 246daba..4f24d00 100644 --- a/libsystem/system.c +++ b/libsystem/system.c @@ -118,3 +118,9 @@ int get_proc_info (struct proc_info* infos, size_t count) { int get_device_info (struct device_info* infos, size_t count) { return (int)do_syscall (SYS_GET_DEVICE_INFO, infos, count); } + +int get_volume_info (struct volume_info* infos, size_t count) { + return (int)do_syscall (SYS_GET_VOLUME_INFO, infos, count); +} + +int volume_delete (const char* key) { return (int)do_syscall (SYS_VOLUME_DELETE, key); } diff --git a/libsystem/system.h b/libsystem/system.h index 1a31575..e651dde 100644 --- a/libsystem/system.h +++ b/libsystem/system.h @@ -7,6 +7,7 @@ #include #include #include +#include /* Quit the current running process */ int quit (void); @@ -122,4 +123,10 @@ int get_proc_info (struct proc_info* infos, size_t count); /* get device information */ int get_device_info (struct device_info* infos, size_t count); +/* get volume information */ +int get_volume_info (struct volume_info* infos, size_t count); + +/* delete a volume */ +int volume_delete (const char* key); + #endif // _LIBMSL_M_SYSTEM_H diff --git a/usb/usb.c b/usb/usb.c index 499cefb..3bfa64b 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -5,14 +5,68 @@ #include #include #include +#include #include #include +#include + +static void usb_poll (void) { + struct device_info* infos = malloc (sizeof (struct device_info) * 1024); + memset (infos, 0, sizeof (struct device_info) * 1024); + + int device_count = get_device_info (infos, 1024); + struct device_info info; + bool found = false; + + for (int dev = 0; dev < device_count; dev++) { + info = infos[dev]; + + if (info.type == DEVICE_TYPE_USB_CTRL) { + found = true; + break; + } + } + + if (found) { + mprintf ("Polling device %s\n", info.key); + + for (;;) { + device_do (info.key, XUSBCTRL_POLL_DRIVER, NULL, NULL, NULL, NULL); + + for (volatile int i = 0; i < 500; i++) + sched (); + } + } + + free (infos); +} + +static void usb_eject (const char* dev_key) { + struct volume_info* volume_infos = malloc (sizeof (*volume_infos) * 100); + memset (volume_infos, 0, sizeof (*volume_infos) * 100); + + size_t count = get_volume_info (volume_infos, 100); + + for (size_t i = 0; i < count; i++) { + struct volume_info* info = &volume_infos[i]; + + if (strcmp (info->device_key, dev_key) == 0) { + int ret = volume_delete (info->volume_name); + mprintf ("Deleted volume %s: %s", info->volume_name, str_status[ret < 0 ? -ret : ret]); + break; + } + } + + free (volume_infos); +} void app_main (void) { libprocess_self_init (); char commandbuf[32]; memset (commandbuf, 0, sizeof (commandbuf)); + char devnamebuf[32]; + memset (devnamebuf, 0, sizeof (devnamebuf)); if (env_get (process_get_pgid (), "C", (void*)commandbuf, sizeof (commandbuf)) != ST_OK) { mprintf ("ERROR C=???. No command provided\n"); @@ -20,29 +74,14 @@ void app_main (void) { } if (strcmp (commandbuf, "poll") == 0) { - struct device_info* infos = malloc (sizeof (struct device_info) * 1024); - memset (infos, 0, sizeof (struct device_info) * 1024); - - int device_count = get_device_info (infos, 1024); - - for (int dev = 0; dev < device_count; dev++) { - struct device_info* info = &infos[dev]; - - if (info->type != DEVICE_TYPE_USB_CTRL) { - continue; - } - - mprintf ("Polling device %s\n", info->key); - - for (;;) { - device_do (info->key, XUSBCTRL_POLL_DRIVER, NULL, NULL, NULL, NULL); - - for (volatile int i = 0; i < 500; i++) - sched (); - } + usb_poll (); + } else if (strcmp (commandbuf, "eject") == 0) { + if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { + mprintf ("ERROR No device provided\n"); + return; } - free (infos); + usb_eject (devnamebuf); } else { mprintf ("ERROR unknown command %s\n", commandbuf); }