summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md29
-rw-r--r--configure.ac2
-rw-r--r--etc/hostname1
-rw-r--r--lib/libc/include/ctype.h10
-rw-r--r--lib/libc/include/unistd.h16
-rw-r--r--lib/libc/src/stdio/fopen.c2
-rw-r--r--lib/libc/src/unistd/dup.c44
-rw-r--r--lib/libc/src/unistd/fork.c37
-rw-r--r--lib/libc/src/unistd/getcwd.c52
-rw-r--r--lib/libc/src/unistd/hostname.c125
-rw-r--r--lib/libc/src/unistd/symlink.c53
-rw-r--r--lib/libc/src/unistd/unlink.c53
-rw-r--r--sys/arch/amd64/amd64/intr.c8
-rw-r--r--sys/arch/amd64/amd64/ipi.c365
-rw-r--r--sys/arch/amd64/amd64/machdep.c95
-rw-r--r--sys/arch/amd64/amd64/mp.c2
-rw-r--r--sys/arch/amd64/amd64/vector.S157
-rw-r--r--sys/dev/acpi/uacpi.c109
-rw-r--r--sys/dev/usb/xhci.c56
-rw-r--r--sys/include/arch/amd64/cpu.h6
-rw-r--r--sys/include/arch/amd64/intr.h3
-rw-r--r--sys/include/arch/amd64/ipi.h109
-rw-r--r--sys/include/dev/acpi/tables.h37
-rw-r--r--sys/include/dev/usb/xhciregs.h1
-rw-r--r--sys/include/sys/sysctl.h12
-rw-r--r--sys/include/sys/systm.h1
-rw-r--r--sys/kern/init_main.c3
-rw-r--r--sys/kern/kern_cpu.c61
-rw-r--r--sys/kern/kern_descrip.c2
-rw-r--r--sys/kern/kern_sysctl.c77
-rw-r--r--usr.bin/fetch/fetch.c2
-rw-r--r--usr.bin/osh/osh.c6
-rw-r--r--usr.bin/sysctl/sysctl.c172
-rw-r--r--usr.sbin/init/main.c42
34 files changed, 1610 insertions, 140 deletions
diff --git a/README.md b/README.md
index b27656e..aa94189 100644
--- a/README.md
+++ b/README.md
@@ -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:
--------------
![Hyra](./.github/assets/hyra.png)
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..2a827e3 100644
--- a/lib/libc/include/ctype.h
+++ b/lib/libc/include/ctype.h
@@ -36,6 +36,12 @@
__BEGIN_DECLS
__always_inline static inline int
+__isascii(int c)
+{
+ return c >= 0 && c <= 127;
+}
+
+__always_inline static inline int
__tolower(int c)
{
return c | 0x20;
@@ -72,6 +78,7 @@ __isspace(int c)
return 1;
return 0;
+ }
}
__END_DECLS
@@ -91,4 +98,7 @@ __END_DECLS
/* Is a space? */
#define isspace(C) __isspace((C))
+/* Is ascii? */
+#define isascii(C) __isascii((C))
+
#endif /* _CTYPE_H */
diff --git a/lib/libc/include/unistd.h b/lib/libc/include/unistd.h
index 8b03b81..40ebee2 100644
--- a/lib/libc/include/unistd.h
+++ b/lib/libc/include/unistd.h
@@ -47,18 +47,34 @@ __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;
diff --git a/lib/libc/src/stdio/fopen.c b/lib/libc/src/stdio/fopen.c
index c15dace..efeb577 100644
--- a/lib/libc/src/stdio/fopen.c
+++ b/lib/libc/src/stdio/fopen.c
@@ -51,6 +51,8 @@ fopen(const char *__restrict path, const char *__restrict mode)
seal |= (O_WRONLY | O_CREAT);
} else if (strcmp(mode, "r+") == 0) {
seal |= O_RDWR;
+ } else if (strcmp(mode, "rb") == 0) {
+ seal |= O_RDONLY;
} else {
return NULL;
}
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/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
index a545788..c44c88e 100644
--- a/sys/arch/amd64/amd64/intr.c
+++ b/sys/arch/amd64/amd64/intr.c
@@ -98,12 +98,12 @@ intr_register(const char *name, const struct intr_hand *ih)
* Try to allocate an interrupt vector. An IPL is made up
* of 4 bits so there can be 16 vectors per IPL.
*
- * XXX: Vector 0x20 is reserved for the Hyra scheduler,
- * vector 0x21 is reserved for the CPU halt IPI,
- * and vector 0x22 is reserved for TLB shootdowns.
+ * XXX: Vector 0x20 is reserved for the Hyra scheduler and
+ * vectors 0x21 to 0x21 + N_IPIVEC are reserved for
+ * inter-processor interrupts.
*/
for (int i = vec; i < vec + 16; ++i) {
- if (g_intrs[i] != NULL || i < 0x23) {
+ if (g_intrs[i] != NULL || i < 0x24) {
continue;
}
diff --git a/sys/arch/amd64/amd64/ipi.c b/sys/arch/amd64/amd64/ipi.c
new file mode 100644
index 0000000..ffa291f
--- /dev/null
+++ b/sys/arch/amd64/amd64/ipi.c
@@ -0,0 +1,365 @@
+/*
+ * 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/syslog.h>
+#include <sys/param.h>
+#include <sys/panic.h>
+#include <sys/spinlock.h>
+#include <machine/cpu.h>
+#include <machine/idt.h>
+#include <machine/ipi.h>
+#include <machine/lapic.h>
+#include <string.h>
+
+void ipi_isr0(void);
+void ipi_isr1(void);
+void ipi_isr2(void);
+void ipi_isr3(void);
+
+void __ipi_handle_common(void);
+
+#define pr_trace(fmt, ...) kprintf("ipi: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+#define BASE_VECTOR 0x21
+#define COOKIE 0x7E0A
+
+/* For the global state of the subsystem */
+static uint32_t cookie = 0;
+
+/*
+ * The next vector that will be used for an IPI to
+ * be allocated. It starts at 0x21 because interrupt
+ * vector 0x20 is used for the Hyra scheduler and `N_IPIVEC'
+ * vectors up are reserved for inter-processor interrupts.
+ *
+ * XXX: This must not go beyond N_IPIVEC !!
+ */
+static uint8_t next_vec = BASE_VECTOR;
+static uint8_t vec_entries = 0;
+
+/*
+ * In order to get an index into the 'vectors' array,
+ * one can pass an `ipi_bitmap' bit index into the
+ * ipi_vector() function. The index into the `ipi`
+ * field within may be acquired with the ipi_index()
+ * function.
+ */
+static uint64_t ipi_bitmap = 0;
+static struct ipi_vector vectors[N_IPIVEC];
+static struct spinlock lock;
+
+/*
+ * Allocate a bit from the `ipi_bitmap' and
+ * return the index.
+ *
+ * Returns a less than zero value upon error.
+ */
+static ssize_t
+alloc_ipi_bit(void)
+{
+ const size_t MAX = sizeof(ipi_bitmap) * 8;
+ off_t i;
+
+ for (i = 0; i < MAX; ++i) {
+ if (!ISSET(ipi_bitmap, BIT(i))) {
+ ipi_bitmap |= BIT(i);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Allocate an IPI that can be sent to other
+ * cores on the CPU. This is the core logic
+ * and contains *no* locks. One should be
+ * using the md_ipi_alloc() function instead.
+ *
+ * Returns the allocated IPI identifier on succes,
+ * otherwise a less than zero value is returned.
+ */
+static int
+__ipi_alloc(struct cpu_ipi **res)
+{
+ struct ipi_vector *vp;
+ struct cpu_ipi *ipip;
+ ssize_t bit;
+ uint8_t idx;
+
+ if (res == NULL) {
+ return -EINVAL;
+ }
+
+ if (next_vec >= BASE_VECTOR + N_IPIVEC) {
+ return -EAGAIN;
+ }
+
+ /*
+ * Attempt to allocate a bit index from
+ * the bitmap.
+ */
+ if ((bit = alloc_ipi_bit()) < 0) {
+ return -EAGAIN;
+ }
+
+ idx = ipi_vector(bit);
+ vp = &vectors[idx];
+
+ /* Initialize the vector if not already */
+ if (vp->cookie != COOKIE) {
+ vp->cookie = COOKIE;
+ vp->nipi = 0;
+ vp->vec = next_vec;
+ memset(vp->ipi, 0, sizeof(vp->ipi));
+ }
+
+ /*
+ * Just a sanity check here, the number of
+ * IPIs per vector should never exceed the
+ * maximum, and if it does, that gives us more
+ * than enough grounds to panic the system as
+ * it would not be wise to trust it.
+ */
+ if (__unlikely(vp->nipi >= IPI_PER_VEC)) {
+ panic("too many IPIs in vector %x\n", vp->vec);
+ }
+
+ idx = ipi_index(bit);
+ ipip = &vp->ipi[idx];
+
+ /* We are allocating, not clobbering */
+ if (ipip->cookie == COOKIE) {
+ panic("ipi table corruption\n");
+ }
+
+ if ((++vec_entries) >= IPI_PER_VEC) {
+ vec_entries = 0;
+ ++next_vec;
+ }
+
+ /* Set up the initial state */
+ ipip->cookie = COOKIE;
+ ipip->handler = NULL;
+ ipip->id = bit;
+ *res = ipip;
+ return bit;
+}
+
+/*
+ * Dispatch pending IPIs for the current
+ * processor.
+ *
+ * @vector: Backing interrupt vector
+ * @ci: Current processor
+ */
+static void
+ipi_dispatch_pending(struct ipi_vector *vec, struct cpu_info *ci)
+{
+ uint8_t bit_i;
+ uint8_t n_bit;
+ uint8_t index;
+ struct cpu_ipi *ipip = NULL;
+ ipi_pend_t pending;
+
+ if (vec == NULL || ci == NULL) {
+ return;
+ }
+
+ n_bit = sizeof(pending) * 8;
+ for (bit_i = 0; bit_i < n_bit; ++bit_i) {
+ index = ipi_vector(bit_i);
+ pending = ci->ipi_pending[index];
+
+ vec = &vectors[index];
+ index = ipi_index(bit_i);
+ ipip = &vec->ipi[index];
+
+ /* Is this pending or not? */
+ if (!ISSET(pending, BIT(bit_i))) {
+ continue;
+ }
+
+ /* Handle and mark as no longer pending */
+ ipip->handler(ipip);
+ ci->ipi_pending[vec->vec] &= ~BIT(bit_i);
+ }
+}
+
+/*
+ * Check an IPI pending bitmap for a
+ * vector and send IPIs as needed
+ *
+ * @ci: Target processor
+ * @pending: Pending IPIs
+ */
+static void
+ipi_send_vector(struct cpu_info *ci, ipi_pend_t pending)
+{
+ struct ipi_vector *vp;
+ struct cpu_ipi *ipip;
+ uint8_t n_bits = sizeof(pending) * 8;
+ uint8_t bit_i;
+ uint8_t vector, index;
+ uint32_t apic_id = 0;
+
+ if (ci != NULL) {
+ /*
+ * We are already dispatching IPIs, we don't
+ * want to find ourselves in interrupt hell.
+ */
+ if (ci->ipi_dispatch) {
+ return;
+ }
+
+ apic_id = ci->apicid;
+ }
+
+ ci->ipi_dispatch = 1;
+ for (bit_i = 0; bit_i < n_bits; ++bit_i) {
+ if (ISSET(pending, BIT(bit_i))) {
+ vector = ipi_vector(bit_i);
+ index = ipi_index(bit_i);
+
+ if (ci != NULL)
+ ci->ipi_id = bit_i;
+
+ vp = &vectors[vector];
+ ipip = &vp->ipi[index];
+
+ /* Ignore if cookie does match */
+ if (ipip->cookie != COOKIE)
+ continue;
+
+ /* Ignore if there is no handler */
+ if (ipip->handler == NULL)
+ continue;
+
+ /* Send that IPI through */
+ lapic_send_ipi(
+ apic_id,
+ IPI_SHORTHAND_NONE,
+ BASE_VECTOR + vector
+ );
+ }
+ }
+}
+
+/*
+ * Common IPI routine, called from vector.S
+ *
+ * XXX: Internal usage only
+ */
+void
+__ipi_handle_common(void)
+{
+ struct ipi_vector *vp;
+ struct cpu_info *ci = this_cpu();
+ uint8_t vector;
+
+ if (cookie != COOKIE) {
+ pr_trace("[warn]: got spurious ipi\n");
+ return;
+ }
+
+ /* Grab the vector */
+ vector = ipi_vector(ci->ipi_id);
+ vp = &vectors[vector];
+ if (vp->cookie != COOKIE) {
+ pr_error("got IPI for uninitialized vector\n");
+ return;
+ }
+
+ if ((ci = this_cpu()) == NULL) {
+ pr_error("could not get current CPU\n");
+ return;
+ }
+
+ ipi_dispatch_pending(vp, ci);
+
+ /* We are done dispatching IPIs */
+ ci->ipi_dispatch = 0;
+ ci->ipi_id = 0;
+}
+
+/*
+ * Send one or more IPIs to a specific
+ * processor after caller sets bits in
+ * the `ci->ipi_pending' field
+ *
+ * @ci: Processor to send IPI(s) to
+ */
+int
+md_ipi_send(struct cpu_info *ci)
+{
+ if (ci == NULL) {
+ return -EINVAL;
+ }
+
+ spinlock_acquire(&lock);
+ for (int i = 0; i < N_IPIVEC; ++i) {
+ ipi_send_vector(ci, ci->ipi_pending[i]);
+ }
+
+ spinlock_release(&lock);
+ return 0;
+}
+
+
+/*
+ * IPI allocation interface with
+ * locking.
+ */
+int
+md_ipi_alloc(struct cpu_ipi **res)
+{
+ int retval;
+
+ spinlock_acquire(&lock);
+ retval = __ipi_alloc(res);
+ spinlock_release(&lock);
+ return retval;
+}
+
+/*
+ * Initialize the IPI thunks
+ */
+void
+md_ipi_init(void)
+{
+ /* Initialize the IPI vectors */
+ idt_set_desc(0x21, IDT_INT_GATE, ISR(ipi_isr0), 0);
+ idt_set_desc(0x22, IDT_INT_GATE, ISR(ipi_isr1), 0);
+ idt_set_desc(0x23, IDT_INT_GATE, ISR(ipi_isr2), 0);
+ idt_set_desc(0x24, IDT_INT_GATE, ISR(ipi_isr3), 0);
+ cookie = COOKIE;
+}
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 9ff96e1..3f8580a 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -42,6 +42,7 @@
#include <machine/uart.h>
#include <machine/sync.h>
#include <machine/intr.h>
+#include <machine/ipi.h>
#include <machine/cdefs.h>
#include <machine/isa/i8042var.h>
#include <dev/cons/cons.h>
@@ -61,9 +62,6 @@
pr_trace(__VA_ARGS__); \
}
-#define HALT_VECTOR 0x21
-#define TLB_VECTOR 0x22
-
#if defined(__SPECTRE_IBRS)
#define SPECTRE_IBRS __SPECTRE_IBRS
#else
@@ -82,19 +80,20 @@ void syscall_isr(void);
void pin_isr_load(void);
struct cpu_info g_bsp_ci = {0};
+static struct cpu_ipi *halt_ipi;
+static struct cpu_ipi *tlb_ipi;
+static struct spinlock ipi_lock = {0};
static bool bsp_init = false;
-__attribute__((__interrupt__))
-static void
-cpu_halt_isr(void *p)
+static int
+cpu_halt_handler(struct cpu_ipi *ipi)
{
__ASMV("cli; hlt");
__builtin_unreachable();
}
-__attribute__((__interrupt__))
-static void
-tlb_shootdown_isr(void *p)
+static int
+tlb_shootdown_handler(struct cpu_ipi *ipi)
{
struct cpu_info *ci;
int ipl;
@@ -106,7 +105,7 @@ tlb_shootdown_isr(void *p)
*/
ci = this_cpu();
if (!ci->tlb_shootdown) {
- return;
+ return -1;
}
ipl = splraise(IPL_HIGH);
@@ -115,6 +114,7 @@ tlb_shootdown_isr(void *p)
ci->shootdown_va = 0;
ci->tlb_shootdown = 0;
splx(ipl);
+ return 0;
}
static void
@@ -141,8 +141,6 @@ setup_vectors(struct cpu_info *ci)
idt_set_desc(0xD, IDT_TRAP_GATE, ISR(general_prot), 0);
idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0);
idt_set_desc(0x80, IDT_USER_INT_GATE, ISR(syscall_isr), IST_SYSCALL);
- idt_set_desc(HALT_VECTOR, IDT_INT_GATE, ISR(cpu_halt_isr), 0);
- idt_set_desc(TLB_VECTOR, IDT_INT_GATE, ISR(tlb_shootdown_isr), 0);
pin_isr_load();
}
@@ -202,6 +200,44 @@ enable_simd(void)
}
static void
+init_ipis(void)
+{
+ int error;
+
+ if (bsp_init) {
+ return;
+ }
+
+ spinlock_acquire(&ipi_lock);
+ error = md_ipi_alloc(&halt_ipi);
+ if (error < 0) {
+ pr_error("md_ipi_alloc: returned %d\n", error);
+ panic("failed to init halt IPI\n");
+ }
+
+ halt_ipi->handler = cpu_halt_handler;
+ error = md_ipi_alloc(&tlb_ipi);
+ if (error < 0) {
+ pr_error("md_ipi_alloc: returned %d\n", error);
+ panic("failed to init TLB IPI\n");
+ }
+
+ tlb_ipi->handler = tlb_shootdown_handler;
+
+ /*
+ * Some IPIs must have very specific IDs
+ * so that they are standard and usable
+ * throughout the rest of the sytem.
+ */
+ if (halt_ipi->id != IPI_HALT)
+ panic("expected IPI_HALT for halt IPI\n");
+ if (tlb_ipi->id != IPI_TLB)
+ panic("expected IPI_TLB for TLB IPI\n");
+
+ spinlock_release(&ipi_lock);
+}
+
+static void
cpu_get_info(struct cpu_info *ci)
{
uint32_t eax, ebx, unused;
@@ -257,7 +293,7 @@ cpu_shootdown_tlb(vaddr_t va)
spinlock_acquire(&cip->lock);
cip->shootdown_va = va;
cip->tlb_shootdown = 1;
- lapic_send_ipi(cip->apicid, IPI_SHORTHAND_NONE, TLB_VECTOR);
+ cpu_ipi_send(cip, IPI_TLB);
spinlock_release(&cip->lock);
}
}
@@ -309,6 +345,9 @@ md_backtrace(void)
void
cpu_halt_all(void)
{
+ struct cpu_info *ci;
+ uint32_t ncpu;
+
/*
* If we have no current 'cpu_info' structure set,
* we can't send IPIs, so just assume only the current
@@ -319,8 +358,15 @@ cpu_halt_all(void)
__ASMV("cli; hlt");
}
- /* Send IPI to all cores */
- lapic_send_ipi(0, IPI_SHORTHAND_ALL, HALT_VECTOR);
+ for (int i = 0; i < ncpu; ++i) {
+ ci = cpu_get(i);
+ if (ci == NULL) {
+ continue;
+ }
+
+ cpu_ipi_send(ci, IPI_HALT);
+ }
+
for (;;);
}
@@ -331,12 +377,24 @@ cpu_halt_all(void)
void
cpu_halt_others(void)
{
+ struct cpu_info *curcpu, *ci;
+ uint32_t ncpu;
+
if (rdmsr(IA32_GS_BASE) == 0) {
__ASMV("cli; hlt");
}
- /* Send IPI to all cores */
- lapic_send_ipi(0, IPI_SHORTHAND_OTHERS, HALT_VECTOR);
+ curcpu = this_cpu();
+ ncpu = cpu_count();
+
+ for (int i = 0; i < ncpu; ++i) {
+ if ((ci = cpu_get(i)) == NULL)
+ continue;
+ if (ci->id == curcpu->id)
+ continue;
+
+ cpu_ipi_send(ci, IPI_HALT);
+ }
}
void
@@ -441,7 +499,10 @@ cpu_startup(struct cpu_info *ci)
wrmsr(IA32_GS_BASE, (uintptr_t)ci);
init_tss(ci);
+
setup_vectors(ci);
+ md_ipi_init();
+ init_ipis();
try_mitigate_spectre();
ci->online = 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/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index 890b314..19c68d5 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -73,72 +73,101 @@ done:
.globl pin_isr_load
pin_isr_load:
- IDT_SET_VEC 35, ioapic_edge_0
- IDT_SET_VEC 36, ioapic_edge_1
- IDT_SET_VEC 37, ioapic_edge_2
- IDT_SET_VEC 38, ioapic_edge_3
- IDT_SET_VEC 39, ioapic_edge_4
- IDT_SET_VEC 40, ioapic_edge_5
- IDT_SET_VEC 41, ioapic_edge_6
- IDT_SET_VEC 42, ioapic_edge_7
- IDT_SET_VEC 43, ioapic_edge_8
- IDT_SET_VEC 44, ioapic_edge_9
- IDT_SET_VEC 45, ioapic_edge_10
- IDT_SET_VEC 46, ioapic_edge_11
- IDT_SET_VEC 47, ioapic_edge_12
- IDT_SET_VEC 48, ioapic_edge_13
- IDT_SET_VEC 49, ioapic_edge_14
- IDT_SET_VEC 50, ioapic_edge_15
- IDT_SET_VEC 51, ioapic_edge_16
- IDT_SET_VEC 52, ioapic_edge_17
- IDT_SET_VEC 53, ioapic_edge_18
- IDT_SET_VEC 54, ioapic_edge_19
- IDT_SET_VEC 55, ioapic_edge_20
- IDT_SET_VEC 56, ioapic_edge_21
- IDT_SET_VEC 57, ioapic_edge_22
- IDT_SET_VEC 58, ioapic_edge_23
- IDT_SET_VEC 59, ioapic_edge_24
- IDT_SET_VEC 60, ioapic_edge_25
- IDT_SET_VEC 61, ioapic_edge_26
- IDT_SET_VEC 62, ioapic_edge_27
- IDT_SET_VEC 63, ioapic_edge_28
- IDT_SET_VEC 64, ioapic_edge_29
- IDT_SET_VEC 65, ioapic_edge_30
- IDT_SET_VEC 66, ioapic_edge_31
- IDT_SET_VEC 67, ioapic_edge_32
- IDT_SET_VEC 68, ioapic_edge_33
- IDT_SET_VEC 69, ioapic_edge_34
- IDT_SET_VEC 70, ioapic_edge_35
- IDT_SET_VEC 71, ioapic_edge_36
- IDT_SET_VEC 72, ioapic_edge_37
- IDT_SET_VEC 73, ioapic_edge_38
- IDT_SET_VEC 74, ioapic_edge_39
- IDT_SET_VEC 75, ioapic_edge_40
- IDT_SET_VEC 76, ioapic_edge_41
- IDT_SET_VEC 77, ioapic_edge_42
- IDT_SET_VEC 78, ioapic_edge_43
- IDT_SET_VEC 79, ioapic_edge_44
- IDT_SET_VEC 80, ioapic_edge_45
- IDT_SET_VEC 81, ioapic_edge_46
- IDT_SET_VEC 82, ioapic_edge_47
- IDT_SET_VEC 83, ioapic_edge_48
- IDT_SET_VEC 84, ioapic_edge_49
- IDT_SET_VEC 85, ioapic_edge_50
- IDT_SET_VEC 86, ioapic_edge_51
- IDT_SET_VEC 87, ioapic_edge_52
- IDT_SET_VEC 88, ioapic_edge_53
- IDT_SET_VEC 89, ioapic_edge_54
- IDT_SET_VEC 90, ioapic_edge_55
- IDT_SET_VEC 91, ioapic_edge_56
- IDT_SET_VEC 92, ioapic_edge_57
- IDT_SET_VEC 93, ioapic_edge_58
- IDT_SET_VEC 94, ioapic_edge_59
- IDT_SET_VEC 95, ioapic_edge_60
- IDT_SET_VEC 96, ioapic_edge_61
- IDT_SET_VEC 97, ioapic_edge_62
- IDT_SET_VEC 97, ioapic_edge_63
+ IDT_SET_VEC 37, ioapic_edge_0
+ IDT_SET_VEC 38, ioapic_edge_1
+ IDT_SET_VEC 39, ioapic_edge_2
+ IDT_SET_VEC 40, ioapic_edge_3
+ IDT_SET_VEC 41, ioapic_edge_4
+ IDT_SET_VEC 42, ioapic_edge_5
+ IDT_SET_VEC 43, ioapic_edge_6
+ IDT_SET_VEC 44, ioapic_edge_7
+ IDT_SET_VEC 45, ioapic_edge_8
+ IDT_SET_VEC 46, ioapic_edge_9
+ IDT_SET_VEC 47, ioapic_edge_10
+ IDT_SET_VEC 48, ioapic_edge_11
+ IDT_SET_VEC 49, ioapic_edge_12
+ IDT_SET_VEC 50, ioapic_edge_13
+ IDT_SET_VEC 51, ioapic_edge_14
+ IDT_SET_VEC 52, ioapic_edge_15
+ IDT_SET_VEC 53, ioapic_edge_16
+ IDT_SET_VEC 54, ioapic_edge_17
+ IDT_SET_VEC 55, ioapic_edge_18
+ IDT_SET_VEC 56, ioapic_edge_19
+ IDT_SET_VEC 57, ioapic_edge_20
+ IDT_SET_VEC 58, ioapic_edge_21
+ IDT_SET_VEC 59, ioapic_edge_22
+ IDT_SET_VEC 60, ioapic_edge_23
+ IDT_SET_VEC 61, ioapic_edge_24
+ IDT_SET_VEC 62, ioapic_edge_25
+ IDT_SET_VEC 63, ioapic_edge_26
+ IDT_SET_VEC 64, ioapic_edge_27
+ IDT_SET_VEC 65, ioapic_edge_28
+ IDT_SET_VEC 66, ioapic_edge_29
+ IDT_SET_VEC 67, ioapic_edge_30
+ IDT_SET_VEC 68, ioapic_edge_31
+ IDT_SET_VEC 69, ioapic_edge_32
+ IDT_SET_VEC 70, ioapic_edge_33
+ IDT_SET_VEC 71, ioapic_edge_34
+ IDT_SET_VEC 72, ioapic_edge_35
+ IDT_SET_VEC 73, ioapic_edge_36
+ IDT_SET_VEC 74, ioapic_edge_37
+ IDT_SET_VEC 75, ioapic_edge_38
+ IDT_SET_VEC 76, ioapic_edge_39
+ IDT_SET_VEC 77, ioapic_edge_40
+ IDT_SET_VEC 78, ioapic_edge_41
+ IDT_SET_VEC 79, ioapic_edge_42
+ IDT_SET_VEC 80, ioapic_edge_43
+ IDT_SET_VEC 81, ioapic_edge_44
+ IDT_SET_VEC 82, ioapic_edge_45
+ IDT_SET_VEC 83, ioapic_edge_46
+ IDT_SET_VEC 84, ioapic_edge_47
+ IDT_SET_VEC 85, ioapic_edge_48
+ IDT_SET_VEC 86, ioapic_edge_49
+ IDT_SET_VEC 87, ioapic_edge_50
+ IDT_SET_VEC 88, ioapic_edge_51
+ IDT_SET_VEC 89, ioapic_edge_52
+ IDT_SET_VEC 90, ioapic_edge_53
+ IDT_SET_VEC 91, ioapic_edge_54
+ IDT_SET_VEC 92, ioapic_edge_55
+ IDT_SET_VEC 93, ioapic_edge_56
+ IDT_SET_VEC 94, ioapic_edge_57
+ IDT_SET_VEC 95, ioapic_edge_58
+ IDT_SET_VEC 96, ioapic_edge_59
+ IDT_SET_VEC 97, ioapic_edge_60
+ IDT_SET_VEC 98, ioapic_edge_61
+ IDT_SET_VEC 99, ioapic_edge_62
+ IDT_SET_VEC 100, ioapic_edge_63
ret
+ .globl ipi_isr0
+INTRENTRY(ipi_isr0, ipi_trampoline)
+ call ipi_trampoline
+ retq
+
+ .globl ipi_isr1
+INTRENTRY(ipi_isr1, ipi_trampoline)
+ call ipi_trampoline
+ retq
+
+ .globl ipi_isr2
+INTRENTRY(ipi_isr2, ipi_trampoline)
+ call ipi_trampoline
+ retq
+
+ .globl ipi_isr3
+INTRENTRY(ipi_isr3, ipi_trampoline)
+ call ipi_trampoline
+ retq
+
+/*
+ * Hyra supports 16 IPI handlers per 4 reserved
+ * IDT vectors. That allows for a maximum of
+ * 64 IPIs.
+ */
+ipi_trampoline:
+ call __ipi_handle_common
+ retq
+
/* I/O APIC edge ISRs */
INTRENTRY(ioapic_edge_0, ioapic_common_func)
INTRENTRY(ioapic_edge_1, ioapic_common_func)
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/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index 116661b..4586163 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -37,6 +37,7 @@
#include <sys/spinlock.h>
#include <machine/tss.h>
#include <machine/cdefs.h>
+#include <machine/intr.h>
#define CPU_IRQ(IRQ_N) (BIT((IRQ_N)) & 0xFF)
@@ -44,9 +45,14 @@
#define CPU_FEAT_SMAP BIT(0)
#define CPU_FEAT_SMEP BIT(1)
+typedef uint16_t ipi_pend_t;
+
struct cpu_info {
uint32_t apicid;
uint32_t feat;
+ uint8_t ipi_dispatch : 1; /* 1: IPIs being dispatched */
+ uint8_t ipi_id;
+ ipi_pend_t ipi_pending[N_IPIVEC];
uint8_t id; /* MI Logical ID */
uint8_t model : 4; /* CPU model number */
uint8_t family : 4; /* CPU family ID */
diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h
index 3870f18..6d9bb09 100644
--- a/sys/include/arch/amd64/intr.h
+++ b/sys/include/arch/amd64/intr.h
@@ -48,6 +48,9 @@
#define IPL_CLOCK 2 /* Clock */
#define IPL_HIGH 3 /* Defer everything */
+#define N_IPIVEC 4 /* Number of vectors reserved for IPIs */
+#define IPI_PER_VEC 16 /* Max IPIs per vector */
+
struct intr_hand;
/*
diff --git a/sys/include/arch/amd64/ipi.h b/sys/include/arch/amd64/ipi.h
new file mode 100644
index 0000000..1a3b51c
--- /dev/null
+++ b/sys/include/arch/amd64/ipi.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef _MACHINE_IPI_H_
+#define _MACHINE_IPI_H_
+
+#include <sys/types.h>
+#include <machine/cpu.h>
+#include <machine/lapic.h>
+
+/* Fixed IPI IDs */
+#define IPI_HALT 0
+#define IPI_TLB 1
+
+/*
+ * Represents an interprocessor interrupt
+ * handler.
+ *
+ * @cookie: Used to verifying an instance
+ * @id: IPI ID (identifies the IPI)
+ * @mask: If set, IPIs are ignored
+ * @handler: Handler routine
+ */
+struct cpu_ipi {
+ uint16_t cookie;
+ uint8_t id;
+ int(*handler)(struct cpu_ipi *ipi);
+};
+
+/*
+ * Represents an interrupt vector for a
+ * specific IPI
+ *
+ * @ipi: IPIs associated with this vector
+ * @cookie: Used to verify an instance
+ * @nipi: Number of IPIs associated
+ * @vec: System interrupt vector number
+ */
+struct ipi_vector {
+ struct cpu_ipi ipi[IPI_PER_VEC];
+ uint16_t cookie;
+ uint8_t nipi;
+ uint8_t vec;
+};
+
+int md_ipi_alloc(struct cpu_ipi **res);
+int md_ipi_send(struct cpu_info *ci);
+void md_ipi_init(void);
+
+/*
+ * Get the vector an IPI belongs to
+ *
+ * @ipi: IPI to check
+ */
+__always_inline static inline uint8_t
+ipi_vector(uint8_t ipi)
+{
+ return ipi / N_IPIVEC;
+}
+
+/*
+ * Get the handler index an IPI belongs
+ * to
+ *
+ * @ipi: IPI to check
+ */
+__always_inline static inline uint8_t
+ipi_index(uint8_t ipi)
+{
+ return ipi % (sizeof(ipi_pend_t) * 8);
+}
+
+__always_inline static inline int
+cpu_ipi_send(struct cpu_info *ci, uint8_t ipi)
+{
+ uint8_t vec = ipi_vector(ipi);
+ uint8_t idx = ipi_index(ipi);
+
+ ci->ipi_pending[vec] |= BIT(idx);
+ return md_ipi_send(ci);
+}
+
+#endif /* !_MACHINE_IPI_H_ */
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/usr.bin/fetch/fetch.c b/usr.bin/fetch/fetch.c
index c81ee84..1e8ef92 100644
--- a/usr.bin/fetch/fetch.c
+++ b/usr.bin/fetch/fetch.c
@@ -33,8 +33,6 @@
#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) \
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/sysctl.c b/usr.bin/sysctl/sysctl.c
index a23bfe8..d4275a7 100644
--- a/usr.bin/sysctl/sysctl.c
+++ b/usr.bin/sysctl/sysctl.c
@@ -31,14 +31,51 @@
#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 sysctl name
+ * Convert string name to a internal name
* definition.
*
* @name: Name to convert
@@ -46,7 +83,7 @@
* Convert to int def
* /
* kern.ostype
- * ^^ name
+ * ^^
*
* --
* Returns a less than zero value on failure
@@ -56,26 +93,128 @@ 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(name, NAME_VERSION) == 0) {
+ if (strcmp(node, NAME_VERSION) == 0) {
return KERN_VERSION;
}
- if (strcmp(name, NAME_VCACHE_TYPE) == 0) {
+ if (strcmp(node, NAME_VCACHE_TYPE) == 0) {
return KERN_VCACHE_TYPE;
}
-
return -1;
case 'o':
- if (strcmp(name, NAME_OSTYPE) == 0) {
+ if (strcmp(node, NAME_OSTYPE) == 0) {
return KERN_OSTYPE;
}
- if (strcmp(name, NAME_OSRELEASE) == 0) {
+ 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;
@@ -86,9 +225,11 @@ main(int argc, char **argv)
{
struct sysctl_args args;
char *var, *p;
- int type, name, error;
+ int type, error;
+ int root, name;
size_t oldlen;
- char buf[128];
+ bool is_str;
+ char buf[BUF_SIZE];
if (argc < 2) {
printf("sysctl: usage: sysctl <var>\n");
@@ -103,10 +244,9 @@ main(int argc, char **argv)
return -1;
}
- /* TODO: Non kern.* vars */
- if (strcmp(p, "kern") != 0) {
- printf("unknown var \"%s\"\n", p);
- return -1;
+ if ((root = name_to_def(p)) < 0) {
+ printf("sysctl: bad var \"%s\"", p);
+ return root;
}
p = strtok(NULL, ".");
@@ -115,12 +255,12 @@ main(int argc, char **argv)
return -1;
}
- if ((name = name_to_def(p)) < 0) {
+ if ((name = node_to_def(root, p, &is_str)) < 0) {
printf("sysctl: bad var \"%s\"\n", p);
return name;
}
- name = name;
+ memset(buf, 0, sizeof(buf));
oldlen = sizeof(buf);
args.name = &name;
args.nlen = 1;
@@ -134,6 +274,6 @@ main(int argc, char **argv)
return error;
}
- printf("%s\n", buf);
+ 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;