diff options
34 files changed, 1335 insertions, 48 deletions
@@ -79,6 +79,35 @@ Documentation will be in the form of comments throughout the codebase and can al - ``share/docs/kernel``: Kernel documentation - ``share/docs/lib``: Library documentation +# Maintainers (by author) +-------------- +| Maintainer | Component | +|--------------------|--------------------| +| <ian@osmora.org> | Hyra AMD64 Kernel | +| <ian@osmora.org> | User C Library | +| <ian@osmora.org> | NVMe Driver | +| <ian@osmora.org> | AHCI Driver | +| <ian@osmora.org> | xHCI Driver | +| <ian@osmora.org> | RTL8139 Driver | +| <ian@osmora.org> | E1000E Driver | +| <ian@osmora.org> | ET131X Driver | +| <ian@osmora.org> | PCI Driver | +| <ian@osmora.org> | PCIe Driver | +| <quinn@osmora.org> | PCI Driver | +| <quinn@osmora.org> | User C Library | +| <quinn@osmora.org> | Killing MS | + +-------------- +# To-do + +``` +[ ] kern: dev: AHCI DCDR cache (<ian@osmora.org>) +[ ] kern: Worker threads (<ian@osmora.org>) +[ ] kern: Multithreaded driver startup (<quinn@osmora.org>) +[ ] libc: Slab allocator (<quinn@osmora.org>) +... +``` + Hyra running on bare metal: --------------  diff --git a/configure.ac b/configure.ac index 6db3a09..50c56b4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([Hyra], [2.5], [ian@osmora.org]) +AC_INIT([Hyra], [2.6], [ian@osmora.org]) TARGET="amd64" QEMU="qemu-system-x86_64" diff --git a/etc/hostname b/etc/hostname new file mode 100644 index 0000000..c90b108 --- /dev/null +++ b/etc/hostname @@ -0,0 +1 @@ +osmora diff --git a/lib/libc/include/ctype.h b/lib/libc/include/ctype.h index 2348852..0ff9a43 100644 --- a/lib/libc/include/ctype.h +++ b/lib/libc/include/ctype.h @@ -72,6 +72,7 @@ __isspace(int c) return 1; return 0; + } } __END_DECLS diff --git a/lib/libc/include/unistd.h b/lib/libc/include/unistd.h index b9c9f5e..40ebee2 100644 --- a/lib/libc/include/unistd.h +++ b/lib/libc/include/unistd.h @@ -47,18 +47,39 @@ __BEGIN_DECLS int sysconf(int name); int setuid(uid_t new); +int gethostname(char *name, size_t size); +int sethostname(const char *name, size_t size); + uid_t getuid(void); char *getlogin(void); +char *getcwd(char *buf, size_t size); +char *getwd(char *pathname); + +int symlink(const char *target, const char *linkpath); +int synlinkat(const char *target, int newdirfd, const char *linkpath); + ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd); int access(const char *path, int mode); + off_t lseek(int fildes, off_t offset, int whence); +int unlinkat(int dirfd, const char *pathname, int flags); +int unlink(const char *path); + +int dup(int fd); +int dup2(int fd, int fd1); pid_t getpid(void); pid_t getppid(void); +pid_t fork(void); + +extern char *optarg; +extern int optind, opterr, optopt; + +int getopt(int argc, char *argv[], const char *optstring); __END_DECLS diff --git a/lib/libc/src/hyra/sysctl.c b/lib/libc/src/hyra/sysctl.c new file mode 100644 index 0000000..2903e6f --- /dev/null +++ b/lib/libc/src/hyra/sysctl.c @@ -0,0 +1,38 @@ +/* + * 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/syscall.h> +#include <sys/sysctl.h> + +int +sysctl(struct sysctl_args *args) +{ + return syscall(SYS_sysctl, (uintptr_t)args); +} diff --git a/lib/libc/src/main.c b/lib/libc/src/main.c index 02a648b..68f9bdb 100644 --- a/lib/libc/src/main.c +++ b/lib/libc/src/main.c @@ -30,6 +30,7 @@ #include <sys/exec.h> #include <stdint.h> #include <stddef.h> +#include <unistd.h> extern int __libc_stdio_init(void); extern int __malloc_mem_init(void); @@ -51,6 +52,7 @@ __libc_entry(uint64_t *ctx) char **argv; char **envp; + optind = 1; argc = *ctx; argv = (char **)(ctx + 1); envp = (char **)(argv + argc + 1); diff --git a/lib/libc/src/posix/getopt.c b/lib/libc/src/posix/getopt.c new file mode 100644 index 0000000..d3cd530 --- /dev/null +++ b/lib/libc/src/posix/getopt.c @@ -0,0 +1,100 @@ +/* + * 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 <unistd.h> +#include <stdbool.h> +#include <string.h> +#include <stdio.h> + +char *optarg; +int optind, opterr, optopt; + +int +getopt(int argc, char *argv[], const char *optstring) +{ + size_t optstr_len; + char *arg; + bool has_arg = false; + + if (argc == 0 || optstring == NULL) { + opterr = -EINVAL; + return -1; + } + + if (optind >= argc) { + return -1; + } + + arg = argv[optind]; + optstr_len = strlen(optstring); + + /* Non option argument? */ + if (arg[0] != '-') { + return -1; + } + + /* + * We will look through each possible flag/option + * in the optstring and match it against our arg. + */ + for (size_t i = 0; i < optstr_len; ++i) { + if (arg[1] != optstring[i]) { + continue; + } + + /* + * If this option has a ':' right next to it, + * it also has an argument. + */ + if (i < optstr_len - 1) { + if (optstring[i + 1] == ':') { + has_arg = true; + } + } + + break; + } + + /* + * Handle cases where the option has an argument + * with it (-opt=arg) + */ + if (has_arg && optind < argc ) { + if (arg[2] != '=') { + opterr = -EINVAL; + return -1; + } + optarg = &arg[3]; + ++optind; + } + + ++optind; + return arg[1]; +} diff --git a/lib/libc/src/unistd/dup.c b/lib/libc/src/unistd/dup.c new file mode 100644 index 0000000..887fdc6 --- /dev/null +++ b/lib/libc/src/unistd/dup.c @@ -0,0 +1,44 @@ +/* + * 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 <unistd.h> + +int +dup(int fd) +{ + /* TODO: STUB */ + return -1; +} + +int +dup2(int fd, int fd1) +{ + /* TODO: STUB */ + return -1; +} diff --git a/lib/libc/src/unistd/fork.c b/lib/libc/src/unistd/fork.c new file mode 100644 index 0000000..970072e --- /dev/null +++ b/lib/libc/src/unistd/fork.c @@ -0,0 +1,37 @@ +/* + * 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 <unistd.h> + +pid_t +fork(void) +{ + /* TODO */ + return -1; +} diff --git a/lib/libc/src/unistd/getcwd.c b/lib/libc/src/unistd/getcwd.c new file mode 100644 index 0000000..641a49b --- /dev/null +++ b/lib/libc/src/unistd/getcwd.c @@ -0,0 +1,52 @@ +/* + * 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 <unistd.h> + +char * +getcwd(char *buf, size_t size) +{ + if (buf == NULL) { + return NULL; + } + + /* TODO: STUB */ + return NULL; +} + +char * +getwd(char *pathname) +{ + if (pathname == NULL) { + return NULL; + } + + /* TODO: STUB */ + return NULL; +} diff --git a/lib/libc/src/unistd/hostname.c b/lib/libc/src/unistd/hostname.c new file mode 100644 index 0000000..60df9a0 --- /dev/null +++ b/lib/libc/src/unistd/hostname.c @@ -0,0 +1,125 @@ +/* + * 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/sysctl.h> +#include <unistd.h> + +/* + * Internal helper to grab a sysctl + * variable. + * + * @name: Name definition of sysctl variable + * @buf: Buffer to read data in + * @buflen: Length of buffer + * + * Returns zero on success, otherwise a less than + * zero value. + */ +static int +__sysctl_get(int name, char *buf, size_t buflen) +{ + struct sysctl_args args; + int error; + + args.name = &name; + args.nlen = 1; + args.oldp = buf; + args.oldlenp = &buflen; + args.newp = NULL; + args.newlen = 0; + + if ((error = sysctl(&args)) != 0) { + return -1; + } + + return 0; +} + +/* + * Internal helper to set a sysctl + * variable. + * + * @name: Name definition of sysctl variable + * @buf: Buffer with data to set + * @buflen: Length of buffer + * + * Returns zero on success, otherwise a less than + * zero value. + */ +static int +__sysctl_set(int name, const char *buf, size_t buflen) +{ + struct sysctl_args args; + int error; + + args.name = &name; + args.nlen = 1; + args.oldp = NULL; + args.oldlenp = NULL; + args.newp = (void *)buf; + args.newlen = buflen; + + if ((error = sysctl(&args)) != 0) { + return -1; + } + + return 0; +} + +/* + * Get the system hostname + * + * @name: Buffer to read name into + * @size: Length of name to read + */ +int +gethostname(char *name, size_t size) +{ + if (name == NULL || size == 0) { + return -1; + } + + return __sysctl_get(KERN_HOSTNAME, name, size); +} + +/* + * Set the system hostname + * + * @name: Name to set + * @size: Size of name to set + */ +int +sethostname(const char *name, size_t size) +{ + if (name == NULL || size == 0) { + return -1; + } + + return __sysctl_set(KERN_HOSTNAME, name, size); +} diff --git a/lib/libc/src/unistd/symlink.c b/lib/libc/src/unistd/symlink.c new file mode 100644 index 0000000..2ad24ca --- /dev/null +++ b/lib/libc/src/unistd/symlink.c @@ -0,0 +1,53 @@ +/* + * 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 <unistd.h> + +int +symlink(const char *target, const char *linkpath) +{ + if (target == NULL || linkpath == NULL) { + return -EINVAL; + } + + /* TODO: STUB */ + return -1; +} + +int +synlinkat(const char *target, int newdirfd, const char *linkpath) +{ + if (target == NULL || linkpath == NULL) { + return -EINVAL; + } + + /* TODO: STUB */ + return -1; +} diff --git a/lib/libc/src/unistd/unlink.c b/lib/libc/src/unistd/unlink.c new file mode 100644 index 0000000..3de0796 --- /dev/null +++ b/lib/libc/src/unistd/unlink.c @@ -0,0 +1,53 @@ +/* + * 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 <unistd.h> + +int +unlink(const char *path) +{ + if (path == NULL) { + return -EINVAL; + } + + /* TODO: STUB */ + return -1; +} + +int +unlinkat(int dirfd, const char *pathname, int flags) +{ + if (pathname == NULL || dirfd < 0) { + return -EINVAL; + } + + /* TODO: STUB */ + return -1; +} diff --git a/share/man/man1/cat.1 b/share/man/man1/cat.1 index 8214724..1759407 100644 --- a/share/man/man1/cat.1 +++ b/share/man/man1/cat.1 @@ -24,7 +24,7 @@ .\" 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. -.Dd Jul 17 2025 +.Dd Aug 6 2025 .Dt CAT 1 .Os HYRA .Sh NAME @@ -39,6 +39,11 @@ The command can be used concatenate files or simply write their contents to standard output. +.Bd -literal +[-n]: Number each line +[-b]: Number each non-blank line +.Ed + .Sh SEE ALSO mex(1) diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c index 20f550f..43830ba 100644 --- a/sys/arch/amd64/amd64/mp.c +++ b/sys/arch/amd64/amd64/mp.c @@ -30,6 +30,7 @@ #include <sys/types.h> #include <sys/limine.h> #include <sys/limits.h> +#include <sys/systm.h> #include <sys/syslog.h> #include <sys/proc.h> #include <sys/spinlock.h> @@ -149,4 +150,5 @@ mp_bootstrap_aps(struct cpu_info *ci) /* Wait for all cores to be ready */ while ((ncpu_up - 1) < cpu_init_counter); + cpu_report_count(ncpu_up); } diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c index b133288..ffec436 100644 --- a/sys/dev/acpi/uacpi.c +++ b/sys/dev/acpi/uacpi.c @@ -32,6 +32,8 @@ #include <sys/param.h> #include <sys/syslog.h> #include <sys/panic.h> +#include <sys/proc.h> +#include <sys/queue.h> #include <dev/timer.h> #include <uacpi/kernel_api.h> #include <uacpi/platform/arch_helpers.h> @@ -58,17 +60,88 @@ typedef struct { uacpi_size length; } io_range_t; +struct uacpi_work { + uacpi_work_handler hand; + uacpi_handle ctx; + TAILQ_ENTRY(uacpi_work) link; +}; + +uacpi_status +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx); + +extern struct proc g_proc0; + +static struct proc *event_td; +static TAILQ_HEAD(, uacpi_work) acpi_gpe_eventq; +static TAILQ_HEAD(, uacpi_work) acpi_notify_eventq; + /* - * TODO: Schedule a system shutdown + * Dispatch ACPI general purpose events from + * hardware. */ -static uacpi_interrupt_ret -power_button_handler(uacpi_handle ctx) +static void +uacpi_gpe_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_gpe_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +/* + * Dispatch ACPI general notify events. + */ +static void +uacpi_notify_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_notify_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +static void +uacpi_event_td(void) +{ + for (;;) { + uacpi_gpe_dispatch(); + uacpi_notify_dispatch(); + sched_yield(); + } +} + +static void +shutdown(uacpi_handle ctx) { - md_intoff(); kprintf("power button pressed\n"); kprintf("halting machine...\n"); cpu_halt_all(); - return UACPI_INTERRUPT_HANDLED; +} + +static uacpi_interrupt_ret +power_button_handler(uacpi_handle ctx) +{ + md_intoff(); + uacpi_kernel_schedule_work(UACPI_WORK_GPE_EXECUTION, shutdown, NULL); + md_inton(); + + for (;;) { + md_hlt(); + } + + __builtin_unreachable(); } void * @@ -278,9 +351,28 @@ uacpi_kernel_uninstall_interrupt_handler([[maybe_unused]] uacpi_interrupt_handle } uacpi_status -uacpi_kernel_schedule_work(uacpi_work_type, uacpi_work_handler, uacpi_handle ctx) +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx) { - return UACPI_STATUS_UNIMPLEMENTED; + struct uacpi_work *work; + + work = dynalloc(sizeof(*work)); + if (work == NULL) { + return UACPI_STATUS_OUT_OF_MEMORY; + } + + work->hand = h; + work->ctx = ctx; + + switch (type) { + case UACPI_WORK_GPE_EXECUTION: + TAILQ_INSERT_TAIL(&acpi_gpe_eventq, work, link); + break; + case UACPI_WORK_NOTIFICATION: + TAILQ_INSERT_TAIL(&acpi_notify_eventq, work, link); + break; + } + + return 0; } uacpi_status @@ -575,5 +667,8 @@ uacpi_init(void) return -1; } + TAILQ_INIT(&acpi_gpe_eventq); + TAILQ_INIT(&acpi_notify_eventq); + spawn(&g_proc0, uacpi_event_td, NULL, 0, &event_td); return 0; } diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 0ccb7a0..e14cb44 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -71,11 +71,16 @@ xhci_intr(void *sf) static inline uint32_t * xhci_get_portsc(struct xhci_hc *hc, uint8_t portno) { - if (portno > hc->maxports) { - portno = hc->maxports; + if (portno >= hc->maxports) { + return NULL; } - return PTR_OFFSET(hc->opregs, 0x400 + (0x10 * (portno - 1))); + /* Zero based */ + if (portno > 0) { + --portno; + } + + return PTR_OFFSET(hc->opregs, 0x400 + (0x10 * portno)); } static int @@ -200,12 +205,12 @@ xhci_init_scratchpads(struct xhci_hc *hc) for (size_t i = 0; i < max_bufs; ++i) { tmp = vm_alloc_frame(1); - memset(PHYS_TO_VIRT(tmp), 0, 0x1000); if (tmp == 0) { /* TODO: Shutdown, free memory */ pr_error("failed to fill scratchpad buffer array\n"); return -1; } + memset(PHYS_TO_VIRT(tmp), 0, 0x1000); bufarr[i] = tmp; } @@ -221,7 +226,7 @@ xhci_alloc_dcbaa(struct xhci_hc *hc) { size_t size; - size = sizeof(uintptr_t) * hc->maxslots; + size = sizeof(uintptr_t) * (hc->maxslots + 1); hc->dcbaap = dynalloc_memalign(size, 0x1000); __assert(hc->dcbaap != NULL); return VIRT_TO_PHYS(hc->dcbaap); @@ -268,7 +273,7 @@ xhci_init_evring(struct xhci_hc *hc) /* setup the event ring segment */ segtab->base = VIRT_TO_PHYS(tmp_p); - segtab->base = ((uintptr_t)segtab->base) + (2 * 4096) & ~0xF; + segtab->base = ((uintptr_t)segtab->base); segtab->size = XHCI_EVRING_LEN; /* Setup the event ring dequeue pointer */ @@ -335,6 +340,13 @@ xhci_reset(struct xhci_hc *hc) return error; } + /* Wait longer if the xHC is not ready */ + error = xhci_poll32(&opregs->usbsts, USBSTS_CNR, false); + if (error < 0) { + pr_error("xhci_reset: xHC ready wait timeout\n"); + return error; + } + return 0; } @@ -372,13 +384,33 @@ xhci_start_hc(struct xhci_hc *hc) /* Don't start up if we are already running */ usbcmd = mmio_read32(&opregs->usbcmd); if (ISSET(usbcmd, USBCMD_RUN)) - return -EBUSY; + return 0; usbcmd |= USBCMD_RUN; mmio_write32(&opregs->usbcmd, usbcmd); return 0; } +/* + * Stop and bring down the host controller. + * Returns 0 on success. + */ +static int +xhci_stop_hc(struct xhci_hc *hc) +{ + struct xhci_opregs *opregs = hc->opregs; + uint32_t usbcmd; + + /* Don't continue if we aren't running */ + usbcmd = mmio_read32(&opregs->usbcmd); + if (!ISSET(usbcmd, USBCMD_RUN)) + return 0; + + usbcmd &= ~USBCMD_RUN; + mmio_write32(&opregs->usbcmd, usbcmd); + return 0; +} + static int xhci_init_ports(struct xhci_hc *hc) { @@ -388,6 +420,9 @@ xhci_init_ports(struct xhci_hc *hc) for (size_t i = 1; i < hc->maxports; ++i) { portsc_p = xhci_get_portsc(hc, i); + if (portsc_p == NULL) { + continue; + } portsc = mmio_read32(portsc_p); /* @@ -461,8 +496,15 @@ xhci_init_hc(struct xhci_hc *hc) return -1; } + pr_trace("stopping xHC chip...\n"); + if ((error = xhci_stop_hc(hc)) != 0) { + pr_error("run/stop timeout\n"); + return error; + } + pr_trace("resetting xHC chip...\n"); if ((error = xhci_reset(hc)) != 0) { + pr_error("reset timeout\n"); return error; } diff --git a/sys/include/dev/acpi/tables.h b/sys/include/dev/acpi/tables.h index 5340c7f..d31cbe0 100644 --- a/sys/include/dev/acpi/tables.h +++ b/sys/include/dev/acpi/tables.h @@ -118,6 +118,43 @@ struct __packed acpi_gas { uint64_t address; }; +/* + * ACPI Address Space ID definitions for GAS + * + * See section 5.2.3.2 of the ACPI software programming + * manual. + * + * XXX: 0x0B->0x7E is reserved as well as 0x80->0xBF + * and 0xC0->0xFF is OEM defined. Values other than + * the ones specified below are either garbage or + * OEM specific values. + */ +#define ACPI_GAS_SYSMEM 0x00 /* System memory space */ +#define ACPI_GAS_SYSIO 0x01 /* System I/O space */ +#define ACPI_GAS_PCICONF 0x02 /* PCI configuration space */ +#define ACPI_GAS_EC 0x03 /* Embedded controller */ +#define ACPI_GAS_SMBUS 0x04 /* System management bus */ +#define ACPI_GAS_CMOS 0x05 /* System CMOS */ +#define ACPI_GAS_PCIBAR 0x06 /* PCI BAR target */ +#define ACPI_GAS_IPMI 0x07 /* IPMI (sensor monitoring) */ +#define ACPI_GAS_GPIO 0x08 /* General Purpose I/O */ +#define ACPI_GAS_GSBUS 0x09 /* GenericSerialBus */ +#define ACPI_GAS_PLATCOM 0x0A /* Platform Communications Channel */ + +/* + * ACPI address size definitions for GAS + * + * See section 5.2.3.2 of the ACPI software programming + * manual. + * + * This is really retarded Intel and Microsoft, thank you. + */ +#define ACPI_GAS_UNDEF 0 /* Undefined (legacy reasons) */ +#define ACPI_GAS_BYTE 1 /* Byte access */ +#define ACPI_GAS_WORD 2 /* Word access */ +#define ACPI_GAS_DWORD 3 /* Dword access */ +#define ACPI_GAS_QWORD 4 /* Qword access */ + struct __packed acpi_hpet { struct acpi_header hdr; uint8_t hardware_rev_id; diff --git a/sys/include/dev/usb/xhciregs.h b/sys/include/dev/usb/xhciregs.h index 1cbfd14..cafd7c9 100644 --- a/sys/include/dev/usb/xhciregs.h +++ b/sys/include/dev/usb/xhciregs.h @@ -77,6 +77,7 @@ struct xhci_opregs { /* USBSTS bits */ #define USBSTS_HCH BIT(0) /* HC halted */ +#define USBSTS_CNR BIT(11) /* Controller not ready */ /* CAPS.HCSPARAMS1 fields */ #define XHCI_MAXSLOTS(HCSPARAMS1) (HCSPARAMS1 & 0xFF) diff --git a/sys/include/sys/sysctl.h b/sys/include/sys/sysctl.h index d13b0f8..3b8d3c7 100644 --- a/sys/include/sys/sysctl.h +++ b/sys/include/sys/sysctl.h @@ -39,10 +39,21 @@ #endif #include <sys/param.h> +/* + * List of 'kern.* ' identifiers + */ #define KERN_OSTYPE 0 #define KERN_OSRELEASE 1 #define KERN_VERSION 2 #define KERN_VCACHE_TYPE 3 +#define KERN_HOSTNAME 4 + +/* + * List of 'hw.* ' identifiers + */ +#define HW_PAGESIZE 5 +#define HW_NCPU 6 +#define HW_MACHINE 7 /* * Option types (i.e., int, string, etc) for @@ -64,6 +75,7 @@ struct sysctl_entry { }; scret_t sys_sysctl(struct syscall_args *scargs); +int sysctl_clearstr(int name); #endif /* _KERNEL */ /* diff --git a/sys/include/sys/systm.h b/sys/include/sys/systm.h index 42e1723..2f69175 100644 --- a/sys/include/sys/systm.h +++ b/sys/include/sys/systm.h @@ -39,6 +39,7 @@ int copyin(const void *uaddr, void *kaddr, size_t len); int copyout(const void *kaddr, void *uaddr, size_t len); int copyinstr(const void *uaddr, char *kaddr, size_t len); +int cpu_report_count(uint32_t count); __always_inline static inline void __sigraise(int signo) diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index e8255bd..541355a 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -35,6 +35,7 @@ #include <sys/exec.h> #include <sys/driver.h> #include <sys/panic.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <dev/acpi/uacpi.h> #include <dev/cons/cons.h> @@ -113,13 +114,13 @@ main(void) sched_init(); memset(&g_proc0, 0, sizeof(g_proc0)); + sysctl_clearstr(KERN_HOSTNAME); /* Startup pid 1 */ spawn(&g_proc0, start_init, NULL, 0, &g_init); md_inton(); /* Load all early drivers */ - driver_blacklist("ahci"); DRIVERS_INIT(); /* Only log to kmsg from here */ diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c new file mode 100644 index 0000000..69d44c4 --- /dev/null +++ b/sys/kern/kern_cpu.c @@ -0,0 +1,61 @@ +/* + * 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/systm.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +/* + * Report the number of processors that are online + * in the machine. + * + * @count: Number of processors active + * + * Returns zero on success, otherwise a less + * than zero value is returned. + */ +int +cpu_report_count(uint32_t count) +{ + struct sysctl_args args; + int error, name = HW_NCPU; + + args.name = &name; + args.nlen = 1; + args.oldlenp = 0; + args.oldp = NULL; + args.newp = &count; + args.newlen = sizeof(count); + + if ((error = sysctl(&args)) != 0) { + return error; + } + + return 0; +} diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index c8f8357..83845f6 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -241,7 +241,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) /* Increment the offset per read */ filedes->offset += n; - retval = count; + retval = n; done: if (kbuf != NULL) { dynfree(kbuf); diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 7679aa1..a4c16bb 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -33,12 +33,15 @@ #include <sys/errno.h> #include <sys/systm.h> #include <vm/dynalloc.h> +#include <vm/vm.h> #include <string.h> #define HYRA_RELEASE "Hyra/" HYRA_ARCH " " \ HYRA_VERSION " " \ HYRA_BUILDDATE +static uint32_t pagesize = DEFAULT_PAGESIZE; +static char machine[] = HYRA_ARCH; static char hyra[] = "Hyra"; static char hyra_version[] = HYRA_VERSION; static char osrelease[] = HYRA_RELEASE; @@ -49,10 +52,17 @@ static char osrelease[] = HYRA_RELEASE; * allocated through dynalloc(9). */ static struct sysctl_entry common_optab[] = { + /* 'kern.*' */ [KERN_OSTYPE] = { KERN_OSTYPE, SYSCTL_OPTYPE_STR_RO, hyra }, [KERN_OSRELEASE] = { KERN_OSRELEASE, SYSCTL_OPTYPE_STR_RO, &osrelease }, [KERN_VERSION] = { KERN_VERSION, SYSCTL_OPTYPE_STR_RO, &hyra_version }, - [KERN_VCACHE_TYPE] = { KERN_VCACHE_TYPE, SYSCTL_OPTYPE_STR, NULL } + [KERN_VCACHE_TYPE] = { KERN_VCACHE_TYPE, SYSCTL_OPTYPE_STR, NULL }, + [KERN_HOSTNAME] = { KERN_HOSTNAME, SYSCTL_OPTYPE_STR, NULL }, + + /* 'hw.*' */ + [HW_PAGESIZE] = { HW_PAGESIZE, SYSCTL_OPTYPE_INT_RO, &pagesize }, + [HW_NCPU] = { HW_NCPU, SYSCTL_OPTYPE_INT, NULL }, + [HW_MACHINE] = {HW_MACHINE, SYSCTL_OPTYPE_STR_RO, &machine } }; static int @@ -91,19 +101,18 @@ static int do_sysctl(struct sysctl_args *args) { struct sysctl_args new_args; - size_t name_len, oldlenp; + size_t name_len = 1, oldlenp = 0; int *name = NULL; void *oldp = NULL, *newp = NULL; - int retval = 0; - - if (args->oldlenp == NULL) { - return -EINVAL; - } - - name_len = args->nlen; - retval = copyin(args->oldlenp, &oldlenp, sizeof(oldlenp)); - if (retval != 0) { - goto done; + int retval = 0, have_oldlen = 0; + + if (args->oldlenp != NULL) { + have_oldlen = 1; + name_len = args->nlen; + retval = copyin(args->oldlenp, &oldlenp, sizeof(oldlenp)); + if (retval != 0) { + goto done; + } } /* Copy in newp if it is set */ @@ -124,25 +133,30 @@ do_sysctl(struct sysctl_args *args) return retval; } - oldp = dynalloc(oldlenp); - retval = copyin(args->oldp, oldp, oldlenp); - if (retval != 0) { - return retval; + if (oldlenp != 0) { + oldp = dynalloc(oldlenp); + retval = copyin(args->oldp, oldp, oldlenp); + if (retval != 0) { + return retval; + } } /* Prepare the arguments for the sysctl call */ new_args.name = name; new_args.nlen = name_len; new_args.oldp = oldp; - new_args.oldlenp = &oldlenp; + new_args.oldlenp = (have_oldlen) ? &oldlenp : NULL; new_args.newp = newp; + new_args.newlen = args->newlen; retval = sysctl(&new_args); if (retval != 0) { goto done; } - copyout(oldp, args->oldp, oldlenp); + if (oldlenp != 0) { + copyout(oldp, args->oldp, oldlenp); + } done: if (name != NULL) dynfree(name); @@ -154,6 +168,33 @@ done: return retval; } +/* + * Clear a writable sysctl string variable to the + * value of "(undef)" + * + * @name: Name to clear + */ +int +sysctl_clearstr(int name) +{ + struct sysctl_args args; + char val[] = "(undef)"; + int error; + + args.name = &name; + args.nlen = 1; + args.oldlenp = 0; + args.oldp = NULL; + args.newp = val; + args.newlen = sizeof(val); + + if ((error = sysctl(&args)) != 0) { + return error; + } + + return 0; +} + int sysctl(struct sysctl_args *args) { diff --git a/sys/kern/vfs_vcache.c b/sys/kern/vfs_vcache.c index 25e244c..6c08caf 100644 --- a/sys/kern/vfs_vcache.c +++ b/sys/kern/vfs_vcache.c @@ -161,7 +161,7 @@ vfs_vcache_migrate(int newtype) args.oldp = NULL; args.oldlenp = NULL; args.newp = sysctl_val; - args.newlen = strlen(sysctl_val); + args.newlen = strlen(sysctl_val) + 1; if ((retval = sysctl(&args)) != 0) { return retval; diff --git a/usr.bin/Makefile b/usr.bin/Makefile index d8bf421..47ba752 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -26,3 +26,4 @@ all: make -C oasm/ $(ARGS) make -C oemu/ $(ARGS) make -C dmidump/ $(ARGS) + make -C sysctl/ $(ARGS) diff --git a/usr.bin/cat/cat.c b/usr.bin/cat/cat.c index 35e9e95..4fb74d1 100644 --- a/usr.bin/cat/cat.c +++ b/usr.bin/cat/cat.c @@ -34,12 +34,27 @@ #include <stdio.h> #include <stdlib.h> +#define NUM_MODE_NONE 0 +#define NUM_MODE_ALL 1 +#define NUM_MODE_NONBLANK 2 + +static void +help(void) +{ + printf( + "usage: cat <flags> <file>\n" + "[-b] do not number blank lines\n" + "[-n] number all lines\n" + ); +} + static void -cat(const char *pathname) +cat(const char *pathname, int num_mode) { FILE *file; char buf[64]; int fd; + size_t lineno = 1; file = fopen(pathname, "r"); if (file == NULL) { @@ -47,7 +62,21 @@ cat(const char *pathname) } while (fgets(buf, sizeof(buf), file) != NULL) { + switch (num_mode) { + case NUM_MODE_NONE: + break; + case NUM_MODE_ALL: + printf("%d ", lineno); + break; + case NUM_MODE_NONBLANK: + if (buf[0] == '\n') { + break; + } + printf("%d ", lineno); + break; + } printf("%s", buf); + ++lineno; } fclose(file); @@ -56,8 +85,27 @@ cat(const char *pathname) int main(int argc, char **argv) { - for (size_t i = 1; i < argc; ++i) { - cat(argv[i]); + int num_mode = NUM_MODE_NONE; + int c; + + if (argc < 2) { + help(); + return -1; + } + + while ((c = getopt(argc, argv, "nb")) != -1) { + switch (c) { + case 'n': + num_mode = NUM_MODE_ALL; + break; + case 'b': + num_mode = NUM_MODE_NONBLANK; + break; + } + } + + for (size_t i = optind; i < argc; ++i) { + cat(argv[i], num_mode); } return 0; diff --git a/usr.bin/fetch/fetch.c b/usr.bin/fetch/fetch.c index 175cd0e..1e8ef92 100644 --- a/usr.bin/fetch/fetch.c +++ b/usr.bin/fetch/fetch.c @@ -30,21 +30,76 @@ #include <unistd.h> #include <fcntl.h> #include <string.h> +#include <stdlib.h> #include <stdio.h> -static const char *user = "unknown"; +#define CPUID(level, a, b, c, d) \ + __ASMV("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)) #define ASCII_ART \ " ____ \n" \ - " | \\__\\ \n" \ - " | /\\ \\ user: %s\n" \ - " |/ \\ \\ OS: Hyra/amd64 v"_OSVER"\n" \ - " \\ R. \\ \\ arch: "_OSARCH"\n" \ + " | \\__\\ user: %s\n" \ + " | /\\ \\ OS: Hyra/amd64 v"_OSVER"\n" \ + " |/ \\ \\ arch: "_OSARCH"\n" \ + " \\ R. \\ \\ cpu: %s\n" \ " \\ I. \\ \\\n" + +/* + * Get the processor brand string + * + * @buffer: Buffer to copy branch string + * + * Returns a pointer to newly allocated memory + * containing the vendor string. One must ensure + * to call free() after use. + */ +static char * +get_brand(void) +{ + uint32_t eax, ebx, ecx, edx; + uint32_t regs[12]; + char buf[sizeof(regs) + 1]; + char *p = buf; + + /* Can we even get the brand? */ + CPUID(0x80000000, eax, ebx, ecx, edx); + if (eax < 0x80000004) { + return NULL; + } + + CPUID(0x80000002, regs[0], regs[1], regs[2], regs[3]); + CPUID(0x80000003, regs[4], regs[5], regs[6], regs[7]); + CPUID(0x80000004, regs[8], regs[9], regs[10], regs[11]); + + /* Log it */ + memcpy(p, regs, sizeof(regs)); + buf[sizeof(regs)] = '\0'; + + /* Strip away leading whitespaces */ + for (int i = 0; i < sizeof(buf); ++i) { + if (buf[i] == ' ') { + ++p; + } else { + break; + } + } + + return strdup(p); +} + int main(void) { - printf(ASCII_ART, getlogin()); + char *brand = get_brand(); + + if (brand == NULL) { + brand = strdup("unknown"); + } + + printf(ASCII_ART, getlogin(), brand); + free(brand); return 0; } diff --git a/usr.bin/osh/osh.c b/usr.bin/osh/osh.c index 545f95a..5062e64 100644 --- a/usr.bin/osh/osh.c +++ b/usr.bin/osh/osh.c @@ -67,7 +67,7 @@ "clear - Clear the screen\n" \ "exit - Exit the shell" -#define PROMPT "[%s::osmora]~ " +#define PROMPT "[%s::%s]~ " static char last_command[INPUT_SIZE]; static char buf[INPUT_SIZE]; @@ -466,6 +466,7 @@ main(int argc, char **argv) { int found, prog_argc; int stdout_fd; + char hostname[128] = "osmora"; uint8_t buf_i; char *p; char c; @@ -478,9 +479,10 @@ main(int argc, char **argv) running = 1; bell_fd = open("/dev/beep", O_WRONLY); dump_file("/etc/motd"); + gethostname(hostname, sizeof(hostname)); while (running) { - printf(PROMPT, getlogin()); + printf(PROMPT, getlogin(), hostname); buf_i = getstr(); if (buf[0] == '\0') { diff --git a/usr.bin/sysctl/Makefile b/usr.bin/sysctl/Makefile new file mode 100644 index 0000000..e32dbc4 --- /dev/null +++ b/usr.bin/sysctl/Makefile @@ -0,0 +1,6 @@ +include user.mk + +CFILES = $(shell find . -name "*.c") + +$(ROOT)/base/usr/bin/sysctl: + gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS) diff --git a/usr.bin/sysctl/sysctl.c b/usr.bin/sysctl/sysctl.c new file mode 100644 index 0000000..d4275a7 --- /dev/null +++ b/usr.bin/sysctl/sysctl.c @@ -0,0 +1,279 @@ +/* + * 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/sysctl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> + +#define BUF_SIZE 128 + +/* Kern var string constants */ +#define NAME_OSTYPE "ostype" +#define NAME_OSRELEASE "osrelease" +#define NAME_VERSION "version" +#define NAME_VCACHE_TYPE "vcache_type" + +/* Hw var string constants */ +#define NAME_PAGESIZE "pagesize" +#define NAME_NCPU "ncpu" +#define NAME_MACHINE "machine" + +/* Name start string constants */ +#define NAME_KERN "kern" +#define NAME_HW "hw" + +/* Name start int constants */ +#define NAME_DEF_KERN 0 +#define NAME_DEF_HW 1 + +/* + * Print the contents read from a sysctl + * variable depending on its type. + * + * @data: Data to print + * @is_str: True if a string + */ +static inline void +varbuf_print(char data[BUF_SIZE], bool is_str) +{ + uint32_t *val; + + if (is_str) { + printf("%s\n", data); + } else { + val = (uint32_t *)data; + printf("%d\n", *val); + } +} + +/* + * Convert string name to a internal name + * definition. + * + * @name: Name to convert + * + * Convert to int def + * / + * kern.ostype + * ^^ + * + * -- + * Returns a less than zero value on failure + * (e.g., entry not found). + */ +static int +name_to_def(const char *name) +{ + switch (*name) { + case 'k': + if (strcmp(name, NAME_KERN) == 0) { + return NAME_DEF_KERN; + } + + return -1; + case 'h': + if (strcmp(name, NAME_HW) == 0) { + return NAME_DEF_HW; + } + + return -1; + } + + return -1; +} + +/* + * Handle parsing of 'kern.*' node names + * + * @node: Node name to parse + * @is_str: Set to true if string + */ +static int +kern_node(const char *node, bool *is_str) +{ + switch (*node) { + case 'v': + if (strcmp(node, NAME_VERSION) == 0) { + return KERN_VERSION; + } + + if (strcmp(node, NAME_VCACHE_TYPE) == 0) { + return KERN_VCACHE_TYPE; + } + return -1; + case 'o': + if (strcmp(node, NAME_OSTYPE) == 0) { + return KERN_OSTYPE; + } + + if (strcmp(node, NAME_OSRELEASE) == 0) { + return KERN_OSRELEASE; + } + return -1; + } + + return -1; +} + +/* + * Handle parsing of 'hw.*' node names + * + * @node: Node name to parse + * @is_str: Set to true if string + */ +static int +hw_node(const char *node, bool *is_str) +{ + switch (*node) { + case 'p': + if (strcmp(node, NAME_PAGESIZE) == 0) { + *is_str = false; + return HW_PAGESIZE; + } + + return -1; + case 'n': + if (strcmp(node, NAME_NCPU) == 0) { + *is_str = false; + return HW_NCPU; + } + + return -1; + case 'm': + if (strcmp(node, NAME_MACHINE) == 0) { + return HW_MACHINE; + } + return -1; + } + + return -1; +} + +/* + * Convert string node to a sysctl name + * definition. + * + * @name: Name to convert + * @is_str: Set to true if string + * + * Convert to int def + * / + * kern.ostype + * ^^ name + * + * -- + * Returns a less than zero value on failure + * (e.g., entry not found). + */ +static int +node_to_def(int name, const char *node, bool *is_str) +{ + int retval; + bool dmmy; + + /* + * If the caller did not set `is_str' just + * set it to a dummy value. Otherwise, we will + * make it *default* to a 'true' value. + */ + if (is_str == NULL) { + is_str = &dmmy; + } else { + *is_str = true; + } + + switch (name) { + case NAME_DEF_KERN: + return kern_node(node, is_str); + case NAME_DEF_HW: + return hw_node(node, is_str); + } + + return -1; +} + +int +main(int argc, char **argv) +{ + struct sysctl_args args; + char *var, *p; + int type, error; + int root, name; + size_t oldlen; + bool is_str; + char buf[BUF_SIZE]; + + if (argc < 2) { + printf("sysctl: usage: sysctl <var>\n"); + return -1; + } + + var = argv[1]; + p = strtok(var, "."); + + if (p == NULL) { + printf("sysctl: bad var\n"); + return -1; + } + + if ((root = name_to_def(p)) < 0) { + printf("sysctl: bad var \"%s\"", p); + return root; + } + + p = strtok(NULL, "."); + if (p == NULL) { + printf("sysctl: bad var \"%s\"\n", p); + return -1; + } + + if ((name = node_to_def(root, p, &is_str)) < 0) { + printf("sysctl: bad var \"%s\"\n", p); + return name; + } + + memset(buf, 0, sizeof(buf)); + oldlen = sizeof(buf); + args.name = &name; + args.nlen = 1; + args.oldp = buf; + args.oldlenp = &oldlen; + args.newp = NULL; + args.newlen = 0; + + if ((error = sysctl(&args)) != 0) { + printf("sysctl returned %d\n", error); + return error; + } + + varbuf_print(buf, is_str); + return 0; +} diff --git a/usr.sbin/init/main.c b/usr.sbin/init/main.c index e1ee4d8..12bb98c 100644 --- a/usr.sbin/init/main.c +++ b/usr.sbin/init/main.c @@ -29,11 +29,49 @@ #include <sys/spawn.h> #include <stddef.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#define log_trace(fmt, ...) printf("[init]: " fmt, ##__VA_ARGS__) +#define log_error(fmt, ...) printf("[error]: " fmt, ##__VA_ARGS__) #define SHELL_PATH "/usr/bin/osh" #define LOGIN_PATH "/usr/bin/login" #define INIT_RC_PATH "/usr/rc/init.rc" +static void +init_hostname(void) +{ + char hostname[128]; + size_t len; + FILE *fp; + + fp = fopen("/etc/hostname", "r"); + if (fp == NULL) { + log_error("[init]: error opening /etc/hostname\n"); + return; + } + + len = fread(hostname, sizeof(char), sizeof(hostname), fp); + if (len == 0) { + log_error("[init]: error reading /etc/hostname\n"); + fclose(fp); + return; + } + + hostname[len - 1] = '\0'; + if (sethostname(hostname, len) < 0) { + log_error("[init]: error setting hostname\n"); + log_error("[init]: tried to set %s (len=%d)\n", hostname, len); + fclose(fp); + return; + } + + log_trace("hostname -> %s\n", hostname); + fclose(fp); +} + int main(int argc, char **argv) { @@ -41,7 +79,11 @@ main(int argc, char **argv) char *start_argv[] = { SHELL_PATH, INIT_RC_PATH, NULL }; char *envp[] = { NULL }; + /* Initialize the system hostname */ + init_hostname(); + /* Start the init.rc */ + log_trace("init.rc up\n"); spawn(SHELL_PATH, start_argv, envp, 0); start_argv[1] = NULL; |