summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/GENERIC1
-rw-r--r--sys/include/sys/disk.h91
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/kern/disk_engine.c196
-rw-r--r--sys/kern/kern_disk.c7
-rw-r--r--sys/kern/kern_syscall.c2
6 files changed, 298 insertions, 0 deletions
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, &param);
+ 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(&param);
+ 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);