summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/Makefile32
-rw-r--r--usr.bin/beep/Makefile6
-rw-r--r--usr.bin/beep/main.c70
-rw-r--r--usr.bin/cat/Makefile6
-rw-r--r--usr.bin/cat/cat.c112
-rw-r--r--usr.bin/date/Makefile6
-rw-r--r--usr.bin/date/date.c132
-rw-r--r--usr.bin/dmidump/Makefile6
-rw-r--r--usr.bin/dmidump/dmidump.c78
-rw-r--r--usr.bin/echo/Makefile6
-rw-r--r--usr.bin/echo/echo.c44
-rw-r--r--usr.bin/elfdump/Makefile6
-rw-r--r--usr.bin/elfdump/elfdump.c171
-rw-r--r--usr.bin/fetch/Makefile6
-rw-r--r--usr.bin/fetch/fetch.c105
-rw-r--r--usr.bin/getconf/Makefile6
-rw-r--r--usr.bin/getconf/getconf.c93
-rw-r--r--usr.bin/kfgwm/Makefile6
-rw-r--r--usr.bin/kfgwm/font.c379
-rw-r--r--usr.bin/kfgwm/include/kfg/font.h40
-rw-r--r--usr.bin/kfgwm/include/kfg/types.h40
-rw-r--r--usr.bin/kfgwm/include/kfg/window.h68
-rw-r--r--usr.bin/kfgwm/kfgwm.c95
-rw-r--r--usr.bin/kfgwm/window.c221
-rw-r--r--usr.bin/kmsg/Makefile6
-rw-r--r--usr.bin/kmsg/kmsg.c58
-rw-r--r--usr.bin/kstat/Makefile6
-rw-r--r--usr.bin/kstat/kstat.c122
-rw-r--r--usr.bin/link.ld5
-rw-r--r--usr.bin/login/Makefile6
-rw-r--r--usr.bin/login/login.c295
-rw-r--r--usr.bin/mex/Makefile6
-rw-r--r--usr.bin/mex/mex.c105
-rw-r--r--usr.bin/mrow/Makefile6
-rw-r--r--usr.bin/mrow/mrow.c287
-rw-r--r--usr.bin/nerve/Makefile6
-rw-r--r--usr.bin/nerve/nerve.c377
-rw-r--r--usr.bin/notes/Makefile6
-rw-r--r--usr.bin/notes/notes.c132
-rw-r--r--usr.bin/oasm/Makefile7
-rw-r--r--usr.bin/oasm/emit.c564
-rw-r--r--usr.bin/oasm/include/oasm/emit.h120
-rw-r--r--usr.bin/oasm/include/oasm/label.h55
-rw-r--r--usr.bin/oasm/include/oasm/lex.h188
-rw-r--r--usr.bin/oasm/include/oasm/log.h48
-rw-r--r--usr.bin/oasm/include/oasm/parse.h37
-rw-r--r--usr.bin/oasm/include/oasm/state.h59
-rw-r--r--usr.bin/oasm/label.c166
-rw-r--r--usr.bin/oasm/lex.c445
-rw-r--r--usr.bin/oasm/log.c81
-rw-r--r--usr.bin/oasm/oasm.c73
-rw-r--r--usr.bin/oasm/parse.c285
-rw-r--r--usr.bin/oemu/Makefile7
-rw-r--r--usr.bin/oemu/cpu.c523
-rw-r--r--usr.bin/oemu/emu.c127
-rw-r--r--usr.bin/oemu/include/oemu/cpu.h83
-rw-r--r--usr.bin/oemu/include/oemu/osmx64.h90
-rw-r--r--usr.bin/oemu/include/oemu/types.h40
-rw-r--r--usr.bin/osh/osh.c416
-rw-r--r--usr.bin/readcore/Makefile6
-rw-r--r--usr.bin/readcore/core.c50
-rw-r--r--usr.bin/readcore/crc32.c91
-rw-r--r--usr.bin/readcore/include/core.h44
-rw-r--r--usr.bin/readcore/include/crc32.h37
-rw-r--r--usr.bin/readcore/include/frame.h107
-rw-r--r--usr.bin/readcore/readcore.c78
-rw-r--r--usr.bin/reboot/Makefile6
-rw-r--r--usr.bin/reboot/reboot.c87
-rw-r--r--usr.bin/screensave/Makefile6
-rw-r--r--usr.bin/screensave/screensave.c116
-rw-r--r--usr.bin/sleep/Makefile6
-rw-r--r--usr.bin/sleep/sleep.c55
-rw-r--r--usr.bin/sysctl/Makefile6
-rw-r--r--usr.bin/sysctl/sysctl.c314
-rw-r--r--usr.bin/whoami/Makefile6
-rw-r--r--usr.bin/whoami/whoami.c38
76 files changed, 7555 insertions, 69 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
new file mode 100644
index 0000000..d754404
--- /dev/null
+++ b/usr.bin/Makefile
@@ -0,0 +1,32 @@
+LDSCRIPT =
+USRDIR =
+ROOT =
+ARGS = -I$(ROOT)/builddeps LDSCRIPT=$(LDSCRIPT) USRDIR=$(USRDIR) ROOT=$(ROOT)
+
+.PHONY: all
+all:
+ make -C osh/ $(ARGS)
+ make -C kmsg/ $(ARGS)
+ make -C fetch/ $(ARGS)
+ make -C kfgwm/ $(ARGS)
+ make -C date/ $(ARGS)
+ make -C mex/ $(ARGS)
+ make -C beep/ $(ARGS)
+ make -C mrow/ $(ARGS)
+ make -C elfdump/ $(ARGS)
+ make -C cat/ $(ARGS)
+ make -C getconf/ $(ARGS)
+ make -C echo/ $(ARGS)
+ make -C readcore/ $(ARGS)
+ make -C login/ $(ARGS)
+ make -C sleep/ $(ARGS)
+ make -C kstat/ $(ARGS)
+ make -C nerve/ $(ARGS)
+ make -C whoami/ $(ARGS)
+ make -C oasm/ $(ARGS)
+ make -C oemu/ $(ARGS)
+ make -C dmidump/ $(ARGS)
+ make -C sysctl/ $(ARGS)
+ make -C reboot/ $(ARGS)
+ make -C screensave/ $(ARGS)
+ make -C notes/ $(ARGS)
diff --git a/usr.bin/beep/Makefile b/usr.bin/beep/Makefile
new file mode 100644
index 0000000..409f87c
--- /dev/null
+++ b/usr.bin/beep/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/beep:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/beep/main.c b/usr.bin/beep/main.c
new file mode 100644
index 0000000..d64a9b5
--- /dev/null
+++ b/usr.bin/beep/main.c
@@ -0,0 +1,70 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ uint32_t payload;
+ uint16_t duration;
+ uint16_t freq;
+ int beep_fd;
+
+ if (argc < 3) {
+ printf("usage: beep <freq> <duration>\n");
+ return -1;
+ }
+
+ duration = atoi(argv[2]);
+ freq = atoi(argv[1]);
+
+ if (duration == 0) {
+ printf("bad duration\n");
+ return -1;
+ }
+ if (freq == 0) {
+ printf("bad frequency\n");
+ return -1;
+ }
+
+ beep_fd = open("/dev/beep", O_WRONLY);
+ if (beep_fd < 0) {
+ printf("failed to open beep fd\n");
+ return -1;
+ }
+
+ payload = freq;
+ payload |= (duration << 16);
+ write(beep_fd, &payload, sizeof(payload));
+ return 0;
+}
diff --git a/usr.bin/cat/Makefile b/usr.bin/cat/Makefile
new file mode 100644
index 0000000..4ecfea7
--- /dev/null
+++ b/usr.bin/cat/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/cat:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/cat/cat.c b/usr.bin/cat/cat.c
new file mode 100644
index 0000000..4fb74d1
--- /dev/null
+++ b/usr.bin/cat/cat.c
@@ -0,0 +1,112 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#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, int num_mode)
+{
+ FILE *file;
+ char buf[64];
+ int fd;
+ size_t lineno = 1;
+
+ file = fopen(pathname, "r");
+ if (file == NULL) {
+ return;
+ }
+
+ 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);
+}
+
+int
+main(int argc, char **argv)
+{
+ 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/date/Makefile b/usr.bin/date/Makefile
new file mode 100644
index 0000000..09ff299
--- /dev/null
+++ b/usr.bin/date/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/date:
+ gcc $(CFILES) -Iinclude/ -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/date/date.c b/usr.bin/date/date.c
new file mode 100644
index 0000000..8c4a9d1
--- /dev/null
+++ b/usr.bin/date/date.c
@@ -0,0 +1,132 @@
+/*
+ * 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/time.h>
+#include <sys/cdefs.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#define MONTHS_PER_YEAR 12
+#define DAYS_PER_WEEK 7
+
+/* Months of the year */
+static const char *montab[] = {
+ "Jan", "Feb", "Mar",
+ "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec"
+};
+
+/* Days of the week */
+static const char *daytab[] = {
+ "Sat", "Sun", "Mon",
+ "Tue", "Wed", "Thu",
+ "Fri"
+};
+
+static int
+set_time(int clock_fd, struct date *dp, char *timestr)
+{
+ uint32_t hour, min, sec;
+ char *p;
+
+ /* Hour */
+ p = strtok(timestr, ":");
+ if (p == NULL)
+ return -1;
+ hour = atoi(p);
+
+ /* Minute */
+ p = strtok(NULL, ":");
+ if (p == NULL)
+ return -1;
+ min = atoi(p);
+
+ /* Second */
+ p = strtok(NULL, ":");
+ if (p == NULL)
+ return -1;
+ sec = atoi(p);
+
+ /* Set the time */
+ dp->hour = hour;
+ dp->min = min;
+ dp->sec = sec;
+ write(clock_fd, dp, sizeof(*dp));
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *day, *month;
+ char date_str[32];
+ struct date d;
+ int rtc_fd, error = 0;
+
+ if ((rtc_fd = open("/dev/rtc", O_RDWR)) < 0) {
+ return rtc_fd;
+ }
+
+
+ read(rtc_fd, &d, sizeof(d));
+
+ /*
+ * If a time was specified to be set in the
+ * 'hh:mm:ss' format, attempt to write it.
+ */
+ if (argc > 1) {
+ error = set_time(rtc_fd, &d, argv[1]);
+ if (error < 0)
+ printf("bad time specified, not set\n");
+ read(rtc_fd, &d, sizeof(d));
+ }
+
+ close(rtc_fd);
+
+ /* This should not happen */
+ if (__unlikely(d.month > MONTHS_PER_YEAR)) {
+ printf("got bad month %d from RTC\n", d.month);
+ return -1;
+ }
+ if (__unlikely(d.month == 0 || d.day == 0)) {
+ printf("got zero month/day from RTC\n");
+ return -1;
+ }
+
+ day = daytab[d.day % DAYS_PER_WEEK];
+ month = montab[d.month - 1];
+
+ snprintf(date_str, sizeof(date_str), "%s %s %d %02d:%02d:%02d\n",
+ day, month, d.day, d.hour, d.min, d.sec);
+ fputs(date_str, stdout);
+ return 0;
+}
diff --git a/usr.bin/dmidump/Makefile b/usr.bin/dmidump/Makefile
new file mode 100644
index 0000000..e9cd625
--- /dev/null
+++ b/usr.bin/dmidump/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/dmidump:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/dmidump/dmidump.c b/usr.bin/dmidump/dmidump.c
new file mode 100644
index 0000000..96d97bc
--- /dev/null
+++ b/usr.bin/dmidump/dmidump.c
@@ -0,0 +1,78 @@
+/*
+ * 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/dmi.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/*
+ * The kernel fills DMI structures to zero,
+ * if any of the fields are unset then p[0]
+ * will have a null terminator which tells
+ * us we should ignore it.
+ */
+static void
+dmi_printfield(const char *name, const char *p)
+{
+ if (p[0] == '\0') {
+ return;
+ }
+
+ printf("%s: %s\n", name, p);
+}
+
+static void
+dmi_dump_board(void)
+{
+ struct dmi_board board;
+ int fd;
+
+ fd = open("/ctl/dmi/board", O_RDONLY);
+ if (fd < 0) {
+ printf("failed to open board control\n");
+ return;
+ }
+
+ read(fd, &board, sizeof(board));
+ printf("** BOARD INFO **\n");
+ dmi_printfield("CPU version", board.cpu_version);
+ dmi_printfield("CPU OEM", board.cpu_manuf);
+ dmi_printfield("product", board.product);
+ dmi_printfield("vendor", board.vendor);
+ dmi_printfield("version", board.version);
+ close(fd);
+}
+
+int
+main(int argc, char **argv)
+{
+ dmi_dump_board();
+ return 0;
+}
diff --git a/usr.bin/echo/Makefile b/usr.bin/echo/Makefile
new file mode 100644
index 0000000..296461b
--- /dev/null
+++ b/usr.bin/echo/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/echo:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/echo/echo.c b/usr.bin/echo/echo.c
new file mode 100644
index 0000000..760c788
--- /dev/null
+++ b/usr.bin/echo/echo.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 <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ for (int i = 1; i < argc; ++i) {
+ printf("%s ", argv[i]);
+ }
+
+ if (argc > 1) {
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/usr.bin/elfdump/Makefile b/usr.bin/elfdump/Makefile
new file mode 100644
index 0000000..b450635
--- /dev/null
+++ b/usr.bin/elfdump/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/elfdump:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c
new file mode 100644
index 0000000..335cdec
--- /dev/null
+++ b/usr.bin/elfdump/elfdump.c
@@ -0,0 +1,171 @@
+/*
+ * 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/elf.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+/* Ehdr.e_type table */
+static const char *elftype[] = {
+ [ET_NONE] = "Untyped",
+ [ET_REL] = "Relocatable",
+ [ET_EXEC] = "Executable",
+ [ET_DYN] = "Shared object",
+ [ET_CORE] = "Core dump"
+};
+
+/* Phdr.p_type table */
+static const char *phdrtype[] = {
+ [PT_NULL] = "Null",
+ [PT_LOAD] = "Loadable",
+ [PT_DYNAMIC] = "Dynamic",
+ [PT_NOTE] = "Note (linker garbage)",
+};
+
+/*
+ * Verify the validity of the ELF header from its
+ * various fields such as magic bytes, ABI, endianness,
+ * etc.
+ *
+ * Returns 0 on success.
+ */
+static int
+elf64_verify(const Elf64_Ehdr *hdr)
+{
+ const char *mag = &hdr->e_ident[EI_MAG0];
+
+ if (memcmp(mag, ELFMAG, SELFMAG) != 0) {
+ printf("Bad ELF magic\n");
+ return -ENOEXEC;
+ }
+ if (hdr->e_ident[EI_OSABI] != ELFOSABI_SYSV) {
+ printf("Bad ELF ABI\n");
+ return -ENOEXEC;
+ }
+ if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+ printf("Bad endianness\n");
+ return -ENOEXEC;
+ }
+ if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
+ printf("ELF not 64 bits\n");
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+static void
+parse_phdrs(const Elf64_Ehdr *eh, int fd)
+{
+ Elf64_Phdr phdr;
+ const char *type = "Unknown";
+
+ lseek(fd, eh->e_phoff, SEEK_SET);
+ printf("-- PHDRS BEGIN --\n");
+ for (size_t i = 0; i < eh->e_phnum; ++i) {
+ if (read(fd, &phdr, eh->e_phentsize) <= 0) {
+ printf("failed to read phdr %d\n", i);
+ break;
+ }
+ if (phdr.p_type < NELEM(phdrtype)) {
+ type = phdrtype[phdr.p_type];
+ }
+
+ printf("* [P.%d] Type: %s\n", i, type);
+ printf("* [P.%d] Offset: %d\n", i, phdr.p_offset);
+ printf("* [P.%d] Vaddr: %p\n", i, phdr.p_vaddr);
+ printf("* [P.%d] Paddr: %p\n", i, phdr.p_paddr);
+ printf("* [P.%d] Memory size: %d\n", i, phdr.p_memsz);
+ printf("* [P.%d] Flags: %p\n", i, phdr.p_flags);
+ printf("* [P.%d] Alignment: %p\n", i, phdr.p_align);
+
+ /* Seperator */
+ if (i < (eh->e_phnum - 1)) {
+ printf("-----------------------------\n");
+ }
+ }
+ printf("-- PHDRS END --\n");
+}
+
+static int
+parse_ehdr(const Elf64_Ehdr *eh, int fd)
+{
+ const char *elf_type = "Bad";
+
+ if (eh->e_type < NELEM(elftype)) {
+ elf_type = elftype[eh->e_type];
+ }
+
+ printf("* Entrypoint: %p\n", eh->e_entry);
+ printf("* Program headers start offset: %p\n", eh->e_phoff);
+ printf("* Section headers start offset: %p\n", eh->e_shoff);
+ printf("* Number of program headers: %d\n", eh->e_phnum);
+ printf("* Endianess: Little\n");
+ parse_phdrs(eh, fd);
+ return 0;
+}
+
+static int
+elfdump_run(const char *filename)
+{
+ Elf64_Ehdr eh;
+ int fd, error;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ return fd;
+ }
+
+ printf("-- Dumping %s --\n", filename);
+ read(fd, &eh, sizeof(eh));
+
+ if ((error = elf64_verify(&eh)) < 0) {
+ return error;
+ }
+ if ((error = parse_ehdr(&eh, fd)) < 0) {
+ return error;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 2) {
+ printf("elfdump: usage: elfdump <elf path>\n");
+ return -1;
+ }
+
+ return elfdump_run(argv[1]);
+}
diff --git a/usr.bin/fetch/Makefile b/usr.bin/fetch/Makefile
new file mode 100644
index 0000000..4b08e84
--- /dev/null
+++ b/usr.bin/fetch/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/fetch:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/fetch/fetch.c b/usr.bin/fetch/fetch.c
new file mode 100644
index 0000000..1e8ef92
--- /dev/null
+++ b/usr.bin/fetch/fetch.c
@@ -0,0 +1,105 @@
+/*
+ * 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>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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" \
+ " | \\__\\ 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)
+{
+ char *brand = get_brand();
+
+ if (brand == NULL) {
+ brand = strdup("unknown");
+ }
+
+ printf(ASCII_ART, getlogin(), brand);
+ free(brand);
+ return 0;
+}
diff --git a/usr.bin/getconf/Makefile b/usr.bin/getconf/Makefile
new file mode 100644
index 0000000..48c05a8
--- /dev/null
+++ b/usr.bin/getconf/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/getconf:
+ gcc $(CFILES) -Iinclude/ -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/getconf/getconf.c b/usr.bin/getconf/getconf.c
new file mode 100644
index 0000000..f028e76
--- /dev/null
+++ b/usr.bin/getconf/getconf.c
@@ -0,0 +1,93 @@
+/*
+ * 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/param.h>
+#include <sys/limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+struct sysvar {
+ const char *var;
+ uint8_t auxv : 1;
+ uint32_t val;
+};
+
+static struct sysvar vartab[] = {
+ { "PAGESIZE", 1, AT_PAGESIZE },
+ { "CHAR_BIT", 0, CHAR_BIT },
+ { "NAME_MAX", 0, NAME_MAX },
+ { "PATH_MAX", 0, PATH_MAX },
+ { "SSIZE_MAX", 0, SSIZE_MAX },
+ { NULL, 0, 0 }
+};
+
+static int
+getvar_val(struct sysvar *vp)
+{
+ if (vp->auxv) {
+ return sysconf(vp->val);
+ }
+
+ return vp->val;
+}
+
+static int
+getvar(const char *sysvar)
+{
+ for (int i = 0; vartab[i].var != NULL; ++i) {
+ if (strcmp(vartab[i].var, sysvar) == 0) {
+ return getvar_val(&vartab[i]);
+ }
+ }
+
+ return -1;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *var;
+ int retval;
+
+ if (argc < 2) {
+ printf("usage: getconf <SYSTEM VAR>\n");
+ return -1;
+ }
+
+ var = argv[1];
+ if ((retval = getvar(var)) < 0) {
+ printf("bad system var \"%s\"\n", var);
+ return retval;
+ }
+
+ printf("%d\n", retval);
+ return 0;
+}
diff --git a/usr.bin/kfgwm/Makefile b/usr.bin/kfgwm/Makefile
new file mode 100644
index 0000000..a0fb49a
--- /dev/null
+++ b/usr.bin/kfgwm/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/kfgwm:
+ gcc $(CFILES) -Iinclude/ -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/kfgwm/font.c b/usr.bin/kfgwm/font.c
new file mode 100644
index 0000000..9873b02
--- /dev/null
+++ b/usr.bin/kfgwm/font.c
@@ -0,0 +1,379 @@
+/*
+ * 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 <kfg/font.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* TODO: Open a .psf font and get rid of this */
+const uint8_t g_KFG_FONT[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x81, 0x81, 0xa5, 0xa5, 0x81,
+ 0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff,
+ 0xff, 0xdb, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0x7e, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
+ 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x3c, 0x3c, 0xdb, 0xff, 0xff, 0xdb, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x66, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
+ 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0x84, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+ 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1e,
+ 0x0e, 0x1e, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x30, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1c, 0x1e, 0x16, 0x12,
+ 0x10, 0x10, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x2c,
+ 0x26, 0x32, 0x3a, 0x2e, 0x26, 0x22, 0x62, 0xe2, 0xc6, 0x0e, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe,
+ 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+ 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c,
+ 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
+ 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0xfc, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0xfe, 0x60, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+ 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+ 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x30, 0x00, 0x30,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+ 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc0, 0xc0, 0x7c, 0x06, 0x06, 0xc6, 0x7c,
+ 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x0c, 0x0c, 0x18, 0x38,
+ 0x30, 0x60, 0x60, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0x6c, 0x38, 0x30, 0x76, 0xde, 0xcc, 0xcc, 0xde, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+ 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
+ 0x0c, 0x0c, 0x18, 0x38, 0x30, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0x06, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc,
+ 0xfe, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+ 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60,
+ 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x00, 0x30,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+ 0xde, 0xde, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0xc0, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
+ 0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xf6, 0xda,
+ 0x6c, 0x06, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc,
+ 0xd8, 0xcc, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c,
+ 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x38,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xc0,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+ 0x60, 0x60, 0x30, 0x38, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x06,
+ 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+ 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xdc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x76, 0xce, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6,
+ 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+ 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+ 0xc0, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
+ 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc6,
+ 0xc6, 0xc6, 0xe6, 0xdc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x76, 0xce, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
+ 0x70, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
+ 0x30, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x30, 0x30,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30,
+ 0x30, 0x30, 0x30, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x6c,
+ 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+ 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x06, 0x06,
+ 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+ 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
+ 0x7c, 0x18, 0x0c, 0x38, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+ 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36,
+ 0x76, 0xde, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c,
+ 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
+ 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,
+ 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+ 0x30, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0xe6,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
+ 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0xd8, 0x70, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x06, 0x06,
+ 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+ 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+ 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd8, 0xd8, 0x6c, 0x00, 0xfc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+ 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c,
+ 0x18, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30,
+ 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
+ 0x00, 0x30, 0x30, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+ 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
+ 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18,
+ 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x06,
+ 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
+ 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+ 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x37, 0x37, 0x30, 0x30, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x37, 0x37, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0xf7, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x30, 0x30, 0x37, 0x37, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xf7, 0xf7, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+ 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+ 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0xff, 0xff, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x76, 0xd6, 0xdc, 0xc8, 0xc8, 0xdc, 0xd6, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xd8, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0xfe, 0x24, 0x24, 0x24, 0x24, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xfe, 0xc2, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc2, 0xfe,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc8, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6c, 0x60, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xfc, 0x98, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x78, 0xcc, 0xcc,
+ 0xcc, 0x78, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c,
+ 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x60, 0x30, 0x78, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x76, 0xbb, 0x99, 0x99, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x3c, 0x6c, 0xce, 0xd6, 0xd6, 0xe6, 0x6c, 0x78,
+ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x60, 0xc0, 0xc0, 0xfe,
+ 0xc0, 0xc0, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc,
+ 0x30, 0x30, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc,
+ 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00,
+ 0x00, 0xd8, 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x0c, 0x18, 0x30, 0x60, 0x7c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
diff --git a/usr.bin/kfgwm/include/kfg/font.h b/usr.bin/kfgwm/include/kfg/font.h
new file mode 100644
index 0000000..7752952
--- /dev/null
+++ b/usr.bin/kfgwm/include/kfg/font.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _KFGWM_FONT_H_
+#define _KFGWM_FONT_H_
+
+#include <sys/types.h>
+
+#define FONT_WIDTH 8
+#define FONT_HEIGHT 16
+
+extern const uint8_t g_KFG_FONT[];
+
+#endif /* !_KFGWM_FONT_H_ */
diff --git a/usr.bin/kfgwm/include/kfg/types.h b/usr.bin/kfgwm/include/kfg/types.h
new file mode 100644
index 0000000..2d17ae1
--- /dev/null
+++ b/usr.bin/kfgwm/include/kfg/types.h
@@ -0,0 +1,40 @@
+/*
+ * 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 KFG_TYPES_H_
+#define KFG_TYPES_H_
+
+#include <sys/types.h>
+#include <stddef.h>
+
+typedef uint32_t kfgpos_t;
+typedef uint32_t kfgdim_t;
+typedef uint32_t kfgpixel_t;
+
+#endif /* !KFG_TYPES_H_ */
diff --git a/usr.bin/kfgwm/include/kfg/window.h b/usr.bin/kfgwm/include/kfg/window.h
new file mode 100644
index 0000000..a597969
--- /dev/null
+++ b/usr.bin/kfgwm/include/kfg/window.h
@@ -0,0 +1,68 @@
+/*
+ * 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 KFG_WINDOW_H_
+#define KFG_WINDOW_H_
+
+#include <kfg/types.h>
+
+#define KFG_RED 0x6E0C24
+#define KFG_YELLOW 0xF0A401
+#define KFG_WHITE 0xF2E5BC
+#define KFG_DARK 0x1D2021
+#define KFG_BLUE 0x076678
+#define KFG_AQUA 0x427B58
+
+/* Default dimensions */
+#define KFG_BORDER_WIDTH 1
+#define KFG_BORDER_HEIGHT 1
+#define KFG_TITLE_HEIGHT 10
+
+struct kfg_window {
+ kfgpos_t x;
+ kfgpos_t y;
+ kfgdim_t width;
+ kfgdim_t height;
+ kfgdim_t fb_pitch;
+ kfgpixel_t bg;
+ kfgpixel_t border_bg;
+ kfgpixel_t *framebuf;
+};
+
+struct kfg_text {
+ const char *text;
+ kfgpos_t x;
+ kfgpos_t y;
+};
+
+struct kfg_window *kfg_win_new(struct kfg_window *parent, kfgpos_t x, kfgpos_t y);
+int kfg_win_draw(struct kfg_window *parent, struct kfg_window *wp);
+int kfg_win_putstr(struct kfg_window *wp, struct kfg_text *tp);
+
+#endif /* !KFG_WINDOW_H_ */
diff --git a/usr.bin/kfgwm/kfgwm.c b/usr.bin/kfgwm/kfgwm.c
new file mode 100644
index 0000000..5a9e7b8
--- /dev/null
+++ b/usr.bin/kfgwm/kfgwm.c
@@ -0,0 +1,95 @@
+/*
+ * 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/mman.h>
+#include <sys/types.h>
+#include <sys/fbdev.h>
+#include <kfg/window.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static struct fbattr fbattr;
+static uint32_t *framep;
+
+static void
+test_win(struct kfg_window *root, kfgpos_t x, kfgpos_t y, const char *str)
+{
+ struct kfg_text text;
+ struct kfg_window *test_win;
+
+ test_win = kfg_win_new(root, x, y);
+ text.text = str;
+ text.x = 0;
+ text.y = 0;
+
+ kfg_win_draw(root, test_win);
+ kfg_win_putstr(test_win, &text);
+}
+
+int
+main(void)
+{
+ int fb_fd, fbattr_fd, prot;
+ size_t fb_size;
+ struct kfg_window *root_win;
+
+ fb_fd = open("/dev/fb0", O_RDWR);
+ if (fb_fd < 0) {
+ return fb_fd;
+ }
+
+ fbattr_fd = open("/ctl/fb0/attr", O_RDONLY);
+ if (fbattr_fd < 0) {
+ close(fb_fd);
+ return fbattr_fd;
+ }
+
+ read(fbattr_fd, &fbattr, sizeof(fbattr));
+ close(fbattr_fd);
+
+ fb_size = fbattr.height * fbattr.pitch;
+ prot = PROT_READ | PROT_WRITE;
+ framep = mmap(NULL, fb_size, prot, MAP_SHARED, fb_fd, 0);
+
+ root_win = malloc(sizeof(*root_win));
+ root_win->x = 0;
+ root_win->y = 0;
+ root_win->width = fbattr.width;
+ root_win->height = fbattr.height;
+ root_win->fb_pitch = fbattr.pitch;
+ root_win->framebuf = framep;
+ root_win->bg = KFG_RED;
+ root_win->border_bg = KFG_RED;
+ test_win(root_win, 40, 85, "Hello, World!");
+ test_win(root_win, 150, 20, "Mrow!");
+
+ for (;;);
+}
diff --git a/usr.bin/kfgwm/window.c b/usr.bin/kfgwm/window.c
new file mode 100644
index 0000000..3908302
--- /dev/null
+++ b/usr.bin/kfgwm/window.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/errno.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <kfg/window.h>
+#include <kfg/font.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+__always_inline static inline size_t
+pixel_index(struct kfg_window *wp, kfgpos_t x, kfgpos_t y)
+{
+ return x + y * (wp->fb_pitch / 4);
+}
+
+static int
+kfg_win_putc(struct kfg_window *wp, uint32_t x, uint32_t y, char ch)
+{
+ size_t idx;
+ const uint8_t *glyph;
+ uint32_t fg, bg;
+
+ glyph = &g_KFG_FONT[(int)ch*16];
+ fg = KFG_WHITE;
+ bg = wp->bg;
+
+ for (uint32_t cy = 0; cy < FONT_HEIGHT; ++cy) {
+ idx = pixel_index(wp, x + (FONT_WIDTH - 1), y + cy);
+ for (uint32_t cx = 0; cx < FONT_WIDTH; ++cx) {
+ wp->framebuf[idx--] = ISSET(glyph[cy], BIT(cx)) ? fg : bg;
+ }
+ }
+}
+
+static void
+draw_win(struct kfg_window *parent, struct kfg_window *wp)
+{
+ kfgpixel_t *framep;
+ kfgpos_t x_i, y_i; /* Start */
+ kfgpos_t x_end, y_end; /* End */
+ kfgpixel_t brush = wp->bg;
+ kfgpos_t rx, ry; /* Starts at 0 */
+ kfgpos_t rx_end, ry_end; /* Starts at 0 */
+ size_t i;
+
+ framep = parent->framebuf;
+ x_i = wp->x;
+ y_i = wp->y;
+ x_end = x_i + wp->width;
+ y_end = y_i + wp->height;
+
+ if (x_end > parent->width)
+ x_end = parent->width;
+ if (y_end > parent->height)
+ y_end = parent->height;
+
+ for (kfgpos_t x = x_i; x < x_end; ++x) {
+ for (kfgpos_t y = y_i; y < y_i+KFG_TITLE_HEIGHT; ++y) {
+ rx = (x - x_i);
+ ry = (y - y_i);
+
+ if (rx <= KFG_BORDER_WIDTH && (rx % 2) == 0)
+ brush = KFG_WHITE;
+ else
+ brush = KFG_AQUA;
+
+ i = pixel_index(parent, x, y);
+ framep[i] = brush;
+ }
+ }
+
+ y_i = wp->y + KFG_TITLE_HEIGHT;
+ for (kfgpos_t x = x_i; x < x_end; ++x) {
+ for (kfgpos_t y = y_i; y < y_end; ++y) {
+ rx = (x - x_i);
+ ry = (y - y_i);
+
+ if (rx <= KFG_BORDER_WIDTH)
+ brush = wp->border_bg;
+ else if (ry <= KFG_BORDER_HEIGHT)
+ brush = wp->border_bg;
+ else if (rx >= (wp->width - KFG_BORDER_WIDTH))
+ brush = wp->border_bg;
+ else if (ry >= (wp->height - KFG_BORDER_HEIGHT))
+ brush = wp->border_bg;
+ else
+ brush = wp->bg;
+
+ i = pixel_index(parent, x, y);
+ framep[i] = brush;
+ }
+ }
+}
+
+/*
+ * Draw a window on the screen
+ *
+ * @parent: Parent window
+ * @wp: New window to draw
+ *
+ * TODO: Double buffering and multiple windows.
+ */
+int
+kfg_win_draw(struct kfg_window *parent, struct kfg_window *wp)
+{
+ kfgpos_t start_x, start_y;
+ kfgpos_t end_x, end_y;
+ kfgpos_t max_x, max_y;
+ kfgdim_t width, height;
+
+ if (parent == NULL) {
+ return -EINVAL;
+ }
+ if (parent->framebuf == NULL) {
+ return -EINVAL;
+ }
+
+ max_x = wp->x + parent->width;
+ max_y = wp->y + parent->height;
+
+ /* Don't overflow the framebuffer! */
+ if ((wp->x + wp->width) > max_x) {
+ wp->x = max_x;
+ }
+ if ((wp->y + wp->height) > max_y) {
+ wp->y = max_y;
+ }
+
+ draw_win(parent, wp);
+ return 0;
+}
+
+/*
+ * Create a new default window
+ *
+ * @x: X position for this window
+ * @y: Y position for this window
+ * @w: Window width
+ * @h: Window height
+ */
+struct kfg_window *
+kfg_win_new(struct kfg_window *parent, kfgpos_t x, kfgpos_t y)
+{
+ struct kfg_window *wp;
+
+ if ((wp = malloc(sizeof(*wp))) == NULL) {
+ return NULL;
+ }
+
+ wp->x = x;
+ wp->y = y;
+ wp->width = 250;
+ wp->height = 150;
+ wp->fb_pitch = parent->fb_pitch;
+ wp->framebuf = parent->framebuf;
+ wp->bg = KFG_DARK;
+ wp->border_bg = KFG_RED;
+ return wp;
+}
+
+int
+kfg_win_putstr(struct kfg_window *wp, struct kfg_text *tp)
+{
+ size_t slen;
+ const char *p;
+ kfgpos_t x, y;
+
+ if (tp == NULL)
+ return -EINVAL;
+ if (tp->text == NULL)
+ return -EINVAL;
+
+ slen = strlen(tp->text);
+ x = (wp->x + tp->x) + (KFG_BORDER_WIDTH + 1);
+ y = (KFG_TITLE_HEIGHT + wp->y) + tp->y;
+ p = tp->text;
+
+ while (slen--) {
+ if (y >= wp->height) {
+ break;
+ }
+
+ kfg_win_putc(wp, x, y, *(p++));
+ x += FONT_WIDTH;
+ if (x >= wp->width) {
+ y += FONT_HEIGHT;
+ x = wp->x + (KFG_BORDER_WIDTH + 1);
+ }
+ }
+
+ return 0;
+}
diff --git a/usr.bin/kmsg/Makefile b/usr.bin/kmsg/Makefile
new file mode 100644
index 0000000..9b76cc2
--- /dev/null
+++ b/usr.bin/kmsg/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/kmsg:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/kmsg/kmsg.c b/usr.bin/kmsg/kmsg.c
new file mode 100644
index 0000000..2deae39
--- /dev/null
+++ b/usr.bin/kmsg/kmsg.c
@@ -0,0 +1,58 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+main(void)
+{
+ int mfd;
+ ssize_t retval;
+ char linebuf[256];
+
+ if ((mfd = open("/dev/kmsg", O_RDONLY)) < 0) {
+ return mfd;
+ }
+
+ for (;;) {
+ retval = read(mfd, linebuf, sizeof(linebuf) - 1);
+ if (retval <= 0) {
+ break;
+ }
+ linebuf[retval] = '\0';
+ fputs(linebuf, stdout);
+ }
+
+ close(mfd);
+ return 0;
+}
diff --git a/usr.bin/kstat/Makefile b/usr.bin/kstat/Makefile
new file mode 100644
index 0000000..ccceb3c
--- /dev/null
+++ b/usr.bin/kstat/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/kstat:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/kstat/kstat.c b/usr.bin/kstat/kstat.c
new file mode 100644
index 0000000..cbbe602
--- /dev/null
+++ b/usr.bin/kstat/kstat.c
@@ -0,0 +1,122 @@
+/*
+ * 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/sched.h>
+#include <sys/vmstat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define MIB_PER_GIB 1024
+
+static void
+print_size_mib(const char *name, size_t mib)
+{
+ if (name == NULL) {
+ return;
+ }
+
+ if (mib >= MIB_PER_GIB) {
+ printf("%s: %d GiB\n", name, mib / MIB_PER_GIB);
+ } else {
+ printf("%s: %d MiB\n", name, mib);
+ }
+}
+
+static void
+get_vm_stat(void)
+{
+ struct vm_stat vmstat;
+ int retval, fd;
+
+ fd = open("/ctl/vm/stat", O_RDONLY);
+ if (fd < 0) {
+ printf("failed to open '/ctl/vm/stat'\n");
+ return;
+ }
+
+ retval = read(fd, &vmstat, sizeof(vmstat));
+ if (retval <= 0) {
+ printf("failed to read vmstat\n");
+ return;
+ }
+
+ close(fd);
+ print_size_mib("memory available", vmstat.mem_avail);
+ print_size_mib("memory used", vmstat.mem_used);
+ print_size_mib("memory total", vmstat.mem_total);
+}
+
+static void
+get_sched_stat(void)
+{
+ struct sched_stat stat;
+ struct sched_cpu *cpu;
+ double nonline, noffline;
+ uint16_t online_percent;
+ int fd;
+
+ fd = open("/ctl/sched/stat", O_RDONLY);
+ if (fd < 0) {
+ printf("failed to get sched stat\n");
+ return;
+ }
+ if (read(fd, &stat, sizeof(stat)) < 0) {
+ printf("failed to read sched stat\n");
+ return;
+ }
+
+ close(fd);
+ noffline = stat.nhlt;
+ nonline = (stat.ncpu - noffline);
+ online_percent = (uint16_t)(((double)nonline / (nonline + noffline)) * 100);
+
+ printf("number of tasks: %d\n", stat.nproc);
+ printf("number of cores online: %d\n", stat.ncpu);
+ printf("scheduler quantum: %d usec\n", stat.quantum_usec);
+ printf("CPU is %d%% online\n", online_percent);
+
+ /*
+ * Log out some per-cpu information
+ */
+ for (int i = 0; i < stat.ncpu; ++i) {
+ cpu = &stat.cpus[i];
+ printf("[cpu %d]: %d switches\n", i, cpu->nswitch);
+ }
+}
+
+int
+main(void)
+{
+ printf("-- scheduler statistics --\n");
+ get_sched_stat();
+ printf("-- memory statistics --\n");
+ get_vm_stat();
+ return 0;
+}
diff --git a/usr.bin/link.ld b/usr.bin/link.ld
index 9fad881..5e99291 100644
--- a/usr.bin/link.ld
+++ b/usr.bin/link.ld
@@ -23,4 +23,9 @@ SECTIONS
*(.bss.*)
__bss_end = .;
}
+
+ /DISCARD/ : {
+ *(.eh_frame)
+ *(.note .note.*)
+ }
}
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
new file mode 100644
index 0000000..8b37d4c
--- /dev/null
+++ b/usr.bin/login/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/login:
+ gcc -Iinclude/ $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
new file mode 100644
index 0000000..5b21303
--- /dev/null
+++ b/usr.bin/login/login.c
@@ -0,0 +1,295 @@
+/*
+ * 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/spawn.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <crypto/sha256.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Row indices for /etc/passwd */
+#define ROW_USERNAME 0
+#define ROW_HASH 1
+#define ROW_USERID 2
+#define ROW_GRPID 3
+#define ROW_GECOS 4
+#define ROW_HOME 5
+#define ROW_SHELL 6
+
+#define is_ascii(C) ((C) >= 0 && (C) <= 128)
+#define is_digit(C) ((C >= '0' && C <= '9'))
+
+#define DEFAULT_SHELL "/usr/bin/osh"
+
+static char buf[64];
+static uint8_t buf_i;
+static short echo_chars = 1;
+
+/*
+ * Verify a UID is valid
+ *
+ * Returns 0 on success
+ */
+static int
+check_uid(const char *uid)
+{
+ size_t len;
+
+ len = strlen(uid);
+
+ /* Must not be greater than 4 chars */
+ if (len > 4) {
+ return -1;
+ }
+
+ for (int i = 0; i < len; ++i) {
+ if (!is_digit(uid[i])) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check an /etc/passwd entry against an alias
+ * (username)
+ *
+ * @alias: Alias to lookup
+ * @hash: Password hash
+ * @entry: /etc/passwd entry
+ *
+ * Returns -1 on failure
+ * Returns 0 if the entry matches
+ */
+static int
+check_user(char *alias, char *hash, char *entry)
+{
+ const char *p;
+ char shell_path[256];
+ char *shell_argv[] = { DEFAULT_SHELL, NULL };
+ char *envp[] = { NULL };
+ size_t len, row = 0;
+ size_t line = 1;
+ short have_user = 0;
+ short have_pw = 0;
+ short have_uid = 0;
+ short have_shell = 0;
+ uid_t uid = -1;
+ pid_t shell_pid;
+
+ if (alias == NULL || entry == NULL) {
+ return -EINVAL;
+ }
+
+ /* Grab the username */
+ p = strtok(entry, ":");
+ if (p == NULL) {
+ printf("bad /etc/passwd entry @ line 1\n");
+ return -1;
+ }
+
+ /* Iterate through each field */
+ while (p != NULL) {
+ switch (row) {
+ case ROW_USERNAME:
+ if (strcmp(p, alias) == 0) {
+ have_user = 1;
+ }
+ break; /* UNREACHABLE */
+ case ROW_HASH:
+ if (strcmp(p, hash) == 0) {
+ have_pw = 1;
+ }
+ break;
+ case ROW_USERID:
+ if (check_uid(p) != 0) {
+ printf("bad uid @ line %d\n", line);
+ return -1;
+ }
+
+ uid = atoi(p);
+ have_uid = 1;
+ break;
+ case ROW_SHELL:
+ len = strlen(p) - 1;
+ if (len >= sizeof(shell_path) - 1) {
+ printf("bad shell path @ line %d\n", line);
+ return -1;
+ }
+
+ memcpy(shell_path, p, len);
+ shell_path[len] = '\0';
+ have_shell = 1;
+ break;
+ }
+
+ p = strtok(NULL, ":");
+ ++row;
+ ++line;
+ }
+
+ /*
+ * We need to have found the password hash,
+ * the username, AND the UID. If we have not,
+ * then this has failed.
+ */
+ if (!have_pw || !have_user || !have_uid) {
+ return -1;
+ }
+
+ /* Do we have the shell path? */
+ if (!have_shell) {
+ return -1;
+ }
+
+ setuid(uid);
+ shell_argv[0] = shell_path;
+ shell_pid = spawn(shell_argv[0], shell_argv, envp, 0);
+ return 0;
+}
+
+static char *
+getstr(void)
+{
+ char c, printc;
+ int input;
+
+ buf_i = 0;
+
+ for (;;) {
+ if ((input = getchar()) < 0) {
+ continue;
+ }
+
+ c = (char)input;
+ if (c == '\t') {
+ continue;
+ }
+
+ /*
+ * If we want to echo characters, 'printc' becomes
+ * exactly the character we got. Otherwise, just
+ * print little stars to redact it.
+ */
+ printc = echo_chars ? c : '*';
+
+ /* return on newline */
+ if (c == '\n') {
+ buf[buf_i] = '\0';
+ putchar('\n');
+ return buf;
+ }
+
+ /* handle backspaces and DEL */
+ if (c == '\b' || c == 127) {
+ if (buf_i > 0) {
+ fputs("\b \b", stdout);
+ buf[--buf_i] = '\0';
+ }
+ } else if (is_ascii(c) && buf_i < sizeof(buf) - 1) {
+ /* write to fd and add to buffer */
+ buf[buf_i++] = c;
+ putchar(printc);
+ }
+ }
+}
+
+static int
+getuser(FILE *fp)
+{
+ char *pwtmp, *alias, *p;
+ char entry[256];
+ char pwhash[SHA256_HEX_SIZE];
+ int retval;
+
+ printf("username: ");
+ p = getstr();
+ alias = strdup(p);
+
+ /* Grab the password now */
+ echo_chars = 0;
+ printf("password: ");
+ p = getstr();
+ pwtmp = strdup(p);
+ sha256_hex(pwtmp, strlen(pwtmp), pwhash);
+
+ /* Paranoia */
+ memset(pwtmp, 0, strlen(pwtmp));
+ buf_i = 0;
+ memset(buf, 0, sizeof(buf));
+
+ /* Clean up */
+ free(pwtmp);
+ pwtmp = NULL;
+
+ /* See if anything matches */
+ while (fgets(entry, sizeof(entry), fp) != NULL) {
+ retval = check_user(alias, pwhash, entry);
+ if (retval == 0) {
+ free(alias);
+ return 0;
+ }
+ }
+
+ /* If we reach this point, bad creds */
+ free(alias);
+ alias = NULL;
+
+ printf("bad username or password\n");
+ fseek(fp, 0, SEEK_SET);
+ memset(buf, 0, sizeof(buf));
+ buf_i = 0;
+ echo_chars = 1;
+ return -1;
+}
+
+int
+main(void)
+{
+ FILE *fp;
+
+ fp = fopen("/etc/passwd", "r");
+ if (fp == NULL) {
+ printf("failed to open /etc/passwd\n");
+ return -1;
+ }
+
+ printf("- Please authenticate yourself -\n");
+ for (;;) {
+ if (getuser(fp) == 0) {
+ break;
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
diff --git a/usr.bin/mex/Makefile b/usr.bin/mex/Makefile
new file mode 100644
index 0000000..6c0db59
--- /dev/null
+++ b/usr.bin/mex/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/mex:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/mex/mex.c b/usr.bin/mex/mex.c
new file mode 100644
index 0000000..7e6f8aa
--- /dev/null
+++ b/usr.bin/mex/mex.c
@@ -0,0 +1,105 @@
+/*
+ * 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>
+#include <stddef.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+
+#define LINE_LEN 16
+
+static void
+dump_line(const char *line, size_t len)
+{
+ /* The amount of bytes we write */
+ const uint8_t BYTE_COUNT = 2;
+
+ for (size_t i = 0; i < LINE_LEN; ++i) {
+ if (i < len) {
+ printf("%02x", line[i] & 0xFF);
+ } else {
+ printf(" ");
+ }
+
+ /* Put spacing between bytes */
+ if (((i + 1) % BYTE_COUNT) == 0) {
+ printf(" ");
+ }
+ }
+
+ printf(" ");
+ for (size_t i = 0; i < len; ++i) {
+ if (line[i] > 31 && line[i] < 127) {
+ printf("%c", line[i]);
+ } else {
+ printf(".");
+ }
+ }
+
+ printf("\n");
+}
+
+static void
+dump_file(int fd)
+{
+ char buf[LINE_LEN];
+ ssize_t count;
+ size_t offset = 0;
+
+ for (;;) {
+ count = read(fd, buf, sizeof(char) * LINE_LEN);
+ if (count <= 0) {
+ break;
+ }
+
+ printf("%08x: ", offset);
+ offset += LINE_LEN;
+ dump_line(buf, count);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+
+ if (argc < 2) {
+ printf("mex: usage: mex <filename>\n");
+ return -1;
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ printf("mex: failed to open input\n");
+ return fd;
+ }
+
+ dump_file(fd);
+ return 0;
+}
diff --git a/usr.bin/mrow/Makefile b/usr.bin/mrow/Makefile
new file mode 100644
index 0000000..d7c7ef4
--- /dev/null
+++ b/usr.bin/mrow/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/mrow:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS) -lgfx
diff --git a/usr.bin/mrow/mrow.c b/usr.bin/mrow/mrow.c
new file mode 100644
index 0000000..1179f7e
--- /dev/null
+++ b/usr.bin/mrow/mrow.c
@@ -0,0 +1,287 @@
+/*
+ * 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 <fcntl.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <libgfx/gfx.h>
+#include <libgfx/draw.h>
+
+#define IS_ASCII(C) ((C) > 0 && (C) < 127)
+
+#define PLAYER_BG 0x808080
+#define MOUSE_BG 0x404040
+#define GAME_BG 0x000000
+
+#define SPRITE_WIDTH 20
+#define SPRITE_HEIGHT 20
+#define MAX_MOUSE_SPEED 2
+#define MIN_MOUSE_SPEED 1
+#define PLAYER_SPEED 30
+
+#define SCR_WIDTH (gfx_ctx.fbdev.width)
+#define SCR_HEIGHT (gfx_ctx.fbdev.height)
+#define MAX_X (SCR_WIDTH - SPRITE_WIDTH)
+#define MAX_Y (SCR_HEIGHT - SPRITE_HEIGHT)
+
+/* Hit beep stuff */
+#define HIT_BEEP_MSEC 50
+#define HIT_BEEP_FREQ 600
+
+static struct gfx_ctx gfx_ctx;
+static uint32_t *framep;
+static int beep_fd;
+static size_t hit_count = 0;
+
+struct player {
+ int32_t x;
+ int32_t y;
+};
+
+struct mouse {
+ int32_t x;
+ int32_t y;
+ uint8_t x_inc : 1;
+ uint8_t y_inc : 1;
+ uint8_t speed;
+};
+
+static void
+draw_sprite(uint32_t x, uint32_t y, uint32_t color)
+{
+ struct gfx_shape sprite_shape = GFX_SHAPE_DEFAULT;
+
+ sprite_shape.x = x;
+ sprite_shape.y = y;
+ sprite_shape.width = SPRITE_WIDTH;
+ sprite_shape.height = SPRITE_HEIGHT;
+ sprite_shape.color = color;
+ gfx_draw_shape(&gfx_ctx, &sprite_shape);
+}
+
+static void
+update_mouse(struct mouse *mouse)
+{
+ draw_sprite(mouse->x, mouse->y, GAME_BG);
+
+ /* Move the mouse in the x direction */
+ if (mouse->x_inc) {
+ mouse->x += mouse->speed;
+ } else {
+ mouse->x -= mouse->speed;
+ }
+
+ /* Move the mouse in the y direction */
+ if (mouse->y_inc) {
+ mouse->y += mouse->speed;
+ } else {
+ mouse->y -= mouse->speed;
+ }
+
+ if (mouse->x >= MAX_X) {
+ mouse->x = MAX_X;
+ mouse->x_inc = 0;
+ } else if (mouse->x <= 0) {
+ mouse->x = 0;
+ mouse->x_inc = 1;
+ }
+
+ if (mouse->y >= MAX_Y) {
+ mouse->y = MAX_Y;
+ mouse->y_inc = 0;
+ } else if (mouse->y <= 0) {
+ mouse->y = 0;
+ mouse->y_inc = 1;
+ }
+
+ draw_sprite(mouse->x, mouse->y, MOUSE_BG);
+}
+
+static void
+beep(uint16_t msec, uint16_t freq)
+{
+ uint32_t payload;
+
+ /* Can't beep :( */
+ if (beep_fd < 0) {
+ return;
+ }
+
+ payload = freq;
+ payload |= (msec << 16);
+ write(beep_fd, &payload, sizeof(payload));
+}
+
+static void
+score_increment(struct player *p, struct mouse *m)
+{
+ printf("\033[31;40mSCORE: %d\033[0m\n", ++hit_count);
+
+ if (m->speed < MAX_MOUSE_SPEED) {
+ m->speed += 1;
+ } else {
+ m->speed = MIN_MOUSE_SPEED;
+ }
+}
+
+static bool
+mouse_collide(struct player *p, struct mouse *m)
+{
+ bool detected = false;
+ bool x_overlap, y_overlap;
+
+ x_overlap = p->x < (m->x + SPRITE_WIDTH) &&
+ (p->x + SPRITE_WIDTH) > m->x;
+ y_overlap = p->y < (m->y + SPRITE_HEIGHT) &&
+ (p->y + SPRITE_HEIGHT) > m->y;
+ detected = x_overlap && y_overlap;
+
+ /*
+ * Play a little ACK sound and reset the game
+ * if we collide
+ */
+ if (detected) {
+ beep(HIT_BEEP_MSEC, HIT_BEEP_FREQ);
+
+ /* Clear the sprites */
+ draw_sprite(m->x, m->y, GAME_BG);
+ draw_sprite(p->x, p->y, GAME_BG);
+
+ m->x = 0;
+ m->y = rand() % MAX_Y;
+ m->x_inc ^= 1;
+ m->y_inc ^= 1;
+ score_increment(p, m);
+ }
+
+ return detected;
+
+}
+
+static void
+game_loop(void)
+{
+ struct timespec ts;
+ struct mouse mouse;
+ struct player p;
+ char c;
+ bool running = true;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 7000000;
+
+ /* Setup the player */
+ p.x = 0;
+ p.y = 0;
+
+ /* Setup the mouse */
+ mouse.x = MAX_X;
+ mouse.y = MAX_Y;
+ mouse.x_inc = 0;
+ mouse.y_inc = 0;
+ mouse.speed = MIN_MOUSE_SPEED;
+
+ /* Draw player and mouse */
+ draw_sprite(p.x, p.y, PLAYER_BG);
+ draw_sprite(mouse.x, mouse.y, MOUSE_BG);
+
+ while (running) {
+ if (mouse_collide(&p, &mouse)) {
+ continue;
+ }
+
+ c = getchar();
+ sleep(&ts, &ts);
+ update_mouse(&mouse);
+
+ if (IS_ASCII(c)) {
+ draw_sprite(p.x, p.y, GAME_BG);
+ }
+
+ switch (c) {
+ case 'w':
+ p.y -= PLAYER_SPEED;
+ if (p.y <= 0) {
+ p.y = 0;
+ }
+ break;
+ case 'a':
+ p.x -= PLAYER_SPEED;
+ if (p.x <= 0) {
+ p.x = 0;
+ }
+ break;
+ case 's':
+ p.y += PLAYER_SPEED;
+ if (p.y > MAX_Y){
+ p.y = MAX_Y;
+ }
+ break;
+ case 'd':
+ p.x += PLAYER_SPEED;
+ if (p.x > MAX_X) {
+ p.x = MAX_X;
+ }
+ break;
+ case 'q':
+ running = false;
+ default:
+ continue;
+ }
+
+ draw_sprite(p.x, p.y, PLAYER_BG);
+ }
+}
+
+int
+main(void)
+{
+ int error;
+ char c;
+
+ error = gfx_init(&gfx_ctx);
+ if (error < 0) {
+ printf("failed to init libgfx\n");
+ return error;
+ }
+
+ beep_fd = open("/dev/beep", O_WRONLY);
+ game_loop();
+ printf("\033[35;40mYOUR FINAL SCORE: %d\033[0m\n", hit_count);
+
+ /* Cleanup */
+ close(beep_fd);
+ gfx_cleanup(&gfx_ctx);
+ return 0;
+}
diff --git a/usr.bin/nerve/Makefile b/usr.bin/nerve/Makefile
new file mode 100644
index 0000000..cc0fd91
--- /dev/null
+++ b/usr.bin/nerve/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/nerve:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/nerve/nerve.c b/usr.bin/nerve/nerve.c
new file mode 100644
index 0000000..75a19be
--- /dev/null
+++ b/usr.bin/nerve/nerve.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/errno.h>
+#include <sys/console.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+/* Verb numeric defs (see string defs) */
+#define VERB_UNKNOWN -1
+#define VERB_POKE 0x0000
+#define VERB_PEEK 0x0001
+
+/* Verb string defs (see numeric defs) */
+#define SVERB_POKE "poke"
+#define SVERB_PEEK "peek"
+
+/* Nerve numeric defs (see string defs) */
+#define NERVE_UNKNOWN -1
+#define NERVE_CONSATTR 0x0000
+#define NERVE_CONSFEAT 0x0001
+
+/* Nerve string defs (see numeric defs) */
+#define SNERVE_CONSATTR "consattr"
+#define SNERVE_CONSFEAT "consfeat"
+
+/* Misc defines */
+#define NERVE_PACKET_LEN 16
+
+struct verb_handler;
+
+static int poke_nerve(const char *nerve, struct verb_handler *h);
+static int peek_nerve(const char *nerve, struct verb_handler *h);
+static int nerve_to_def(const char *nerve);
+
+/*
+ * Contains verb handlers called when a verb
+ * (e.g., 'poke') is matched.
+ */
+struct verb_handler {
+ int(*run)(const char *nerve, struct verb_handler *h);
+ char **argv;
+ size_t argc;
+};
+
+/*
+ * Holds information that may be sent down
+ * my nerves.
+ *
+ * Example: nerve poke <x> 1 0 1
+ * * * *
+ * +--------+ / / /
+ * | meow | <------+ / /
+ * |--------| / /
+ * | foo | <------+ /
+ * |--------| /
+ * | foobar | <------+
+ * +--------+
+ * packet
+ */
+struct nerve_payload {
+ uint32_t packet[NERVE_PACKET_LEN];
+ uint16_t len;
+};
+
+/*
+ * Verb handler table, when a verb is matched,
+ * its respective handler is called.
+ */
+static struct verb_handler verbtab[] = {
+ { poke_nerve },
+ { peek_nerve }
+};
+
+/*
+ * Print list of available options as well as
+ * information about the program.
+ */
+static void
+help(void)
+{
+ printf(
+ "nerve: usage: nerve <verb> [ .. data ..]\n"
+ "verb 'poke': Poke a control (/ctl) nerve\n"
+ "???????????????? NERVES ????????????????\n"
+ "consattr: Console attributes\n"
+ "consfeat: Console features\n"
+ );
+}
+
+/*
+ * The user gets to send data down my nerves through
+ * a nerve payload. This function acquires the nerve
+ * payload. Please don't hurt me.
+ *
+ * @argc: Number of arguments within argv
+ * @argv: Argument vector
+ * @res: Where the payload goes
+ */
+static int
+get_nerve_payload(int argc, char *argv[], struct nerve_payload *res)
+{
+ char *payload_str;
+ uint32_t datum;
+
+ /* Do we have a nerve payload? */
+ if (argc < 4) {
+ printf("[!] missing nerve payload\n");
+ return -1;
+ }
+
+ /* Reset fields */
+ res->len = 0;
+ memset(res->packet, 0, sizeof(res->packet));
+
+ /* Start grabbing bytes */
+ for (int i = 3; i < argc; ++i) {
+ if (res->len >= NERVE_PACKET_LEN) {
+ printf("[*] truncated packet\n");
+ break;
+ }
+ payload_str = argv[i];
+ datum = atoi(payload_str);
+ res->packet[res->len++] = datum;
+ }
+
+ return 0;
+}
+
+/*
+ * Peek at a control nerve located in /ctl/
+ *
+ * @nerve: Name of nerve to peek at
+ * @h: Verb handler, instance of self
+ *
+ * Returns less than zero if the nerve does
+ * not match.
+ */
+static int
+peek_nerve(const char *nerve, struct verb_handler *h)
+{
+ int error, nerve_idx = -1;
+
+ if (nerve == NULL || h == NULL) {
+ return -EINVAL;
+ }
+
+ /* Grab the nerve table index */
+ nerve_idx = nerve_to_def(nerve);
+ if (nerve_idx == NERVE_UNKNOWN) {
+ printf("[&^]: This is not my nerve.\n");
+ return -1;
+ }
+
+ switch (nerve_idx) {
+ case NERVE_CONSATTR:
+ {
+ struct console_attr c;
+ int fd;
+
+ fd = open("/ctl/console/attr", O_RDONLY);
+ read(fd, &c, sizeof(c));
+ printf("(cursx=%d, cursy=%d)\n", c.cursor_x, c.cursor_y);
+ close(fd);
+ break;
+ }
+ case NERVE_CONSFEAT:
+ {
+ struct console_feat f;
+ int fd;
+
+ fd = open("/ctl/console/feat", O_RDONLY);
+ read(fd, &f, sizeof(f));
+ printf("ansi_esc=%d\n", f.ansi_esc);
+ printf("show_curs=%d\n", f.show_curs);
+ close(fd);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Poke a control nerve located in /ctl/
+ *
+ * @nerve: Name of the nerve (e.g., consattr)
+ * @h: Verb handler, instance of self
+ *
+ * Returns less than zero if the nerve does not
+ * match.
+ */
+static int
+poke_nerve(const char *nerve, struct verb_handler *h)
+{
+ struct nerve_payload payload;
+ int error, nerve_idx = -1;
+
+ if (nerve == NULL || h == NULL) {
+ return -EINVAL;
+ }
+
+ /* Grab the nerve table index */
+ nerve_idx = nerve_to_def(nerve);
+ if (nerve_idx == NERVE_UNKNOWN) {
+ printf("[&^]: This is not my nerve.\n");
+ return -1;
+ }
+
+ /* Grab the payload passed by the user */
+ error = get_nerve_payload(h->argc, h->argv, &payload);
+ if (error < 0) {
+ printf("[!] nerve error\n");
+ return -1;
+ }
+
+ switch (nerve_idx) {
+ case NERVE_CONSATTR:
+ {
+ struct console_attr c;
+ int fd;
+
+ c.cursor_x = payload.packet[0];
+ c.cursor_y = payload.packet[1];
+
+ fd = open("/ctl/console/attr", O_WRONLY);
+ write(fd, &c, sizeof(c));
+ close(fd);
+ break;
+ }
+ case NERVE_CONSFEAT:
+ {
+ struct console_feat f;
+ int fd;
+
+ f.ansi_esc = payload.packet[0] & 0xFF;
+ f.show_curs = payload.packet[1] & 0xFF;
+
+ fd = open("/ctl/console/feat", O_WRONLY);
+ write(fd, &f, sizeof(f));
+ close(fd);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/*
+ * Convert a nerve name into a numeric nerve
+ * definition
+ *
+ * @nerve: Nerve name to convert
+ */
+static int
+nerve_to_def(const char *nerve)
+{
+ /*
+ * Now we need to parse the nerve string
+ * and see if it matches with anything
+ * that we know.
+ */
+ switch (*nerve) {
+ case 'c':
+ if (strcmp(nerve, SNERVE_CONSATTR) == 0) {
+ return NERVE_CONSATTR;
+ } else if (strcmp(nerve, SNERVE_CONSFEAT) == 0) {
+ return NERVE_CONSFEAT;
+ }
+ }
+
+ return NERVE_UNKNOWN;
+}
+
+/*
+ * Convert a string verb, passed in through the command
+ * line, into a numeric definition
+ *
+ * @verb: String verb
+ */
+static int
+verb_to_def(const char *verb)
+{
+ if (verb == NULL) {
+ return -EINVAL;
+ }
+
+ /*
+ * Parse the verb and try to match it against
+ * a constant.
+ *
+ * XXX: Here we are first matching the first character
+ * before we match the entire verb as that is more
+ * efficient than scanning each entire string until
+ * one matches.
+ */
+ switch (*verb) {
+ case 'p':
+ if (strcmp(verb, SVERB_POKE) == 0) {
+ return VERB_POKE;
+ }
+ if (strcmp(verb, SVERB_PEEK) == 0) {
+ return VERB_PEEK;
+ }
+ default:
+ printf("[!] bad verb \"%s\"\n", verb);
+ return VERB_UNKNOWN;
+ }
+
+ return VERB_UNKNOWN;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct verb_handler *verbd;
+ int verb;
+
+ if (argc < 2) {
+ help();
+ return -1;
+ }
+
+ verb = verb_to_def(argv[1]);
+ if (verb < 0) {
+ return -1;
+ }
+
+ /* Make sure the arguments match */
+ switch (verb) {
+ case VERB_POKE:
+ if (argc < 3) {
+ printf("[!] missing nerve name\n");
+ help();
+ return -1;
+ }
+ break;
+ }
+
+ verbd = &verbtab[verb];
+ verbd->argv = argv;
+ verbd->argc = argc;
+ return verbd->run(argv[2], verbd);
+}
diff --git a/usr.bin/notes/Makefile b/usr.bin/notes/Makefile
new file mode 100644
index 0000000..c8717a9
--- /dev/null
+++ b/usr.bin/notes/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/notes:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/notes/notes.c b/usr.bin/notes/notes.c
new file mode 100644
index 0000000..9db8b60
--- /dev/null
+++ b/usr.bin/notes/notes.c
@@ -0,0 +1,132 @@
+/*
+ * 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 <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#define BEEP_MSEC 100
+#define key_step(KEY) ('9' - ((KEY)))
+
+static uint8_t freq_addend = 0;
+
+static uint16_t freqtab[] = {
+ [ key_step('0') ] = 950,
+ [ key_step('9') ] = 900,
+ [ key_step('8') ] = 850,
+ [ key_step('7') ] = 800,
+ [ key_step('6') ] = 750,
+ [ key_step('5') ] = 700,
+ [ key_step('4') ] = 650,
+ [ key_step('3') ] = 600,
+ [ key_step('2') ] = 550,
+ [ key_step('1') ] = 500
+};
+
+static int beep_fd = 0;
+static bool running = false;
+
+static void
+beep(uint16_t freq)
+{
+ uint32_t payload;
+
+ if (beep_fd < 0) {
+ return;
+ }
+
+ payload = freq;
+ payload |= (BEEP_MSEC << 16);
+ write(beep_fd, &payload, sizeof(payload));
+}
+
+static inline void
+play_notekey(char key)
+{
+ uint8_t step = key_step(key);
+ uint16_t freq;
+
+ /* Should not happen */
+ if (step >= NELEM(freqtab)) {
+ step = key_step('0');
+ }
+
+ freq = freqtab[step] + freq_addend;
+ beep(freq);
+}
+
+static void
+play_loop(void)
+{
+ uint16_t freq = 0;
+ char c;
+
+ running = true;
+ while (running) {
+ c = getchar();
+ switch (c) {
+ case 'q':
+ running = false;
+ break;
+ case 'i':
+ /* NOTE: Overflow purposefully allowed here */
+ ++freq_addend;
+ printf("%d ", freq_addend);
+ break;
+ case 'd':
+ /* NOTE: Underflow purposefully allowed here */
+ --freq_addend;
+ printf("%d ", freq_addend);
+ break;
+ default:
+ if (!isdigit(c)) {
+ break;
+ }
+
+ play_notekey(c);
+ }
+ }
+
+ printf("\ncya!\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ beep_fd = open("/dev/beep", O_WRONLY);
+ if (beep_fd < 0) {
+ return -1;
+ }
+
+ printf("bleep bloop time! - [i]nc/[d]ec\n");
+ play_loop();
+ close(beep_fd);
+}
diff --git a/usr.bin/oasm/Makefile b/usr.bin/oasm/Makefile
new file mode 100644
index 0000000..a83aaab
--- /dev/null
+++ b/usr.bin/oasm/Makefile
@@ -0,0 +1,7 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+CFLAGS = -Iinclude/
+
+$(ROOT)/base/usr/bin/oasm:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS) $(CFLAGS)
diff --git a/usr.bin/oasm/emit.c b/usr.bin/oasm/emit.c
new file mode 100644
index 0000000..099f0b2
--- /dev/null
+++ b/usr.bin/oasm/emit.c
@@ -0,0 +1,564 @@
+/*
+ * 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 <oasm/emit.h>
+#include <oasm/log.h>
+#include <stdlib.h>
+#include <string.h>
+
+static inline void
+emit_bytes(struct emit_state *state, void *p, size_t len)
+{
+ write(state->out_fd, p, len);
+}
+
+/*
+ * Convert an IR register to an OSMX64
+ * valid register value that can be encoded
+ * into the instruction.
+ */
+static inline reg_t
+ir_to_reg(tt_t ir)
+{
+ switch (ir) {
+ case TT_X0: return OSMX64_R_X0;
+ case TT_X1: return OSMX64_R_X1;
+ case TT_X2: return OSMX64_R_X2;
+ case TT_X3: return OSMX64_R_X3;
+ case TT_X4: return OSMX64_R_X4;
+ case TT_X5: return OSMX64_R_X5;
+ case TT_X6: return OSMX64_R_X6;
+ case TT_X7: return OSMX64_R_X7;
+ case TT_X8: return OSMX64_R_X8;
+ case TT_X9: return OSMX64_R_X9;
+ case TT_X10: return OSMX64_R_X10;
+ case TT_X11: return OSMX64_R_X11;
+ case TT_X12: return OSMX64_R_X12;
+ case TT_X13: return OSMX64_R_X13;
+ case TT_X14: return OSMX64_R_X14;
+ case TT_X15: return OSMX64_R_X15;
+ }
+
+ return OSMX64_R_BAD;
+}
+
+/*
+ * Encode a MOV instruction
+ *
+ * mov [r], [r/imm]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_mov(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+
+ if (state == NULL || tok == NULL) {
+ return NULL;
+ }
+
+ /* Next token should be a register */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: bad 'mov' order\n");
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad reg in 'mov'\n");
+ return NULL;
+ }
+
+ /* Next token should be an IMM */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ oasm_err("[emit error]: bad 'mov' order\n");
+ return NULL;
+ }
+ if (tok->type != TT_IMM) {
+ oasm_err("[emit error]: expected <imm>\n");
+ return NULL;
+ }
+
+ curinst.opcode = OSMX64_MOV_IMM;
+ curinst.rd = rd;
+ curinst.imm = tok->imm;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a INC/DEC instruction
+ *
+ * inc/dec [r]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_incdec(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_INC;
+ char *inst_str = "inc";
+
+ if (state == NULL || tok == NULL) {
+ return NULL;
+ }
+
+ if (tok->type == TT_DEC) {
+ inst_str = "dec";
+ opcode = OSMX64_DEC;
+ }
+
+ /* Next token should be a register */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: bad '%s' order\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad reg in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode an arithmetic instruction
+ *
+ * add [r], <imm>
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_arith(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_ADD;
+ char *inst_str = "add";
+
+ switch (tok->type) {
+ case TT_SUB:
+ inst_str = "sub";
+ opcode = OSMX64_SUB;
+ break;
+ case TT_MUL:
+ inst_str = "mul";
+ opcode = OSMX64_MUL;
+ break;
+ case TT_DIV:
+ inst_str = "div";
+ opcode = OSMX64_DIV;
+ break;
+ }
+
+ /*
+ * The next operand must be an X<n>
+ * register.
+ */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: bad '%s' order\n", inst_str);
+ return NULL;
+ }
+
+ /* Get the register and validate it */
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad reg in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ /* The next token should be an <imm> */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (tok->type != TT_IMM) {
+ oasm_err("[emit error]: expected <imm> in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.imm = tok->imm;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a HLT instruction
+ *
+ * 'hlt' - no operands
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_hlt(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+
+ curinst.opcode = OSMX64_HLT;
+ curinst.rd = 0;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a BR instruction
+ *
+ * br [r]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_br(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_BR;
+ char *inst_str = "br";
+
+ /* Grab the register */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: expected register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad in register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode the MRO type instructions
+ *
+ * mrob x1[7:0]
+ * mrow x1[15:0] ! Mrowwww :3333
+ * mrod x1[31:0]
+ * mroq x[63:0]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_mro(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_MROB;
+ char *inst_str = "mrob";
+
+ switch (tok->type) {
+ case TT_MROW:
+ opcode = OSMX64_MROW;
+ inst_str = "mrow";
+ break;
+ case TT_MROD:
+ opcode = OSMX64_MROD;
+ inst_str = "mrod";
+ break;
+ case TT_MROQ:
+ opcode = OSMX64_MROQ;
+ inst_str = "mroq";
+ break;
+ }
+
+ /* Next token should be a register */
+ tok = TAILQ_NEXT(tok, link);
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: expected register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ /* Next token should be an IMM */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok->type != TT_IMM) {
+ oasm_err("[emit error]: expected <imm> after reg in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.imm = tok->imm;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a NOP instruction
+ *
+ * 'nop' - no operands
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_nop(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+
+ curinst.opcode = OSMX64_NOP;
+ curinst.rd = 0;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a bitwise instruction:
+ *
+ * and r, r/imm
+ * or r, r/imm
+ * xor r, r/imm
+ */
+static struct oasm_token *
+emit_encode_bitw(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ imm_t imm;
+ reg_t rd;
+ uint8_t opcode = OSMX64_AND;
+ char *inst_str = "and";
+
+ switch (tok->type) {
+ case TT_OR:
+ opcode = OSMX64_OR;
+ inst_str = "or";
+ break;
+ case TT_XOR:
+ opcode = OSMX64_XOR;
+ inst_str = "xor";
+ break;
+ case TT_LSR:
+ opcode = OSMX64_LSR;
+ inst_str = "lsr";
+ break;
+ case TT_LSL:
+ opcode = OSMX64_LSL;
+ inst_str = "lsl";
+ break;
+ }
+
+ /* Next token should be a register */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ oasm_err("[emit error]: expected register for '%s'\n", inst_str);
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: bad register for '%s'\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ oasm_err("[emit error]: missing operand in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ /*
+ * Check that the next token is an immediate
+ * value.
+ *
+ * TODO: Allow a register operand to be passed
+ * to these instructions.
+ */
+ if (tok->type != TT_IMM) {
+ oasm_err("[emit error]: expected <imm> for '%s'\n", inst_str);
+ return NULL;
+ }
+
+ imm = tok->imm;
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.imm = imm;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+int
+emit_osmx64(struct emit_state *state, struct oasm_token *tp)
+{
+ struct oasm_token *toknew;
+
+ if (state == NULL || tp == NULL) {
+ return -EINVAL;
+ }
+
+ /*
+ * We need to create a copy of the object as the
+ * caller will likely end up destroying it.
+ */
+ toknew = malloc(sizeof(*toknew));
+ if (toknew == NULL) {
+ return -ENOMEM;
+ }
+
+ memcpy(toknew, tp, sizeof(*toknew));
+ TAILQ_INSERT_TAIL(&state->ir, toknew, link);
+ return 0;
+}
+
+int
+emit_init(struct emit_state *state)
+{
+ state->last_token = TT_UNKNOWN;
+ state->is_init = 1;
+ TAILQ_INIT(&state->ir);
+ return 0;
+}
+
+int
+emit_destroy(struct emit_state *state)
+{
+ struct oasm_token *curtok, *last = NULL;
+
+ TAILQ_FOREACH(curtok, &state->ir, link) {
+ if (last != NULL) {
+ free(last);
+ last = NULL;
+ }
+ if (curtok->raw != NULL) {
+ free(curtok->raw);
+ }
+
+ last = curtok;
+ }
+
+ /* Clean up any last objects */
+ if (last != NULL) {
+ free(last);
+ }
+
+ return 0;
+}
+
+int
+emit_process(struct oasm_state *oasm, struct emit_state *emit)
+{
+ struct oasm_token *curtok;
+ tt_t last_tok;
+
+ if (!emit->is_init) {
+ return -1;
+ }
+
+ emit->out_fd = oasm->out_fd;
+ curtok = TAILQ_FIRST(&emit->ir);
+ while (curtok != NULL) {
+ switch (curtok->type) {
+ case TT_NOP:
+ curtok = emit_encode_nop(emit, curtok);
+ break;
+ case TT_MOV:
+ curtok = emit_encode_mov(emit, curtok);
+ break;
+ case TT_INC:
+ case TT_DEC:
+ curtok = emit_encode_incdec(emit, curtok);
+ break;
+ case TT_ADD:
+ case TT_SUB:
+ case TT_MUL:
+ case TT_DIV:
+ curtok = emit_encode_arith(emit, curtok);
+ break;
+ case TT_AND:
+ case TT_OR:
+ case TT_XOR:
+ case TT_LSR:
+ case TT_LSL:
+ curtok = emit_encode_bitw(emit, curtok);
+ break;
+ case TT_BR:
+ curtok = emit_encode_br(emit, curtok);
+ break;
+ case TT_HLT:
+ curtok = emit_encode_hlt(emit, curtok);
+ break;
+ default:
+ if (tok_is_mro(curtok->type)) {
+ curtok = emit_encode_mro(emit, curtok);
+ break;
+ }
+ curtok = TAILQ_NEXT(curtok, link);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/usr.bin/oasm/include/oasm/emit.h b/usr.bin/oasm/include/oasm/emit.h
new file mode 100644
index 0000000..57683a8
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/emit.h
@@ -0,0 +1,120 @@
+/* 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 _EMIT_H_
+#define _EMIT_H_
+
+#include <sys/queue.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <oasm/lex.h>
+#include <oasm/state.h>
+
+/*
+ * The OSMX64 architecture has 32-bit instructions
+ * that are encoded in the following manner:
+ *
+ * - [0:7]: Opcode
+ * - [11:8]: Register
+ * - [31:12]: Reserved
+ *
+ * The values below define various operation
+ * codes.
+ */
+#define OSMX64_NOP 0x00 /* No-operation */
+#define OSMX64_ADD 0x01 /* Add operation */
+#define OSMX64_SUB 0x02 /* Sub operation */
+#define OSMX64_MUL 0x03 /* Multiply operation */
+#define OSMX64_DIV 0x04 /* Divide operation */
+#define OSMX64_INC 0x05 /* Increment operation */
+#define OSMX64_DEC 0x06 /* Decrement operation */
+#define OSMX64_OR 0x07 /* Bitwise OR operation */
+#define OSMX64_XOR 0x08 /* Bitwise XOR operation */
+#define OSMX64_AND 0x09 /* Bitwise AND operation */
+#define OSMX64_NOT 0x0A /* Bitwise NOT operation */
+#define OSMX64_SLL 0x0B /* Shift left logical operation */
+#define OSMX64_SRL 0x0C /* Shift right logical operation */
+#define OSMX64_MOV_IMM 0x0D /* Data move operation from IMM */
+#define OSMX64_HLT 0x0E /* Halt the processor */
+#define OSMX64_BR 0x0F /* Branch */
+#define OSMX64_MROB 0x10 /* Mask register over byte */
+#define OSMX64_MROW 0x11 /* Mask register over word */
+#define OSMX64_MROD 0x12 /* Mask register over dword */
+#define OSMX64_MROQ 0x13 /* Mask register over qword */
+#define OSMX64_LSR 0x14 /* Logical shift right */
+#define OSMX64_LSL 0x15 /* Logical shift left */
+
+/*
+ * OSMX64 register definitions
+ */
+#define OSMX64_R_X0 0x00
+#define OSMX64_R_X1 0x01
+#define OSMX64_R_X2 0x02
+#define OSMX64_R_X3 0x03
+#define OSMX64_R_X4 0x04
+#define OSMX64_R_X5 0x05
+#define OSMX64_R_X6 0x06
+#define OSMX64_R_X7 0x07
+#define OSMX64_R_X8 0x08
+#define OSMX64_R_X9 0x09
+#define OSMX64_R_X10 0x0A
+#define OSMX64_R_X11 0x0B
+#define OSMX64_R_X12 0x0C
+#define OSMX64_R_X13 0x0D
+#define OSMX64_R_X14 0x0E
+#define OSMX64_R_X15 0x0F
+#define OSMX64_R_BAD 0xFF
+
+typedef uint8_t reg_t;
+typedef uint16_t imm_t;
+
+/*
+ * OSMX64 instruction
+ */
+typedef struct {
+ uint8_t opcode;
+ uint8_t rd;
+ union {
+ uint16_t imm;
+ uint16_t unused;
+ };
+} inst_t;
+
+struct emit_state {
+ tt_t last_token;
+ uint8_t is_init : 1;
+ int out_fd;
+ TAILQ_HEAD(, oasm_token) ir;
+};
+
+int emit_init(struct emit_state *state);
+int emit_destroy(struct emit_state *state);
+int emit_process(struct oasm_state *oasm, struct emit_state *emit);
+int emit_osmx64(struct emit_state *state, struct oasm_token *tp);
+
+#endif /* !_EMIT_H_ */
diff --git a/usr.bin/oasm/include/oasm/label.h b/usr.bin/oasm/include/oasm/label.h
new file mode 100644
index 0000000..8acb369
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/label.h
@@ -0,0 +1,55 @@
+/*
+ * 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 _OASM_LABEL_H_
+#define _OASM_LABEL_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#define MAX_LABELS 128
+
+/*
+ * Represents a label
+ *
+ * @name: Label name (e.g., _start)
+ * @ip: Address at which label code starts
+ */
+struct oasm_label {
+ char *name;
+ uintptr_t ip;
+ TAILQ_ENTRY(oasm_label) link;
+ TAILQ_HEAD(, oasm_label) buckets;
+};
+
+void labels_destroy(void);
+int label_enter(const char *name, uintptr_t ip);
+struct oasm_label *label_lookup(const char *name);
+
+#endif /* !_OASM_LABEL_H_ */
diff --git a/usr.bin/oasm/include/oasm/lex.h b/usr.bin/oasm/include/oasm/lex.h
new file mode 100644
index 0000000..93422a6
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/lex.h
@@ -0,0 +1,188 @@
+/*
+ * 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 _OASM_LEX_H_
+#define _OASM_LEX_H_
+
+#include <sys/queue.h>
+#include <sys/cdefs.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct oasm_state;
+
+#define __XN_REGS \
+ TT_X0, \
+ TT_X1, \
+ TT_X2, \
+ TT_X3, \
+ TT_X4, \
+ TT_X5, \
+ TT_X6, \
+ TT_X7, \
+ TT_X8, \
+ TT_X9, \
+ TT_X10, \
+ TT_X11, \
+ TT_X12, \
+ TT_X13, \
+ TT_X14, \
+ TT_X15
+
+#define __FN_REGS \
+ TT_F0, \
+ TT_F1, \
+ TT_F2, \
+ TT_F3, \
+ TT_F4, \
+ TT_F5, \
+ TT_F6, \
+ TT_F7
+
+#define __DN_REGS \
+ TT_D0, \
+ TT_D1, \
+ TT_D2, \
+ TT_D3, \
+ TT_D4, \
+ TT_D5, \
+ TT_D6, \
+ TT_D7
+
+#define __VN_REGS \
+ TT_V0, \
+ TT_V1, \
+ TT_V2, \
+ TT_V3, \
+ TT_V4, \
+ TT_V5, \
+ TT_V6, \
+ TT_V7
+
+/*
+ * Token type definitions
+ */
+typedef enum {
+ TT_UNKNOWN, /* Unknown token */
+ TT_NOP, /* No operation */
+
+ /* Arithmetic instructions */
+ TT_ADD, /* 'add' */
+ TT_SUB, /* 'sub' */
+ TT_MUL, /* 'mul' */
+ TT_DIV, /* 'div' */
+ TT_HLT, /* 'hlt' */
+ TT_BR, /* 'br' */
+ TT_MROB, /* 'mrob' */
+ TT_MROW, /* 'mrow' */
+ TT_MROD, /* 'mrod' */
+ TT_MROQ, /* 'mroq' */
+ TT_AND, /* 'and' */
+ TT_OR, /* 'or' */
+ TT_XOR, /* 'xor' */
+ TT_LSR, /* 'lsr' */
+ TT_LSL, /* 'lsl' */
+
+ /* Register ops */
+ TT_MOV, /* 'mov' */
+ TT_INC, /* 'inc' */
+ TT_DEC, /* 'dec' */
+ TT_IMM, /* #<n> */
+ TT_LABEL, /* 'label: ...' */
+
+ /* Register sets */
+ __XN_REGS, /* x0-x15 */
+ __FN_REGS, /* f0-f7 */
+ __DN_REGS, /* d0-d7 */
+ __VN_REGS, /* v0-v7 */
+
+ /* Symbols */
+ TT_COMMA, /* ',' */
+} tt_t;
+
+struct oasm_token {
+ tt_t type;
+ uint8_t is_reg : 1;
+ uint16_t imm;
+ char *raw;
+ TAILQ_ENTRY(oasm_token) link;
+};
+
+int lex_tok(struct oasm_state *state, struct oasm_token *ttp);
+
+
+/*
+ * Check if a token is an X<n> register.
+ * Returns true on match.
+ */
+__always_inline static inline bool
+tok_is_xreg(tt_t tok)
+{
+ switch (tok) {
+ case TT_X0:
+ case TT_X1:
+ case TT_X2:
+ case TT_X3:
+ case TT_X4:
+ case TT_X5:
+ case TT_X6:
+ case TT_X7:
+ case TT_X8:
+ case TT_X9:
+ case TT_X10:
+ case TT_X11:
+ case TT_X12:
+ case TT_X13:
+ case TT_X14:
+ case TT_X15:
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Check if a token is of an MRO type
+ * instruction. Returns true on match.
+ */
+__always_inline static inline bool
+tok_is_mro(tt_t tok)
+{
+ switch (tok) {
+ case TT_MROB:
+ case TT_MROW:
+ case TT_MROD:
+ case TT_MROQ:
+ return true;
+ }
+
+ return false;
+}
+
+#endif /* !_OASM_LEX_H_ */
diff --git a/usr.bin/oasm/include/oasm/log.h b/usr.bin/oasm/include/oasm/log.h
new file mode 100644
index 0000000..330c273
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/log.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _OASM_LOG_H_
+#define _OASM_LOG_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <stdio.h>
+
+#define ERROR_COLOR "\033[31;40m"
+#define WARN_COLOR "\033[35;40m"
+
+void __oasm_debug(const char *fmt, ...);
+void __oasm_err(const char *fmt, ...);
+void __oasm_warn(const char *fmt, ...);
+
+#define oasm_debug(...) __oasm_debug(__VA_ARGS__)
+#define oasm_err(...) __oasm_err(__VA_ARGS__)
+#define oasm_warn(...) __oasm_warn(__VA_ARGS__)
+
+#endif /* !_OASM_LOG_H_ */
diff --git a/usr.bin/oasm/include/oasm/parse.h b/usr.bin/oasm/include/oasm/parse.h
new file mode 100644
index 0000000..04962e7
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/parse.h
@@ -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.
+ */
+
+#ifndef _OASM_PARSE_H_
+#define _OASM_PARSE_H_
+
+#include <oasm/state.h>
+
+void parse_enter(struct oasm_state *state);
+
+#endif /* !_OASM_PARSE_H_ */
diff --git a/usr.bin/oasm/include/oasm/state.h b/usr.bin/oasm/include/oasm/state.h
new file mode 100644
index 0000000..6dd2435
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/state.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _OASM_STATE_H_
+#define _OASM_STATE_H_
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <oasm/lex.h>
+
+/*
+ * OASM state:
+ *
+ * @filename: Filname of unit we are parsing
+ * @pip: Pseudo instruction pointer
+ * @label_ip: IP at current label start
+ * @in_fd: Input file descriptor
+ * @out_fd: Resulting binary output file descriptor
+ * @line: Current line number
+ * @last: Last token
+ */
+struct oasm_state {
+ char *filename;
+ off_t pip;
+ off_t label_ip;
+ int in_fd;
+ int out_fd;
+ off_t line;
+ tt_t last;
+};
+
+#endif /* !_OASM_STATE_H_ */
diff --git a/usr.bin/oasm/label.c b/usr.bin/oasm/label.c
new file mode 100644
index 0000000..2647bb9
--- /dev/null
+++ b/usr.bin/oasm/label.c
@@ -0,0 +1,166 @@
+/*
+ * 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/queue.h>
+#include <oasm/label.h>
+#include <oasm/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+static struct oasm_label *labels[MAX_LABELS];
+static size_t label_count = 0;
+
+static uint32_t
+fnv1_hash(const char *s)
+{
+ uint32_t hash = 2166136261UL;
+ const uint8_t *p = (uint8_t *)s;
+
+ while (*p != '\0') {
+ hash ^= *p;
+ hash = hash * 0x01000193;
+ ++p;
+ }
+
+ return hash;
+}
+
+/*
+ * The label table is a big hashmap containing
+ * label entries. This function creates and add
+ * a new label into the table.
+ *
+ * @name: Name of the label (e.g., _start)
+ * @ip: Instruction pointer
+ */
+int
+label_enter(const char *name, uintptr_t ip)
+{
+ uint32_t hash = fnv1_hash(name);
+ uint32_t idx = hash % MAX_LABELS;
+ struct oasm_label *lp, *lp_new;
+
+ if (label_count >= MAX_LABELS) {
+ oasm_err("[internal error]: too many labels\n");
+ return -EIO;
+ }
+
+ lp_new = malloc(sizeof(*lp_new));
+ if (lp_new == NULL) {
+ oasm_err("[internal error]: out of memory\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize the label */
+ lp_new->name = strdup(name);
+ lp_new->ip = ip;
+ TAILQ_INIT(&lp_new->buckets);
+
+ /*
+ * If there is no existing entry here, we
+ * can take this slot.
+ */
+ lp = labels[idx];
+ if (lp == NULL) {
+ labels[idx] = lp_new;
+ ++label_count;
+ return 0;
+ }
+
+ /*
+ * To prevent collisions in our table here,
+ * we must check if the name matches at all.
+ * If it does not, there is a collision and
+ * we'll have to add this to a bucket.
+ */
+ if (strcmp(name, lp->name) != 0) {
+ TAILQ_INSERT_TAIL(&lp->buckets, lp_new, link);
+ ++label_count;
+ return 0;
+ }
+
+ /* Can't put the same entry in twice */
+ oasm_err("[internal error]: duplicate labels\n");
+ return -EEXIST;
+}
+
+/*
+ * Find a label entry in the label table.
+ *
+ * @name: Name of the label to lookup (e.g., _start)
+ */
+struct oasm_label *
+label_lookup(const char *name)
+{
+ uint32_t hash = fnv1_hash(name);
+ uint32_t idx = hash % MAX_LABELS;
+ struct oasm_label *lp, *lp_tmp;
+
+ lp = labels[idx];
+ if (lp == NULL) {
+ return NULL;
+ }
+
+ /* Is this the label we are looking up? */
+ if (strcmp(name, lp->name) == 0) {
+ return lp;
+ }
+
+ /* Maybe there was a collision? */
+ TAILQ_FOREACH(lp_tmp, &lp->buckets, link) {
+ if (strcmp(name, lp_tmp->name) == 0) {
+ return lp_tmp;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Clean up all allocated labels by
+ * calling free() on each entry of
+ * the queue.
+ */
+void
+labels_destroy(void)
+{
+ struct oasm_label *lp;
+
+ for (size_t i = 0; i < MAX_LABELS; ++i) {
+ lp = labels[i];
+ if (lp != NULL) {
+ free(lp->name);
+ free(lp);
+ }
+ }
+}
diff --git a/usr.bin/oasm/lex.c b/usr.bin/oasm/lex.c
new file mode 100644
index 0000000..1f58d07
--- /dev/null
+++ b/usr.bin/oasm/lex.c
@@ -0,0 +1,445 @@
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+#include <oasm/state.h>
+#include <oasm/lex.h>
+#include <oasm/log.h>
+
+#define COMMENT '!'
+#define is_num(c) ((c) >= '0' && (c) <= '9')
+
+static char putback = '\0';
+
+/* Instruction mnemonic strings */
+#define S_IMN_NOP "nop"
+#define S_IMN_MOV "mov"
+#define S_IMN_ADD "add"
+#define S_IMN_SUB "sub"
+#define S_IMN_MUL "mul"
+#define S_IMN_DIV "div"
+#define S_IMN_INC "inc"
+#define S_IMN_DEC "dec"
+#define S_IMN_HLT "hlt"
+#define S_IMN_BR "br"
+#define S_IMN_MROB "mrob"
+#define S_IMN_MROW "mrow"
+#define S_IMN_MROD "mrod"
+#define S_IMN_MROQ "mroq"
+#define S_IMN_AND "and"
+#define S_IMN_OR "or"
+#define S_IMN_XOR "xor"
+#define S_IMN_LSL "lsl"
+#define S_IMN_LSR "lsr"
+
+/* Instruction length */
+#define OSMX64_INST_LEN 4
+
+/*
+ * Update the state when the caller encounters
+ * a newline.
+ */
+static inline void
+lex_newline(struct oasm_state *state)
+{
+ ++state->line;
+ state->pip += OSMX64_INST_LEN;
+}
+
+/*
+ * Returns 0 if a char is counted as a
+ * skippable token. Otherwise, -1
+ */
+static inline int
+lex_skippable(struct oasm_state *state, char c)
+{
+ switch (c) {
+ case ' ': return 0;
+ case '\f': return 0;
+ case '\t': return 0;
+ case '\r': return 0;
+ case '\n':
+ lex_newline(state);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * For cleaning up allocated sources
+ * during error conditions
+ *
+ * @p: Memory to free
+ */
+static inline void
+lex_try_free(void *p)
+{
+ if (p != NULL) {
+ free(p);
+ }
+}
+
+/*
+ * Put back a token to grab later
+ *
+ * @c: Character to put back
+ */
+static inline char
+lex_putback(char c)
+{
+ putback = c;
+ return c;
+}
+
+/*
+ * Grab a character from the input file
+ * descriptor.
+ */
+static char
+lex_cin(struct oasm_state *state)
+{
+ char retval;
+
+ if (putback != '\0') {
+ retval = putback;
+ putback = '\0';
+ return retval;
+ }
+
+ if (read(state->in_fd, &retval, 1) <= 0) {
+ return '\0';
+ }
+ return retval;
+}
+
+/*
+ * Nom an operation, directive or any kind
+ * of raw string (unquoted/builtin) and return
+ * memory allocated by strdup() pointing to the
+ * string.
+ *
+ * @state: OASM state pointer
+ * @res: Resulting string
+ *
+ * Returns 0 on success. Greater than zero
+ * value of the last character if a comma or
+ * space was not buffered.
+ */
+static int
+lex_nomstr(struct oasm_state *state, char **res)
+{
+ char buf[256];
+ int retval = 0, n = 0;
+ int tmp;
+
+ memset(buf, 0, sizeof(buf));
+
+ /*
+ * We are filling the buffer containing
+ * the operation or directive.
+ *
+ * Keep going until we hit a space or comman (^)
+ * Examples of such strings (everything in '[]'):
+ *
+ * [mov] [x0], [#1]
+ * ^ ^
+ */
+ while ((tmp = lex_cin(state)) != 0) {
+ if (tmp == ' ' || tmp == ',') {
+ retval = tmp;
+ break;
+ }
+ if (tmp == ':') {
+ retval = tmp;
+ break;
+ }
+ if (tmp == '\n') {
+ ++state->line;
+ retval = tmp;
+ break;
+
+ }
+
+ buf[n++] = tmp;
+ }
+
+ *res = strdup(buf);
+ return retval;
+}
+
+static tt_t
+token_arith(char *p)
+{
+ if (strcmp(p, S_IMN_MOV) == 0) {
+ return TT_MOV;
+ } else if (strcmp(p, S_IMN_INC) == 0) {
+ return TT_INC;
+ } else if (strcmp(p, S_IMN_DEC) == 0) {
+ return TT_DEC;
+ } else if (strcmp(p, S_IMN_ADD) == 0) {
+ return TT_ADD;
+ } else if (strcmp(p, S_IMN_SUB) == 0) {
+ return TT_SUB;
+ } else if (strcmp(p, S_IMN_DIV) == 0) {
+ return TT_DIV;
+ } else if (strcmp(p, S_IMN_HLT) == 0) {
+ return TT_HLT;
+ } else if (strcmp(p, S_IMN_MUL) == 0) {
+ return TT_MUL;
+ } else if (strcmp(p, S_IMN_XOR) == 0) {
+ return TT_XOR;
+ }
+
+ return TT_UNKNOWN;
+}
+
+/*
+ * Control flow instructions
+ */
+static tt_t
+token_cfi(char *p)
+{
+ if (strcmp(p, S_IMN_BR) == 0) {
+ return TT_BR;
+ }
+
+ return TT_UNKNOWN;
+}
+
+/*
+ * Bitwise MRO instructions
+ */
+static tt_t
+token_bitw_mro(char *p)
+{
+ if (strcmp(p, S_IMN_MROB) == 0) {
+ return TT_MROB;
+ } else if (strcmp(p, S_IMN_MROW) == 0) {
+ return TT_MROW;
+ } else if (strcmp(p, S_IMN_MROD) == 0) {
+ return TT_MROD;
+ } else if (strcmp(p, S_IMN_MROQ) == 0) {
+ return TT_MROQ;
+ } else if (strcmp(p, S_IMN_AND) == 0) {
+ return TT_AND;
+ } else if (strcmp(p, S_IMN_OR) == 0) {
+ return TT_OR;
+ }
+
+ return TT_UNKNOWN;
+}
+
+/*
+ * Bitwise instructions
+ */
+static tt_t
+token_bitw(char *p)
+{
+ tt_t token;
+
+ token = token_bitw_mro(p);
+ if (token != TT_UNKNOWN) {
+ return token;
+ }
+
+ if (strcmp(p, S_IMN_LSL) == 0) {
+ return TT_LSL;
+ } else if (strcmp(p, S_IMN_LSR) == 0) {
+ return TT_LSR;
+ }
+
+ return TT_UNKNOWN;
+}
+
+static tt_t
+token_xreg(char *p)
+{
+ int num;
+
+ if (p[0] != 'x') {
+ return TT_UNKNOWN;
+ }
+
+ if (!is_num(p[1])) {
+ return TT_UNKNOWN;
+ }
+
+ num = atoi(&p[1]);
+ switch (num) {
+ case 0: return TT_X0;
+ case 1: return TT_X1;
+ case 2: return TT_X2;
+ case 3: return TT_X3;
+ case 4: return TT_X4;
+ case 5: return TT_X5;
+ case 6: return TT_X6;
+ case 7: return TT_X7;
+ case 8: return TT_X8;
+ case 9: return TT_X9;
+ case 10: return TT_X10;
+ case 11: return TT_X11;
+ case 12: return TT_X12;
+ case 13: return TT_X13;
+ case 14: return TT_X14;
+ case 15: return TT_X15;
+ }
+
+ return TT_UNKNOWN;
+}
+
+static tt_t
+token_operand(char *p)
+{
+ /* Is this a numeric constant? */
+ if (p[0] == '#') {
+ return TT_IMM;
+ }
+
+ return TT_UNKNOWN;
+}
+
+static tt_t
+token_reg(char *p)
+{
+ tt_t tok;
+
+ if ((tok = token_xreg(p)) != TT_UNKNOWN) {
+ return tok;
+ }
+
+ return TT_UNKNOWN;
+}
+
+int
+lex_tok(struct oasm_state *state, struct oasm_token *ttp)
+{
+ char *p = NULL;
+ char c = ' ';
+ short in_comment = 0;
+ int tmp;
+ tt_t tok;
+
+ if (state == NULL || ttp == NULL) {
+ return -EINVAL;
+ }
+
+ /*
+ * Grab characters. If they are skippable or
+ * comments, don't use them.
+ */
+ while (lex_skippable(state, c) == 0 || in_comment) {
+ if ((c = lex_cin(state)) == 0) {
+ return -1;
+ }
+
+ if (c == COMMENT) {
+ in_comment = 1;
+ } else if (c == '\n') {
+ in_comment = 0;
+ }
+ }
+
+ switch (c) {
+ case '\n':
+ lex_newline(state);
+ return 0;
+ case '\0':
+ return -1;
+ case ',':
+ return TT_COMMA;
+ default:
+ ttp->type = TT_UNKNOWN;
+ ttp->raw = NULL;
+
+ lex_putback(c);
+ c = lex_nomstr(state, &p);
+
+ while (c == ':') {
+ ttp->type = TT_LABEL;
+ ttp->raw = p;
+ state->label_ip = state->pip;
+ return 0;
+ }
+
+ /* No operation? */
+ if (strcmp(p, S_IMN_NOP) == 0) {
+ ttp->type = TT_NOP;
+ ttp->raw = p;
+ return 0;
+ }
+
+ /* Arithmetic operation? */
+ if ((tok = token_arith(p)) != TT_UNKNOWN) {
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
+ /* Control flow instruction? */
+ if ((tok = token_cfi(p)) != TT_UNKNOWN) {
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
+ /* Register? */
+ if ((tok = token_reg(p)) != TT_UNKNOWN) {
+ ttp->is_reg = 1;
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
+ if ((tok = token_bitw(p)) != TT_UNKNOWN) {
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
+ /* Immediate operand? */
+ if ((tok = token_operand(p)) != TT_UNKNOWN) {
+ if (tok == TT_IMM) {
+ ttp->imm = atoi(&p[1]);
+ }
+
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
+ oasm_err("bad token \"%s\"\n", p);
+ lex_try_free(p);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/usr.bin/oasm/log.c b/usr.bin/oasm/log.c
new file mode 100644
index 0000000..c408865
--- /dev/null
+++ b/usr.bin/oasm/log.c
@@ -0,0 +1,81 @@
+/*
+ * 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 <oasm/log.h>
+#include <oasm/state.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* TODO FIXME: Use stdarg.h */
+#define __va_start(ap, fmt) __builtin_va_start(ap, fmt)
+#define __va_end(ap) __builtin_va_end(ap)
+
+extern struct oasm_state g_state;
+
+void
+oasm_debug(const char *fmt, ...)
+{
+ char buf[512];
+ va_list ap;
+ int ret;
+
+ __va_start(ap, fmt);
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+ printf("[debug]: %s\033[0m", buf);
+ printf("\033[0m");
+ __va_end(ap);
+}
+
+void
+oasm_err(const char *fmt, ...)
+{
+ char buf[512];
+ va_list ap;
+ int ret;
+
+ __va_start(ap, fmt);
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+ printf(ERROR_COLOR "error: %s\033[0m", buf);
+ printf("%s: line %d\n", g_state.filename, g_state.line);
+ __va_end(ap);
+}
+
+void
+oasm_warn(const char *fmt, ...)
+{
+ char buf[512];
+ va_list ap;
+ int ret;
+
+ __va_start(ap, fmt);
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+ printf(WARN_COLOR "warning: %s\033[0m", buf);
+ printf("line %d\n", g_state.filename, g_state.line);
+ __va_end(ap);
+}
diff --git a/usr.bin/oasm/oasm.c b/usr.bin/oasm/oasm.c
new file mode 100644
index 0000000..6c37778
--- /dev/null
+++ b/usr.bin/oasm/oasm.c
@@ -0,0 +1,73 @@
+/*
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <oasm/state.h>
+#include <oasm/parse.h>
+#define OASM_DBG
+#include <oasm/log.h>
+
+struct oasm_state g_state;
+
+static void
+oasm_start(struct oasm_state *state)
+{
+ state->line = 1;
+ parse_enter(state);
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 3) {
+ printf("oasm: usage: oasm <file> <output>\n");
+ return -1;
+ }
+
+ g_state.in_fd = open(argv[1], O_RDONLY);
+ if (g_state.in_fd < 0) {
+ printf("could not open \"%s\"\n", argv[1]);
+ return -1;
+ }
+
+ g_state.out_fd = open(argv[2], O_CREAT | O_WRONLY);
+ if (g_state.out_fd < 0) {
+ printf("could not open output \"%s\"\n", argv[2]);
+ close(g_state.in_fd);
+ return -1;
+ }
+
+ g_state.filename = argv[1];
+ oasm_start(&g_state);
+ close(g_state.in_fd);
+ close(g_state.out_fd);
+ return 0;
+}
diff --git a/usr.bin/oasm/parse.c b/usr.bin/oasm/parse.c
new file mode 100644
index 0000000..042cce8
--- /dev/null
+++ b/usr.bin/oasm/parse.c
@@ -0,0 +1,285 @@
+/* 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 <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <oasm/emit.h>
+#include <oasm/state.h>
+#include <oasm/lex.h>
+#include <oasm/parse.h>
+#include <oasm/log.h>
+#include <oasm/label.h>
+
+static struct emit_state emit_state;
+static const char *tokstr[] = {
+ [ TT_UNKNOWN] = "bad",
+ [ TT_NOP ] = "nop",
+ [ TT_ADD ] = "add",
+ [ TT_SUB ] = "sub",
+ [ TT_MUL ] = "mul",
+ [ TT_DIV ] = "div",
+ [ TT_HLT ] = "hlt",
+ [ TT_BR ] = "br",
+ [ TT_COMMA ] = ",",
+ [ TT_INC ] = "inc",
+ [ TT_DEC ] = "dec",
+ [ TT_MOV ] = "mov",
+ [ TT_IMM ] = "<imm>",
+ [ TT_LABEL ] = "<label>",
+ [ TT_LSR ] = "lsr",
+ [ TT_LSL ] = "lsl",
+
+ /* Bitwise */
+ [ TT_MROB ] = "mrob",
+ [ TT_MROW ] = "mrow",
+ [ TT_MROD ] = "mrod",
+ [ TT_MROQ ] = "mroq",
+ [ TT_AND ] = "and",
+ [ TT_OR ] = "or",
+ [ TT_XOR ] = "xor",
+
+ /* X<n> registers */
+ [ TT_X0 ] = "x0",
+ [ TT_X1 ] = "x1",
+ [ TT_X2 ] = "x2",
+ [ TT_X3 ] = "x3",
+ [ TT_X4 ] = "x4",
+ [ TT_X5 ] = "x5",
+ [ TT_X6 ] = "x6",
+ [ TT_X7 ] = "x7",
+ [ TT_X8 ] = "x8",
+ [ TT_X9 ] = "x9",
+ [ TT_X10 ] = "x10",
+ [ TT_X11 ] = "x11",
+ [ TT_X12 ] = "x12",
+ [ TT_X13 ] = "x13",
+ [ TT_X14 ] = "x14",
+ [ TT_X15 ] = "x15",
+
+ /* V<n> registers */
+ [ TT_F0 ] = "v0",
+ [ TT_F1 ] = "v1",
+ [ TT_F2 ] = "v2",
+ [ TT_F3 ] = "v3",
+ [ TT_F4 ] = "v4",
+ [ TT_F5 ] = "v5",
+ [ TT_F6 ] = "v6",
+ [ TT_F7 ] = "v7",
+
+ /* D<n> registers */
+ [ TT_D0 ] = "d0",
+ [ TT_D1 ] = "d1",
+ [ TT_D2 ] = "d2",
+ [ TT_D3 ] = "d3",
+ [ TT_D4 ] = "d4",
+ [ TT_D5 ] = "d5",
+ [ TT_D6 ] = "d6",
+ [ TT_D7 ] = "d7",
+
+ /* V<n> registers */
+ [ TT_V0 ] = "v0",
+ [ TT_V1 ] = "v1",
+ [ TT_V2 ] = "v2",
+ [ TT_V3 ] = "v3",
+ [ TT_V4 ] = "v4",
+ [ TT_V5 ] = "v5",
+ [ TT_V6 ] = "v6",
+ [ TT_V7 ] = "v7",
+};
+
+static int
+parse_reg(struct oasm_state *state, struct oasm_token *tok)
+{
+ const char *p;
+
+ /* Valid instructions that go with regs */
+ switch (state->last) {
+ case TT_MOV:
+ case TT_DEC:
+ case TT_INC:
+ case TT_ADD:
+ case TT_SUB:
+ case TT_MUL:
+ case TT_DIV:
+ case TT_BR:
+ case TT_AND:
+ case TT_OR:
+ case TT_XOR:
+ case TT_LSR:
+ case TT_LSL:
+ state->last = tok->type;
+ break;
+ default:
+ if (tok_is_mro(state->last)) {
+ break;
+ }
+
+ p = tokstr[state->last];
+ oasm_err("bad token '%s' for regop\n", p);
+ return -1;
+ }
+
+ if (!tok_is_xreg(tok->type)) {
+ p = tokstr[tok->type];
+ oasm_err("bad register \"%s\"\n", p);
+ return -1;
+ }
+
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ return 0;
+}
+
+static int
+parse_tok(struct oasm_state *state, struct oasm_token *tok)
+{
+ const char *p;
+ int error;
+
+ switch (tok->type) {
+ case TT_NOP:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_BR:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_LABEL:
+ state->last = tok->type;
+ label_enter(tok->raw, state->pip);
+ break;
+ case TT_AND:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_OR:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_XOR:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_HLT:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_MUL:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_DIV:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_LSR:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_LSL:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_MOV:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_ADD:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_SUB:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_DEC:
+ case TT_INC:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_IMM:
+ p = tokstr[state->last];
+ if (!tok_is_xreg(state->last)) {
+ oasm_err("expected X<n> but got %s\n", p);
+ return -1;
+ }
+ emit_osmx64(&emit_state, tok);
+ break;
+ default:
+ if (tok_is_mro(tok->type)) {
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ return 0;
+ }
+
+ if (!tok->is_reg) {
+ oasm_err("syntax error\n");
+ return -1;
+ }
+
+ error = parse_reg(state, tok);
+ if (error < 0) {
+ return error;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void
+parse_enter(struct oasm_state *state)
+{
+ struct oasm_token tok;
+ const char *type, *raw;
+ int error = 0;
+
+ emit_init(&emit_state);
+
+ for (;;) {
+ error = lex_tok(state, &tok);
+ if (error < 0) {
+ break;
+ }
+
+ if (parse_tok(state, &tok) < 0) {
+ break;
+ }
+
+ type = tokstr[tok.type];
+ raw = tok.raw;
+ oasm_debug("got token type %s (%s)\n", type, raw);
+ }
+
+ /* Process then destroy the emit state */
+ emit_process(state, &emit_state);
+ emit_destroy(&emit_state);
+ labels_destroy();
+}
diff --git a/usr.bin/oemu/Makefile b/usr.bin/oemu/Makefile
new file mode 100644
index 0000000..366208c
--- /dev/null
+++ b/usr.bin/oemu/Makefile
@@ -0,0 +1,7 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+CFLAGS = -Iinclude/
+
+$(ROOT)/base/usr/bin/oemu:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS) $(CFLAGS)
diff --git a/usr.bin/oemu/cpu.c b/usr.bin/oemu/cpu.c
new file mode 100644
index 0000000..de8b465
--- /dev/null
+++ b/usr.bin/oemu/cpu.c
@@ -0,0 +1,523 @@
+/*
+ * 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/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <oemu/cpu.h>
+#include <oemu/types.h>
+#include <oemu/osmx64.h>
+
+/*
+ * Return true if the instruction is an
+ * MRO type instruction.
+ */
+static bool
+cpu_is_mro(inst_t *inst)
+{
+ switch (inst->opcode) {
+ case INST_MROB:
+ case INST_MROW:
+ case INST_MROD:
+ case INST_MROQ:
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Decode the INST_MOV_IMM instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_mov_imm(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'mov'\n");
+ return;
+ }
+
+ regs->xreg[inst->rd] = inst->imm;
+ printf("#%d -> x%d\n", inst->imm, inst->rd);
+}
+
+/*
+ * Decode the INST_INC instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_inc(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'mov'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd]++;
+ printf("INC X%d [%x], new=%x\n", inst->rd,
+ imm, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_DEC instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_dec(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'mov'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd]--;
+ printf("DEC X%d [%x], new=%x\n", inst->rd,
+ imm, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_ADD instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_add(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'add'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd];
+ regs->xreg[inst->rd] += inst->imm;
+ printf("%d + %d -> X%d, new=%d\n",
+ imm, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_SUB instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_sub(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'sub'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd];
+ regs->xreg[inst->rd] -= inst->imm;
+ printf("%d - %d -> X%d, new=%d\n",
+ imm, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_MUL instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_mul(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'mul'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd];
+ regs->xreg[inst->rd] *= inst->imm;
+ printf("%d * %d -> X%d, new=%d\n",
+ imm, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+static void
+cpu_and(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'and'\n");
+ return;
+ }
+
+ imm = inst->imm;
+ regs->xreg[inst->rd] &= inst->imm;
+ printf("X%d & %x -> X%d, new=%d\n",
+ inst->rd, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+static void
+cpu_or(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'or'\n");
+ return;
+ }
+
+ imm = inst->imm;
+ regs->xreg[inst->rd] |= imm;
+ printf("X%d | %x -> X%d, new=%d\n",
+ inst->rd, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+static void
+cpu_xor(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'xor'\n");
+ return;
+ }
+
+ imm = inst->imm;
+ regs->xreg[inst->rd] ^= imm;
+ printf("X%d ^ %x -> X%d, new=%d\n",
+ inst->rd, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_DIV instruction
+ *
+ * @cpu: CPU that is executing
+ * @inst: Instruction dword
+ */
+static void
+cpu_div(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'div'\n");
+ return;
+ }
+
+ imm = regs->xreg[inst->rd];
+ if (imm == 0) {
+ /* TODO: Some sort of interrupt */
+ printf("** DIVIDE BY ZERO **\n");
+ return;
+ }
+
+ regs->xreg[inst->rd] /= inst->imm;
+ printf("%d / %d -> X%d, new=%d\n",
+ imm, inst->imm, inst->rd, regs->xreg[inst->rd]);
+}
+
+/*
+ * Decode the INST_DIV instruction
+ */
+static void
+cpu_br(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ imm_t imm;
+ addr_t br_to;
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for 'br'\n");
+ return;
+ }
+
+ /*
+ * If we are branching to the reset vector, might
+ * as well reset all state.
+ */
+ br_to = regs->xreg[inst->rd];
+ if (br_to == 0) {
+ cpu_reset(cpu);
+ }
+
+ regs->ip = br_to;
+}
+
+/*
+ * Decode a logical shift instruction:
+ *
+ * LSR r, r/imm
+ * LSL r, r/imm
+ */
+static void
+cpu_lshift(struct oemu_cpu *cpu, inst_t *inst)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ reg_t reg = inst->rd;
+ imm_t shift = inst->imm;
+
+ switch (inst->opcode) {
+ case INST_LSR:
+ regs->xreg[reg] >>= shift;
+ printf("X%d >> %d -> %d\n", reg, shift, regs->xreg[reg]);
+ break;
+ case INST_LSL:
+ regs->xreg[reg] <<= shift;
+ printf("X%d << %d -> %d\n", reg, shift, regs->xreg[reg]);
+ break;
+ }
+}
+
+/*
+ * Decode MRO type instructions
+ */
+static void
+cpu_mro(struct oemu_cpu *cpu, inst_t *inst)
+{
+ inst_t *next_inst;
+ struct cpu_regs *regs = &cpu->regs;
+ char *inst_str = "bad";
+ uint64_t mask = 0;
+ bool set_mask = false;
+ imm_t imm;
+
+ switch (inst->imm) {
+ case 0: break;
+ case 1:
+ set_mask = true;
+ break;
+ default:
+ imm = inst->imm & 1;
+ if (inst->imm == 1) {
+ set_mask = true;
+ }
+ break;
+ }
+
+ switch (inst->opcode) {
+ case INST_MROB:
+ inst_str = "mrob";
+ if (!set_mask) {
+ break;
+ }
+ mask |= MASK(8);
+ break;
+ case INST_MROW:
+ inst_str = "mrow";
+ if (!set_mask) {
+ break;
+ }
+ mask |= MASK(16);
+ break;
+ case INST_MROD:
+ inst_str = "mrod";
+ if (!set_mask) {
+ break;
+ }
+ mask |= MASK(32);
+ break;
+ case INST_MROQ:
+ inst_str = "mroq";
+ if (!set_mask) {
+ break;
+ }
+ mask |= __UINT64_MAX;
+ break;
+ }
+
+ if (inst->rd > NELEM(regs->xreg)) {
+ printf("bad register operand for '%s'\n", inst_str);
+ return;
+ }
+
+ if (set_mask) {
+ imm = regs->xreg[inst->rd] |= mask;
+ printf("set %x->x%d, new=%x\n", mask, inst->rd, imm);
+ } else {
+ imm = regs->xreg[inst->rd] &= ~mask;
+ printf("cleared %x->x%d, new=%x\n", mask, inst->rd, imm);
+ }
+}
+
+/*
+ * Reset a CPU to a default state
+ */
+void
+cpu_reset(struct oemu_cpu *cpu)
+{
+ struct cpu_regs *regs;
+
+ /*
+ * When an OSMX64 processor first starts up, it will
+ * initially be executing in supervisor mode with all
+ * of its registeres initialized to zeros.
+ */
+ regs = &cpu->regs;
+ regs->ip = 0;
+ regs->sr_state = CPU_SRS_SV;
+ regs->blr = 0x0;
+ regs->ilr = 0x0;
+ memset(regs->xreg, 0x0, sizeof(regs->xreg));
+}
+void
+cpu_regdump(struct oemu_cpu *cpu)
+{
+ struct cpu_regs *regs;
+
+ regs = &cpu->regs;
+ printf(
+ "X0=%p, X1=%p, X2=%p\n"
+ "X3=%p, X4=%p, X5=%p\n"
+ "X6=%p, X7=%p, X8=%p\n"
+ "X9=%p, X10=%p, X11=%p\n"
+ "X12=%p, X13=%p, X14=%p\n"
+ "X15=%p, IP=%p, SRS=%p\n"
+ "BLR=%p, ILR=%p\n",
+ regs->xreg[0], regs->xreg[1],
+ regs->xreg[2], regs->xreg[3],
+ regs->xreg[4], regs->xreg[5],
+ regs->xreg[6], regs->xreg[7],
+ regs->xreg[8], regs->xreg[9],
+ regs->xreg[10], regs->xreg[11],
+ regs->xreg[12], regs->xreg[13],
+ regs->xreg[14], regs->xreg[15],
+ regs->ip, regs->sr_state,
+ regs->blr, regs->ilr
+ );
+}
+
+/*
+ * Main instruction execution loop.
+ */
+void
+cpu_kick(struct oemu_cpu *cpu, struct sysmem *mem)
+{
+ struct cpu_regs *regs = &cpu->regs;
+ inst_t *inst;
+ uint8_t *memp = mem->mem;
+
+ for (;;) {
+ inst = (inst_t *)&memp[regs->ip];
+
+ switch (inst->opcode) {
+ case INST_NOP:
+ /* NOP */
+ regs->ip += sizeof(*inst);
+ continue;
+ case INST_MOV_IMM:
+ cpu_mov_imm(cpu, inst);
+ break;
+ case INST_INC:
+ cpu_inc(cpu, inst);
+ break;
+ case INST_DEC:
+ cpu_dec(cpu, inst);
+ break;
+ case INST_ADD:
+ cpu_add(cpu, inst);
+ break;
+ case INST_SUB:
+ cpu_sub(cpu, inst);
+ break;
+ case INST_MUL:
+ cpu_mul(cpu, inst);
+ break;
+ case INST_DIV:
+ cpu_div(cpu, inst);
+ break;
+ case INST_AND:
+ cpu_and(cpu, inst);
+ break;
+ case INST_OR:
+ cpu_or(cpu, inst);
+ break;
+ case INST_XOR:
+ cpu_xor(cpu, inst);
+ break;
+ case INST_BR:
+ cpu_br(cpu, inst);
+ break;
+ case INST_LSL:
+ case INST_LSR:
+ cpu_lshift(cpu, inst);
+ break;
+ default:
+ if (cpu_is_mro(inst)) {
+ cpu_mro(cpu, inst);
+ }
+ break;
+ }
+
+ /*
+ * X0 is readonly and should always be zero, undo
+ * any writes or side effects from any operations
+ * upon this register.
+ */
+ regs->xreg[0] = 0;
+
+ /* Is this a halt instruction? */
+ if (inst->opcode == INST_HLT) {
+ printf("HALTED\n");
+ break;
+ }
+
+ if (regs->ip >= MEMORY_SIZE) {
+ break;
+ }
+
+ regs->ip += sizeof(*inst);
+ }
+
+ cpu_regdump(cpu);
+}
diff --git a/usr.bin/oemu/emu.c b/usr.bin/oemu/emu.c
new file mode 100644
index 0000000..1b4280b
--- /dev/null
+++ b/usr.bin/oemu/emu.c
@@ -0,0 +1,127 @@
+/*
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <oemu/cpu.h>
+
+static struct oemu_cpu core_0;
+struct sysmem g_mem;
+
+static void
+help(void)
+{
+ printf(
+ "OSMORA OSMX64 Emulator\n"
+ "usage: oemu <binary file>\n"
+ );
+}
+
+/*
+ * Allocate and initialize platform
+ * memory.
+ */
+static int
+mem_init(void)
+{
+ printf("allocating 0x%x bytes of memory\n", MEMORY_SIZE);
+ g_mem.mem_size = MEMORY_SIZE;
+ g_mem.mem = malloc(MEMORY_SIZE);
+ if (g_mem.mem == NULL) {
+ printf("failed to allocate memory\n");
+ return -1;
+ }
+}
+
+/*
+ * Load a program specified by a path into
+ * memory for execution.
+ */
+static int
+program_load(const char *path, paddr_t loadoff)
+{
+ void *mem = g_mem.mem;
+ size_t size;
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ printf("failed to open \"%s\"\n", path);
+ return -ENOENT;
+ }
+
+ /* Grab the size of the file */
+ size = lseek(fd, 0, SEEK_END);
+ lseek(fd, loadoff, SEEK_SET);
+ printf("loading size %d\n", size);
+
+ /* Is it too big? */
+ if (size >= g_mem.mem_size) {
+ printf("program too big !! (memsize=%x)\n", g_mem.mem_size);
+ close(fd);
+ return -1;
+ }
+
+ printf("read data into %p\n", mem);
+ printf("read %d bytes\n", read(fd, mem, size));
+ close(fd);
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 2) {
+ help();
+ return -1;
+ }
+
+ /* Initialize memory */
+ if (mem_init() < 0) {
+ return -1;
+ }
+
+ /* Put the CPU in a known state */
+ cpu_reset(&core_0);
+
+ /*
+ * Load the program and send the little guy off
+ * to start nomming those 32-bit instructions
+ */
+ if (program_load(argv[1], 0x00000000) < 0) {
+ return -1;
+ }
+ cpu_kick(&core_0, &g_mem);
+ free(g_mem.mem);
+ return 0;
+}
diff --git a/usr.bin/oemu/include/oemu/cpu.h b/usr.bin/oemu/include/oemu/cpu.h
new file mode 100644
index 0000000..882fe93
--- /dev/null
+++ b/usr.bin/oemu/include/oemu/cpu.h
@@ -0,0 +1,83 @@
+/*
+ * 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 _OEMU_CPU_H_
+#define _OEMU_CPU_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <oemu/types.h>
+
+#define MEMORY_SIZE 512
+
+/*
+ * Processor state register
+ */
+#define CPU_SRS_SV BIT(1) /* Supervisor flag */
+#define CPU_SRS_CARRY BIT(2) /* Carry flag */
+
+/*
+ * System memory
+ *
+ * @mem: Data
+ * @mem_size: Memory size max
+ */
+struct sysmem {
+ void *mem;
+ size_t mem_size;
+};
+
+/*
+ * CPU register state
+ *
+ * @xreg: X<n>
+ * @ip: Instruction pointer
+ * @sr_state: Processor state register
+ * @blr: Branch link register
+ * @ilr: Interrupt link register
+ */
+struct cpu_regs {
+ reg_t xreg[16];
+ reg_t ip;
+ reg_t sr_state;
+ reg_t blr;
+ reg_t ilr;
+};
+
+struct oemu_cpu {
+ struct cpu_regs regs;
+};
+
+void cpu_regdump(struct oemu_cpu *cpu);
+void cpu_reset(struct oemu_cpu *cpu);
+void cpu_kick(struct oemu_cpu *cpu, struct sysmem *mem);
+
+#endif /* !_OEMU_CPU_H_ */
diff --git a/usr.bin/oemu/include/oemu/osmx64.h b/usr.bin/oemu/include/oemu/osmx64.h
new file mode 100644
index 0000000..1e094d0
--- /dev/null
+++ b/usr.bin/oemu/include/oemu/osmx64.h
@@ -0,0 +1,90 @@
+/*
+ * 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 _OEMU_OSMX64_H_
+#define _OEMU_OSMX64_H_
+
+#include <stdint.h>
+
+/* Opcodes */
+#define INST_NOP 0x00 /* No-operation */
+#define INST_ADD 0x01 /* Add operation */
+#define INST_SUB 0x02 /* Sub operation */
+#define INST_MUL 0x03 /* Multiply operation */
+#define INST_DIV 0x04 /* Divide operation */
+#define INST_INC 0x05 /* Increment operation */
+#define INST_DEC 0x06 /* Decrement operation */
+#define INST_OR 0x07 /* Bitwise OR operation */
+#define INST_XOR 0x08 /* Bitwise XOR operation */
+#define INST_AND 0x09 /* Bitwise AND operation */
+#define INST_NOT 0x0A /* Bitwise NOT operation */
+#define INST_SLL 0x0B /* Shift left logical operation */
+#define INST_SRL 0x0C /* Shift right logical operation */
+#define INST_MOV_IMM 0x0D /* Data move operation from IMM */
+#define INST_HLT 0x0E /* Halt */
+#define INST_BR 0x0F /* Branch */
+#define INST_MROB 0x10 /* Mask register over byte */
+#define INST_MROW 0x11 /* Mask register over word */
+#define INST_MROD 0x12 /* Mask register over dword */
+#define INST_MROQ 0x13 /* Mask register over qword */
+#define INST_LSR 0x14 /* Logical shift right */
+#define INST_LSL 0x15 /* Logical shift left */
+
+/* Registers */
+#define REG_X0 0x00
+#define REG_X1 0x01
+#define REG_X2 0x02
+#define REG_X3 0x03
+#define REG_X4 0x04
+#define REG_X5 0x05
+#define REG_X6 0x06
+#define REG_X7 0x07
+#define REG_X8 0x08
+#define REG_X9 0x09
+#define REG_X10 0x0A
+#define REG_X11 0x0B
+#define REG_X12 0x0C
+#define REG_X13 0x0D
+#define REG_X14 0x0E
+#define REG_X15 0x0F
+#define REG_BAD 0xFF
+
+/*
+ * OSMX64 instruction format
+ */
+typedef struct {
+ uint8_t opcode;
+ uint8_t rd;
+ union {
+ uint16_t imm;
+ uint16_t unused;
+ };
+} inst_t;
+
+#endif /* !_OEMU_OSMX64_H_ */
diff --git a/usr.bin/oemu/include/oemu/types.h b/usr.bin/oemu/include/oemu/types.h
new file mode 100644
index 0000000..caf6e9b
--- /dev/null
+++ b/usr.bin/oemu/include/oemu/types.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _OEMU_TYPES_H_
+#define _OEMU_TYPES_H_
+
+#include <sys/types.h>
+
+typedef uint64_t reg_t;
+typedef uintptr_t addr_t;
+typedef uint16_t imm_t;
+typedef addr_t paddr_t;
+
+#endif /* !_OEMU_TYPES_H_ */
diff --git a/usr.bin/osh/osh.c b/usr.bin/osh/osh.c
index 2f592ad..71ca6de 100644
--- a/usr.bin/osh/osh.c
+++ b/usr.bin/osh/osh.c
@@ -29,63 +29,131 @@
#include <sys/types.h>
#include <sys/cdefs.h>
+#include <sys/errno.h>
+#include <sys/spawn.h>
+#include <sys/wait.h>
#include <fcntl.h>
#include <stddef.h>
+#include <stdbool.h>
#include <unistd.h>
#include <string.h>
+#include <stdio.h>
-#define prcons(FD, STR) write((FD), (STR), strlen((STR)))
+#define is_printable(C) ((C) >= 32 && (C) <= 126)
#define is_ascii(C) ((C) >= 0 && (C) <= 128)
+
+#define INPUT_SIZE 64
+
+#define REPEAT "!!"
+#define COMMENT '@'
#define WELCOME \
":::::::::::::::::::::::::::::::::::::::\n" \
":: OSMORA GATEWAY ~ Every key echos ::\n" \
":: ..... Proceed with purpose ..... ::\n" \
- ":::::::::::::::::::::::::::::::::::::::\n"
+ ":::::::::::::::::::::::::::::::::::::::"
#define HELP \
"Default commands:\n" \
- "help - Display this help message\n" \
- "echo - Print the arguments to the console\n" \
- "exit - Exit the shell\n"
+ "help - Display this help message\n" \
+ "echo - Print the arguments to the console\n" \
+ "reboot - Reboot the machine\n" \
+ "kmsg - Print kernel message buffer\n" \
+ "fetch - System information\n" \
+ "kfg - Start up kfgwm\n" \
+ "bell - Toggle backspace bell\n" \
+ "date - Get the current date\n" \
+ "clear - Clear the screen\n" \
+ "exit - Exit the shell"
-#define PROMPT "[root::osmora]~ "
+#define PROMPT "[%s::%s]~ "
-static char buf[64];
-static uint8_t i;
+static char last_command[INPUT_SIZE];
+static char buf[INPUT_SIZE];
static int running;
+static int bell_fd;
+static bool bs_bell = true; /* Beep on backspace */
-struct command {
+static void cmd_help(int argc, char *argv[]);
+static void cmd_echo(int argc, char *argv[]);
+static void cmd_exit(int argc, char *argv[]);
+static void cmd_bell(int argc, char *argv[]);
+static void cmd_clear(int argc, char *argv[]);
+
+struct builtin_cmd {
const char *name;
- void (*func)(int fd, int argc, char *argv[]);
+ void (*func)(int argc, char *argv[]);
+};
+
+/*
+ * Results after parsing a command
+ *
+ * @bg: Run command in background
+ */
+struct parse_state {
+ uint8_t bg : 1;
};
-void
-cmd_help(int fd, int argc, char *argv[])
+static struct builtin_cmd cmds[] = {
+ {"help",cmd_help},
+ {"exit",cmd_exit},
+ {"bell", cmd_bell},
+ {"clear", cmd_clear},
+ {NULL, NULL}
+};
+
+static void
+cmd_help(int argc, char *argv[])
{
- prcons(fd, HELP);
+ puts(HELP);
}
-void
-cmd_exit(int fd, int argc, char *argv[])
+static void
+cmd_exit(int argc, char *argv[])
{
running = 0;
}
-void
-cmd_echo(int fd, int argc, char *argv[])
+static void
+cmd_clear(int argc, char *argv[])
{
- for (i = 1; i < argc; i++) {
- prcons(fd, argv[i]);
- prcons(fd, " ");
+ fputs("\033[2J", stdout);
+}
+
+static void
+cmd_bell(int argc, char *argv[])
+{
+ const char *usage_str = "usage: bell [on/off]";
+ const char *arg;
+
+ if (argc < 2) {
+ puts(usage_str);
+ return;
+ }
+
+ arg = argv[1];
+ if (strcmp(arg, "on") == 0) {
+ bs_bell = true;
+ } else if (strcmp(arg, "off") == 0) {
+ bs_bell = false;
+ } else {
+ puts(usage_str);
}
- prcons(fd, "\n");
}
-int
-parse_args(char *input, char *argv[], int max_args)
+static int
+parse_args(char *input, char *argv[], int max_args, struct parse_state *p)
{
int argc = 0;
+ /* ignore comments */
+ if (*input == '@') {
+ return 0;
+ }
+
+ /* setup default state */
+ p->bg = 0;
+
+ /* parse loop */
while (*input != '\0') {
/* skip leading spaces */
while (*input == ' ') {
@@ -97,11 +165,26 @@ parse_args(char *input, char *argv[], int max_args)
break;
}
+ /* comment? */
+ if (*input == COMMENT) {
+ break;
+ }
+
+ /* run in background? */
+ if (*input == '&') {
+ p->bg = 1;
+ }
+
if (argc < max_args) {
argv[argc++] = input; /* mark start of the argument */
}
/* move forward until next space or end */
while (*input != '\0' && *input != ' ') {
+ /* ignore comments */
+ if (*input == COMMENT) {
+ return 0;
+ }
+
input++;
}
@@ -115,90 +198,285 @@ parse_args(char *input, char *argv[], int max_args)
return argc;
}
-static char *
-getstr(int fd)
+/*
+ * Grab a string from stdin and return
+ * the resulting offset within the input
+ * buffer we are at.
+ */
+static uint8_t
+getstr(void)
{
char c;
- uint8_t input;
- i = 0;
+ int input;
+ uint32_t beep_payload;
+ uint8_t buf_i = 0;
+
+ /*
+ * Prepare the beep payload @ 500 Hz
+ * for 20ms
+ */
+ beep_payload = 500;
+ beep_payload |= (30 << 16);
for (;;) {
- if (read(fd, &input, 2) <= 0) {
+ if ((input = getchar()) < 0) {
continue;
}
- c = input & 0xFF;
+ c = (char)input;
+ if (c == '\t') {
+ continue;
+ }
/* return on newline */
if (c == '\n') {
- buf[i] = '\0';
- write(fd, "\n", 1);
- return buf;
+ buf[buf_i] = '\0';
+ putchar('\n');
+ return buf_i;
}
/* handle backspaces and DEL */
if (c == '\b' || c == 127) {
- if (i > 0) {
- i--;
- write(fd, "\b \b", 3);
+ if (buf_i > 0) {
+ buf_i--;
+ fputs("\b \b", stdout);
+ } else if (bell_fd > 0 && bs_bell) {
+ write(bell_fd, &beep_payload, sizeof(beep_payload));
}
- } else if (is_ascii(c) && i < sizeof(buf) - 1) {
+ } else if (is_printable(c) && buf_i < sizeof(buf) - 1) {
/* write to fd and add to buffer */
- buf[i++] = c;
- write(fd, &c, 1);
+ buf[buf_i++] = c;
+ putchar(c);
}
}
}
-struct command cmds[] = {
- {"help", cmd_help},
- {"echo", cmd_echo},
- {"exit", cmd_exit},
- {NULL, NULL}
-};
+static void
+builtin_run(struct builtin_cmd *cmd, int argc, char *argv[])
+{
+ if (cmd->func != NULL) {
+ cmd->func(argc, argv);
+ return;
+ }
+}
-int
-main(void)
+static int
+cmd_run(const char *input, int argc, char *argv[])
+{
+ char bin_path[512];
+ char *envp[1] = { NULL };
+ pid_t child;
+
+ /*
+ * If we can access the raw input as a file, try to
+ * spawn it as a program. This case would run if for
+ * example, the user entered /usr/sbin/foo, or some
+ * path directly into the console.
+ */
+ if (access(input, F_OK) == 0) {
+ child = spawn(input, argv, envp, 0);
+ if (child < 0) {
+ return child;
+ }
+ return child;
+ }
+
+ snprintf(bin_path, sizeof(bin_path), "/usr/bin/%s", input);
+
+ /* See if we can access it */
+ if (access(bin_path, F_OK) != 0) {
+ return -1;
+ }
+
+ if ((child = spawn(bin_path, argv, envp, 0)) < 0) {
+ return child;
+ }
+
+ return child;
+}
+
+/*
+ * Match a command with a builtin or binary
+ *
+ * @input: Command input
+ * @argc: Argument count
+ * @argv: Argument vector
+ */
+static int
+command_match(const char *input, int argc, char *argv[])
+{
+ int found = 0;
+ int i;
+ pid_t child = -1;
+
+ for (i = 0; cmds[i].name != NULL; i++) {
+ if (strcmp(input, cmds[i].name) == 0) {
+ builtin_run(&cmds[i], argc, argv);
+ found = 1;
+ }
+ }
+
+ if (found == 0) {
+ if ((child = cmd_run(input, argc, argv)) < 0) {
+ puts("Unrecognized command");
+ return -1;
+ }
+ }
+
+ return child;
+}
+
+static void
+script_skip_comment(int fd)
{
- int fd, found, argc;
- char *input, *argv[16];
char c;
- if ((fd = open("/dev/console", O_RDWR)) < 0) {
- return fd;
+ while (c != '\n') {
+ if (read(fd, &c, 1) <= 0)
+ break;
}
+}
- i = 0;
- running = 1;
- found = 0;
+/*
+ * Parse a single line typed in from the
+ * user.
+ *
+ * @input: Input line
+ */
+static int
+parse_line(char *input)
+{
+ int argc;
+ char *argv[16];
+ struct parse_state state = {0};
+ pid_t child;
- prcons(fd, WELCOME);
- while (running) {
- prcons(fd, PROMPT);
+ /*
+ * If we are using the REPEAT shorthand,
+ * repeat the last command. We return -EAGAIN
+ * to indicate we did not parse a normal command
+ * so the repeat command isn't pushed into the last
+ * command buffer and we enter a recursive hell.
+ */
+ if (strcmp(input, REPEAT) == 0) {
+ parse_line(last_command);
+ return -EAGAIN;
+ }
- input = getstr(fd);
- if (input[0] == '\0') {
+ /* Ensure the aux vector is zeored */
+ memset(argv, 0, sizeof(argv));
+
+ /*
+ * Grab args from the user, there should be
+ * at least one.
+ */
+ argc = parse_args(input, argv, sizeof(argv), &state);
+ if (argc == 0) {
+ return -EAGAIN;
+ }
+
+ child = command_match(input, argc, argv);
+ if (child > 0 && !state.bg) {
+ waitpid(child, NULL, 0);
+ }
+
+ return 0;
+}
+
+static int
+open_script(const char *pathname)
+{
+ int fd, argc, buf_i = 0;
+ char c, *input;
+ char buf[256];
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0) {
+ printf("osh: failed to open %s\n", pathname);
+ return fd;
+ }
+
+ while (read(fd, &c, 1) > 0) {
+ /* Skip comments */
+ if (c == COMMENT) {
+ script_skip_comment(fd);
continue;
}
- argc = parse_args(input, argv, sizeof(argv));
- if (argc == 0) {
+ /* Skip blank newlines */
+ if (c == '\n' && buf_i == 0) {
continue;
}
- for (i = 0; cmds[i].name != NULL; i++) {
- if (strcmp(input, cmds[i].name) == 0) {
- cmds[i].func(fd, argc, argv);
- found = 1;
- break;
- }
+ if (buf_i >= sizeof(buf) - 1) {
+ buf_i = 0;
}
- if (found == 0) {
- prcons(fd, "Unrecognized command\n");
+ if (c == '\n') {
+ buf[buf_i] = '\0';
+ parse_line(buf);
+ buf_i = 0;
+ continue;
+ }
+ buf[buf_i++] = c;
+ }
+
+ return 0;
+}
+
+static void
+dump_file(const char *pathname)
+{
+ FILE *file;
+ char buf[64];
+ int fd;
+
+ file = fopen(pathname, "r");
+ if (file == NULL) {
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), file) != NULL) {
+ printf("%s", buf);
+ }
+
+ fclose(file);
+}
+
+int
+main(int argc, char **argv)
+{
+ int found, prog_argc;
+ int stdout_fd;
+ char hostname[128] = "osmora";
+ uint8_t buf_i;
+ char *p;
+ char c;
+ pid_t child;
+
+ if (argc > 1) {
+ return open_script(argv[1]);
+ }
+
+ running = 1;
+ bell_fd = open("/dev/beep", O_WRONLY);
+ dump_file("/etc/motd");
+ gethostname(hostname, sizeof(hostname));
+
+ while (running) {
+ printf(PROMPT, getlogin(), hostname);
+
+ buf_i = getstr();
+ if (buf[0] == '\0') {
+ continue;
+ }
+
+ buf[buf_i] = '\0';
+ if (parse_line(buf) < 0) {
+ continue;
}
- found = 0;
+ memcpy(last_command, buf, buf_i + 1);
buf[0] = '\0';
}
return 0;
diff --git a/usr.bin/readcore/Makefile b/usr.bin/readcore/Makefile
new file mode 100644
index 0000000..0c18475
--- /dev/null
+++ b/usr.bin/readcore/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/readcore:
+ gcc -Iinclude/ $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/readcore/core.c b/usr.bin/readcore/core.c
new file mode 100644
index 0000000..6871d06
--- /dev/null
+++ b/usr.bin/readcore/core.c
@@ -0,0 +1,50 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include "frame.h"
+#include "core.h"
+
+void
+core_dumpframe(const struct core *core)
+{
+#if defined(__x86_64__)
+ printf(
+ "RDI=%p, RSI=%p\n"
+ "RCX=%p, RDX=%p\n"
+ "RAX=%p, RIP=%p\n",
+ core->frame.rdi, core->frame.rsi,
+ core->frame.rcx, core->frame.rdx,
+ core->frame.rax, core->frame.rip
+ );
+#else
+ printf("core_dumpframe: unsupported arch\n");
+#endif
+}
diff --git a/usr.bin/readcore/crc32.c b/usr.bin/readcore/crc32.c
new file mode 100644
index 0000000..2df49ac
--- /dev/null
+++ b/usr.bin/readcore/crc32.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include "crc32.h"
+
+static const uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+ 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+ 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+ 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+ 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+ 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+ 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+ 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+ 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+ 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+ 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+ 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+ 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+ 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+ 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+ 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+ 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+ 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+uint32_t
+crc32(const void *data, size_t len)
+{
+ const uint8_t *p = data;
+ uint32_t val = 0xFFFFFFFF;
+
+ for (size_t i = 0; i < len; ++i) {
+ val = (val >> 8) ^ crc32_tab[(val ^ p[i]) & 0xFF];
+ }
+
+ return val ^ 0xFFFFFFFF;
+}
diff --git a/usr.bin/readcore/include/core.h b/usr.bin/readcore/include/core.h
new file mode 100644
index 0000000..51105f4
--- /dev/null
+++ b/usr.bin/readcore/include/core.h
@@ -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.
+ */
+
+#ifndef CORE_H_
+#define CORE_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include "frame.h"
+
+struct __packed core {
+ pid_t pid;
+ uintptr_t fault_addr;
+ struct core_frame frame;
+ uint32_t checksum;
+};
+
+#endif /* !CORE_H_ */
diff --git a/usr.bin/readcore/include/crc32.h b/usr.bin/readcore/include/crc32.h
new file mode 100644
index 0000000..a175a30
--- /dev/null
+++ b/usr.bin/readcore/include/crc32.h
@@ -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.
+ */
+
+#ifndef CRC32_H_
+#define CRC32_H_
+
+#include <stdint.h>
+
+uint32_t crc32(const void *data, size_t len);
+
+#endif
diff --git a/usr.bin/readcore/include/frame.h b/usr.bin/readcore/include/frame.h
new file mode 100644
index 0000000..50740fb
--- /dev/null
+++ b/usr.bin/readcore/include/frame.h
@@ -0,0 +1,107 @@
+/*
+ * 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 FRAME_H_
+#define FRAME_H_
+
+#include <sys/types.h>
+
+struct core;
+
+#if defined(__x86_64__)
+struct core_frame {
+ uint64_t trapno;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rbx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t rbp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t error_code;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+};
+#elif defined(__aarch64__)
+struct core_frame {
+ lreg_t x30;
+ lreg_t x29;
+ lreg_t x28;
+ lreg_t x27;
+ lreg_t x26;
+ lreg_t x25;
+ lreg_t x24;
+ lreg_t x23;
+ lreg_t x22;
+ lreg_t x21;
+ lreg_t x20;
+ lreg_t x19;
+ lreg_t x18;
+ lreg_t x17;
+ lreg_t x16;
+ lreg_t x15;
+ lreg_t x14;
+ lreg_t x13;
+ lreg_t x12;
+ lreg_t x11;
+ lreg_t x10;
+ lreg_t x9;
+ lreg_t x8;
+ lreg_t x7;
+ lreg_t x6;
+ lreg_t x5;
+ lreg_t x4;
+ lreg_t x3;
+ lreg_t x2;
+ lreg_t x1;
+ lreg_t x0;
+ lreg_t elr;
+ lreg_t esr;
+ frament_t trapno;
+};
+#else
+struct core_frame {
+ uint64_t data[30];
+};
+#endif
+
+void core_dumpframe(const struct core *core);
+
+#endif /* !FRAME_H_ */
diff --git a/usr.bin/readcore/readcore.c b/usr.bin/readcore/readcore.c
new file mode 100644
index 0000000..9d8b17b
--- /dev/null
+++ b/usr.bin/readcore/readcore.c
@@ -0,0 +1,78 @@
+/*
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "crc32.h"
+#include "frame.h"
+#include "core.h"
+
+static void
+parse_core(const struct core *dump)
+{
+ uint32_t checksum;
+
+ printf("-- CORE DUMP OF PID %d CRASH -- \n", dump->pid);
+ printf("Faulting address: %p\n", dump->fault_addr);
+ core_dumpframe(dump);
+
+ checksum = crc32(dump, sizeof(*dump) - sizeof(checksum));
+ if (checksum != dump->checksum) {
+ printf("!! WARNING: coredump might be corrupt !!\n");
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ struct core core;
+
+ if (argc < 2) {
+ printf("usage: readcore <coredump>\n");
+ return -1;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 2) {
+ printf("readcore: Could not open \"%s\"\n", argv[1]);
+ return fd;
+ }
+
+ if (read(fd, &core, sizeof(core)) < sizeof(core)) {
+ printf("readcore: bad read()\n");
+ return -1;
+ }
+
+ parse_core(&core);
+ close(fd);
+ return 0;
+}
diff --git a/usr.bin/reboot/Makefile b/usr.bin/reboot/Makefile
new file mode 100644
index 0000000..3700676
--- /dev/null
+++ b/usr.bin/reboot/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/reboot:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/reboot/reboot.c b/usr.bin/reboot/reboot.c
new file mode 100644
index 0000000..ac9785a
--- /dev/null
+++ b/usr.bin/reboot/reboot.c
@@ -0,0 +1,87 @@
+/*
+ * 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/reboot.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define REBOOT_FLAGS "rhp"
+#define REBOOT_FLAG_RB 'r' /* Reboot */
+#define REBOOT_FLAG_HLT 'h' /* Halt */
+#define REBOOT_FLAG_PWR 'p' /* Power off */
+
+static void
+help(void)
+{
+ printf(
+ "reboot: usage: reboot [flags]\n"
+ "flags:\n"
+ " [-r] Reboot\n"
+ " [-h] Halt\n"
+ " [-p] Power off\n"
+ );
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+
+ if (argc < 2) {
+ help();
+ return -1;
+ }
+
+ /*
+ * Now we parse the args. Every case is a fall through
+ * as if one fails (indicated by us returning), another
+ * method is attempted.
+ */
+ while ((c = getopt(argc, argv, REBOOT_FLAGS)) != -1) {
+ switch (c) {
+ case REBOOT_FLAG_RB:
+ cpu_reboot(REBOOT_RESET);
+ printf("REBOOT failed\n");
+ /* Fall through */
+ case REBOOT_FLAG_HLT:
+ cpu_reboot(REBOOT_HALT);
+ printf("HALT failed\n");
+ /* Fall through */
+ case REBOOT_FLAG_PWR:
+ cpu_reboot(REBOOT_POWEROFF);
+ printf("POWEROFF failed\n");
+ /* Fall through */
+ default:
+ printf("got bad flag '%c'\n", c);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/usr.bin/screensave/Makefile b/usr.bin/screensave/Makefile
new file mode 100644
index 0000000..a005346
--- /dev/null
+++ b/usr.bin/screensave/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/screensave:
+ gcc $(CFILES) -lgfx -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/screensave/screensave.c b/usr.bin/screensave/screensave.c
new file mode 100644
index 0000000..bb67cde
--- /dev/null
+++ b/usr.bin/screensave/screensave.c
@@ -0,0 +1,116 @@
+/*
+ * 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 <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgfx/draw.h>
+#include <libgfx/gfx.h>
+
+static struct gfx_ctx ctx;
+
+static ssize_t
+rand_bytes(char *buf, size_t len)
+{
+ ssize_t retval;
+ int fd;
+
+ fd = open("/dev/random", O_RDONLY);
+ if (fd < 0) {
+ return fd;
+ }
+
+ if ((retval = read(fd, buf, len)) < 0) {
+ close(fd);
+ return retval;
+ }
+
+ close(fd);
+ return retval;
+}
+
+static void
+screensave(void)
+{
+ size_t n_iter = 0; /* Monotonic */
+ struct timespec ts;
+ char randbuf[2];
+ color_t curpix, nextpix;
+ uint8_t step = 0;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 3000000;
+
+ /* Begin the radiation ::) */
+ for (;;) {
+ rand_bytes(randbuf, sizeof(randbuf));
+ for (size_t i = 0; i < (ctx.fb_size / 4) - 1; i += step + 1) {
+ curpix = ctx.io[i];
+ nextpix = ctx.io[i + 1];
+
+ /* If a multiple of 16, AND, otherwise XOR */
+ if ((n_iter & 15) != 0) {
+ curpix ^= randbuf[0] & 3;
+ nextpix ^= (curpix | (nextpix << 1));
+ nextpix ^= step;
+ } else {
+ curpix &= randbuf[0] & 3;
+ nextpix &= (curpix | (nextpix << 1));
+ nextpix &= step;
+ }
+
+ ctx.io[i] = curpix;
+ ctx.io[i + 1] = nextpix;
+ }
+
+ sleep(&ts, &ts);
+ if ((++step) > 50) {
+ step = 0;
+ }
+ ++n_iter;
+ }
+}
+
+int
+main(void)
+{
+ int error;
+
+ error = gfx_init(&ctx);
+ if (error < 0) {
+ printf("could not init libgfx\n");
+ return error;
+ }
+
+ screensave();
+ gfx_cleanup(&ctx);
+ return 0;
+}
diff --git a/usr.bin/sleep/Makefile b/usr.bin/sleep/Makefile
new file mode 100644
index 0000000..5bfd04f
--- /dev/null
+++ b/usr.bin/sleep/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/sleep:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/sleep/sleep.c b/usr.bin/sleep/sleep.c
new file mode 100644
index 0000000..f7d07f8
--- /dev/null
+++ b/usr.bin/sleep/sleep.c
@@ -0,0 +1,55 @@
+/*
+ * 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 <time.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ struct timespec ts;
+ uint16_t nsec = 0;
+
+ if (argc < 2) {
+ printf("sleep: usage: sleep <seconds>\n");
+ return -1;
+ }
+
+ nsec = atoi(argv[1]);
+ if (nsec == 0) {
+ printf("sleep: bad argument\n");
+ return -1;
+ }
+
+ ts.tv_nsec = 0;
+ ts.tv_sec = nsec;
+ sleep(&ts, &ts);
+ return 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..4a84484
--- /dev/null
+++ b/usr.bin/sysctl/sysctl.c
@@ -0,0 +1,314 @@
+/*
+ * 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"
+
+/* Proc var string constants */
+#define NAME_COUNT "count"
+
+/* Name start string constants */
+#define NAME_KERN "kern"
+#define NAME_HW "hw"
+#define NAME_PROC "proc"
+
+/* Name start int constants */
+#define NAME_DEF_KERN 0
+#define NAME_DEF_HW 1
+#define NAME_DEF_PROC 2
+
+/*
+ * 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;
+ case 'p':
+ if (strcmp(name, NAME_PROC) == 0) {
+ return NAME_DEF_PROC;
+ }
+
+ 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;
+}
+
+/*
+ * Handle parsing of 'proc.*' node names
+ *
+ * @node: Node name to parse
+ * @is_str: Set to true if string
+ */
+static int
+proc_node(const char *node, bool *is_str)
+{
+ switch (*node) {
+ case 'c':
+ if (strcmp(node, NAME_COUNT) == 0) {
+ *is_str = false;
+ return PROC_COUNT;
+ }
+
+ 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);
+ case NAME_DEF_PROC:
+ return proc_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 \"%s\"\n", p);
+ return -1;
+ }
+
+ if ((root = name_to_def(p)) < 0) {
+ printf("sysctl: bad var \"%s\"\n", 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.bin/whoami/Makefile b/usr.bin/whoami/Makefile
new file mode 100644
index 0000000..ced9ae2
--- /dev/null
+++ b/usr.bin/whoami/Makefile
@@ -0,0 +1,6 @@
+include user.mk
+
+CFILES = $(shell find . -name "*.c")
+
+$(ROOT)/base/usr/bin/whoami:
+ gcc $(CFILES) -o $@ $(INTERNAL_CFLAGS)
diff --git a/usr.bin/whoami/whoami.c b/usr.bin/whoami/whoami.c
new file mode 100644
index 0000000..c3adcf0
--- /dev/null
+++ b/usr.bin/whoami/whoami.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 <stdio.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ printf("%s\f\n", getlogin());
+ return 0;
+}