diff options
-rw-r--r-- | lib/libc/src/hyra/disk.c | 106 | ||||
-rw-r--r-- | sys/conf/GENERIC | 1 | ||||
-rw-r--r-- | sys/include/sys/disk.h | 91 | ||||
-rw-r--r-- | sys/include/sys/syscall.h | 1 | ||||
-rw-r--r-- | sys/kern/disk_engine.c | 196 | ||||
-rw-r--r-- | sys/kern/kern_disk.c | 7 | ||||
-rw-r--r-- | sys/kern/kern_syscall.c | 2 |
7 files changed, 404 insertions, 0 deletions
diff --git a/lib/libc/src/hyra/disk.c b/lib/libc/src/hyra/disk.c new file mode 100644 index 0000000..354ef03 --- /dev/null +++ b/lib/libc/src/hyra/disk.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/errno.h> +#include <sys/syscall.h> +#include <sys/disk.h> + +/* + * Disk I/O multiplexer system call which routes + * various disk operations via a single call. + * + * @id: The ID of the disk to be operated on + * @op: Operation code + * @param: Operation parameters + * + * Returns the number of bytes operated on upon success, + * otherwise a less than zero value is returned. + */ +ssize_t +__disk_io(diskid_t id, diskop_t op, const struct disk_param *param) +{ + if (param == NULL) { + return -EINVAL; + } + + return syscall( + SYS_disk, + id, + op, + (uintptr_t)param + ); +} + +/* + * Performs a write operation on a specific disk + * + * @id: ID of disk to operate on + * @blk: Block offset to operate on + * @buf: Data to write + * @len: Number of bytes to write + * + * Returns the number of bytes written upon success, otherwise + * a less than zero value is returned on error. + */ +ssize_t +disk_write(diskid_t id, blkoff_t blk, const void *buf, size_t len) +{ + struct disk_param param; + + if (buf == NULL || len == 0) { + return -EINVAL; + } + + disk_param_init(buf, blk, len, ¶m); + return __disk_io(id, DISK_IO_WRITE, ¶m); +} + +/* + * Performs a read operation on a specific disk + * + * @id: ID of disk to operate on + * @blk: Block offset to operate on + * @buf: Buffer to read data into + * @len: Number of bytes to read + * + * Returns the number of bytes read upon success, otherwise + * a less than zero value is returned on error. + */ +ssize_t +disk_read(diskid_t id, blkoff_t blk, void *buf, size_t len) +{ + struct disk_param param; + + if (buf == NULL || len == 0) { + return -EINVAL; + } + + disk_param_init(buf, blk, len, ¶m); + return __disk_io(id, DISK_IO_READ, ¶m); +} diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC index 5734c43..a8e4620 100644 --- a/sys/conf/GENERIC +++ b/sys/conf/GENERIC @@ -3,6 +3,7 @@ option PANIC_SCR no // Clear screen on panic // Kernel constants setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ) +setval DISK_MAX 16 // Maximum disks to be registered // Console attributes setval CONSOLE_BG 0x000000 diff --git a/sys/include/sys/disk.h b/sys/include/sys/disk.h index 09319f5..f6ed126 100644 --- a/sys/include/sys/disk.h +++ b/sys/include/sys/disk.h @@ -30,14 +30,30 @@ #ifndef _SYS_DISK_H_ #define _SYS_DISK_H_ +#include <sys/syscall.h> #include <sys/queue.h> #include <sys/device.h> #include <sys/types.h> #include <sys/limits.h> +#include <sys/cdefs.h> #define DISK_PRIMARY 0 /* ID of primary disk */ /* + * To prevent unlikely cases of unintended disk + * operations (e.g., read, write, etc), we store + * a cookie within each set of parameters. + * + * Requests whose bundle of parameters have no valid + * cookie shall be rejected by us. + */ +#define DISK_PARAM_COOKIE 0xD1531001 + +/* Valid disk operations */ +#define DISK_IO_READ 0x00 +#define DISK_IO_WRITE 0x01 + +/* * A disk identifier is a zero-based index into * the disk registry. */ @@ -49,6 +65,79 @@ typedef uint16_t diskid_t; typedef off_t blkoff_t; /* + * Disk operations may be requested by user + * programs by using a disk operation code. + */ +typedef uint8_t diskop_t; + +/* + * The disk metadata structure contains information + * describing the disk. It is used for Hyra's pbuf + * (persistent buffers / sls) support. This structure + * is to be stored at the very last sector of the drive. + * + * @root_blk: Disk offset to root block + * @n_ublk: Number of usable user blocks + */ +struct disk_meta { + char magic[6]; + blkoff_t root_blk; + size_t n_ublk; +}; + +/* + * A disk I/O parameter contains information + * that is passed from a user application to + * the kernel for specific operations. + * + * @buf: User-side pointer to data buffer + * @size: Size of data buffer in bytes + * @cookie: Used to prevent unintended operations + * @blk: Disk block offset + * @u_buf: Used by the kernel to keep track of user buffer + */ +struct disk_param { + void *buf; + size_t size; + uint32_t cookie; + blkoff_t blk; +#if defined(_KERNEL) + void *u_buf; +#endif +}; + +/* + * Helper used to initialize disk I/O parameters. + * This is used by the user to initialize a declared + * set of parameters. + * + * @buf: Buffer to operate on + * @blk: Disk block to operate on + * @size: Operation size in bytes (block-aligned) + * @res: Pointer to params to be initialized + */ +__always_inline static inline void +disk_param_init(uint8_t *buf, blkoff_t blk, size_t size, struct disk_param *res) +{ + if (res != NULL) { + res->buf = buf; + res->blk = blk; + res->size = size; + res->cookie = DISK_PARAM_COOKIE; + } +} + +/* + * User side disk API + */ +#if !defined(_KERNEL) +ssize_t __disk_io(diskid_t id, diskop_t op, const struct disk_param *param); +ssize_t disk_write(diskid_t id, blkoff_t off, const void *buf, size_t len); +ssize_t disk_read(diskid_t id, blkoff_t off, void *buf, size_t len); +#endif /* !_KERNEL */ + +#if defined(_KERNEL) +/* * Represents a block storage device * * @name: Name of disk @@ -78,4 +167,6 @@ ssize_t disk_write(diskid_t id, blkoff_t blk, const void *buf, size_t len); int disk_add(const char *name, dev_t dev, const struct bdevsw *bdev, int flags); int disk_get_id(diskid_t id, struct disk **res); +scret_t sys_disk(struct syscall_args *scargs); +#endif /* _KERNEL */ #endif /* !_SYS_DISK_H_ */ diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h index f53db8f..604f937 100644 --- a/sys/include/sys/syscall.h +++ b/sys/include/sys/syscall.h @@ -67,6 +67,7 @@ #define SYS_recvmsg 26 #define SYS_connect 27 #define SYS_setsockopt 28 +#define SYS_disk 29 #if defined(_KERNEL) /* Syscall return value and arg type */ diff --git a/sys/kern/disk_engine.c b/sys/kern/disk_engine.c new file mode 100644 index 0000000..a49c15f --- /dev/null +++ b/sys/kern/disk_engine.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/syscall.h> +#include <sys/syslog.h> +#include <sys/systm.h> +#include <sys/disk.h> +#include <vm/dynalloc.h> + +#define pr_trace(fmt, ...) kprintf("disk: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +/* + * Clones a disk parameter structure passed + * by a user. The structure returned is safe + * to be accessed freely by the kernel. + * + * @u_param: Contains user-side pointer + * @res: Resulting safe data + * + * Returns zero on success, otherwise a less than + * zero value is returned. + */ +static int +disk_param_clone(struct disk_param *u_param, struct disk_param *res) +{ + void *data; + int error; + + if (u_param == NULL) { + pr_error("disk_param_clone: got NULL u_param\n"); + return -EINVAL; + } + + error = copyin(u_param, res, sizeof(*res)); + if (error < 0) { + return error; + } + + /* + * If these parameters do not have a valid cookie, fuck + * that object, something is not right with it... + */ + if (res->cookie != DISK_PARAM_COOKIE) { + pr_error("disk_param_clone: erroneous params (bad cookie)\n"); + return -EACCES; + } + + data = dynalloc(res->size); + if (data == NULL) { + pr_error("disk_param_clone: out of memory\n"); + return -ENOMEM; + } + + error = copyin(res->buf, data, res->size); + if (error < 0) { + pr_error("failed to copy in param data\n"); + dynfree(data); + return error; + } + + res->u_buf = res->buf; + res->buf = data; + return 0; +} + +/* + * Deallocate a kernel managed disk parameter + * structure created by disk_param_clone() + * + * @param: Params to free + * + * Returns zero on success, otherwise a less than + * zero value is returned. + */ +static int +disk_param_free(struct disk_param *param) +{ + if (param == NULL) { + return -EINVAL; + } + + if (param->cookie != DISK_PARAM_COOKIE) { + return -EACCES; + } + + dynfree(param->buf); + return 0; +} + +/* + * Perform an operation on a disk. + * + * @id: ID of disk to operate on + * @opcode: Operation to perform (see DISK_IO_*) + * @u_param: User side disk parameters + * + * Returns a less than zero value on error + */ +static ssize_t +disk_mux_io(diskid_t id, diskop_t opcode, struct disk_param *u_param) +{ + struct disk_param param; + struct disk *dp; + ssize_t retval = -EIO; + int error; + + if (u_param == NULL) { + return -EINVAL; + } + + error = disk_param_clone(u_param, ¶m); + if (error < 0) { + return error; + } + + /* First, attempt to acquire the disk */ + error = disk_get_id(id, &dp); + if (error < 0) { + pr_error("disk_mux_io: no such device (id=%d)\n", id); + return error; + } + + switch (opcode) { + case DISK_IO_READ: + retval = disk_read( + id, + param.blk, + param.buf, + param.size + ); + + /* Write back the data to the user program */ + error = copyout(param.buf, param.u_buf, param.size); + if (error < 0) { + retval = error; + } + break; + case DISK_IO_WRITE: + retval = disk_write( + id, + param.blk, + param.buf, + param.size + ); + break; + } + + disk_param_free(¶m); + return retval; +} + +/* + * Disk I/O multiplexer syscall + * + * arg0: disk id + * arg1: opcode + * arg2: disk params + */ +scret_t +sys_disk(struct syscall_args *scargs) +{ + struct disk_param *u_param = (void *)scargs->arg2; + diskid_t id = scargs->arg0; + diskop_t opcode = scargs->arg1; + + return disk_mux_io(id, opcode, u_param); +} diff --git a/sys/kern/kern_disk.c b/sys/kern/kern_disk.c index 1b16e4d..b956c02 100644 --- a/sys/kern/kern_disk.c +++ b/sys/kern/kern_disk.c @@ -239,6 +239,13 @@ disk_add(const char *name, dev_t dev, const struct bdevsw *bdev, int flags) /* Disk queue must be initialized */ check_diskq(); + /* There is a limit to how many can be added */ + if (disk_count >= DISK_MAX) { + pr_error("disk_add: disk limit %d/%d reached\n", + disk_count, DISK_MAX); + return -EAGAIN; + } + /* Is the disk name of correct length? */ name_len = strlen(name); if (name_len >= sizeof(dp->name) - 1) { diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c index ba70b12..c352b9c 100644 --- a/sys/kern/kern_syscall.c +++ b/sys/kern/kern_syscall.c @@ -33,6 +33,7 @@ #include <sys/reboot.h> #include <sys/types.h> #include <sys/ucred.h> +#include <sys/disk.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/proc.h> @@ -69,6 +70,7 @@ scret_t(*g_sctab[])(struct syscall_args *) = { sys_recvmsg, /* SYS_recvmsg */ sys_connect, /* SYS_connect */ sys_setsockopt, /* SYS_setsockopt */ + sys_disk, /* SYS_disk */ }; const size_t MAX_SYSCALLS = NELEM(g_sctab); |