diff options
Diffstat (limited to 'usr.bin')
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; +} |