summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/conf/BLACKLIST1
-rw-r--r--sys/kern/kern_subr.c21
-rw-r--r--usr.bin/oasm/emit.c206
-rw-r--r--usr.bin/oasm/include/oasm/emit.h109
-rw-r--r--usr.bin/oasm/include/oasm/lex.h35
-rw-r--r--usr.bin/oasm/lex.c22
-rw-r--r--usr.bin/oasm/oasm.c10
-rw-r--r--usr.bin/oasm/parse.c91
8 files changed, 490 insertions, 5 deletions
diff --git a/sys/conf/BLACKLIST b/sys/conf/BLACKLIST
deleted file mode 100644
index 4eb32d8..0000000
--- a/sys/conf/BLACKLIST
+++ /dev/null
@@ -1 +0,0 @@
-xhci ahci nvme
diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c
index f437ec7..8a08f33 100644
--- a/sys/kern/kern_subr.c
+++ b/sys/kern/kern_subr.c
@@ -29,9 +29,12 @@
#include <sys/proc.h>
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/errno.h>
+#include <sys/mman.h>
#include <sys/exec.h>
#include <sys/systm.h>
+#include <vm/vm.h>
#include <string.h>
/*
@@ -45,6 +48,8 @@ static bool
check_uaddr(const void *uaddr)
{
vaddr_t stack_start, stack_end;
+ struct mmap_lgdr *lp;
+ struct mmap_entry find, *res;
struct exec_prog exec;
struct proc *td;
uintptr_t addr;
@@ -61,6 +66,22 @@ check_uaddr(const void *uaddr)
if (addr >= stack_start && addr <= stack_end)
return true;
+ /* Try to grab the mmap ledger */
+ if ((lp = td->mlgdr) == NULL) {
+ return false;
+ }
+
+ /*
+ * Now give an attempt at looking through the
+ * mmap ledger. Perhaps this memory was allocated
+ * in the user heap?
+ */
+ find.va_start = ALIGN_DOWN(addr, DEFAULT_PAGESIZE);
+ res = RBT_FIND(lgdr_entries, &lp->hd, &find);
+ if (res != NULL) {
+ return true;
+ }
+
return false;
}
diff --git a/usr.bin/oasm/emit.c b/usr.bin/oasm/emit.c
new file mode 100644
index 0000000..0275d05
--- /dev/null
+++ b/usr.bin/oasm/emit.c
@@ -0,0 +1,206 @@
+/*
+ * 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 'move' 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);
+}
+
+int
+emit_osxm64(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;
+ TAILQ_FOREACH(curtok, &emit->ir, link) {
+ switch (curtok->type) {
+ case TT_MOV:
+ curtok = emit_encode_mov(emit, curtok);
+ break;
+ }
+
+ if (curtok == NULL) {
+ 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..e4ed83c
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/emit.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _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 0x10 /* Bitwise NOT operation */
+#define OSMX64_SLL 0x11 /* Shift left logical operation */
+#define OSMX64_SRL 0x12 /* Shift right logical operation */
+#define OSMX64_MOV_IMM 0x13 /* Data move operation from IMM */
+
+/*
+ * 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;
+ uint16_t imm;
+} 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_osxm64(struct emit_state *state, struct oasm_token *tp);
+
+#endif /* !_EMIT_H_ */
diff --git a/usr.bin/oasm/include/oasm/lex.h b/usr.bin/oasm/include/oasm/lex.h
index 9e293e6..28ad52c 100644
--- a/usr.bin/oasm/include/oasm/lex.h
+++ b/usr.bin/oasm/include/oasm/lex.h
@@ -30,6 +30,8 @@
#ifndef _OASM_LEX_H_
#define _OASM_LEX_H_
+#include <sys/queue.h>
+#include <sys/cdefs.h>
#include <stdint.h>
struct oasm_state;
@@ -113,9 +115,42 @@ typedef enum {
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;
+}
+
#endif /* !_OASM_LEX_H_ */
diff --git a/usr.bin/oasm/lex.c b/usr.bin/oasm/lex.c
index afbe21d..f8427e0 100644
--- a/usr.bin/oasm/lex.c
+++ b/usr.bin/oasm/lex.c
@@ -29,6 +29,7 @@
#include <sys/errno.h>
#include <string.h>
+#include <stdlib.h>
#include <oasm/state.h>
#include <oasm/lex.h>
#include <oasm/log.h>
@@ -66,6 +67,20 @@ lex_skippable(struct oasm_state *state, char c)
}
/*
+ * 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
@@ -231,7 +246,7 @@ token_reg(char *p)
int
lex_tok(struct oasm_state *state, struct oasm_token *ttp)
{
- char *p;
+ char *p = NULL;
char c = ' ';
int tmp;
tt_t tok;
@@ -282,11 +297,16 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
/* 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;
}
diff --git a/usr.bin/oasm/oasm.c b/usr.bin/oasm/oasm.c
index 844f004..6c37778 100644
--- a/usr.bin/oasm/oasm.c
+++ b/usr.bin/oasm/oasm.c
@@ -47,7 +47,7 @@ oasm_start(struct oasm_state *state)
int
main(int argc, char **argv)
{
- if (argc < 2) {
+ if (argc < 3) {
printf("oasm: usage: oasm <file> <output>\n");
return -1;
}
@@ -58,8 +58,16 @@ main(int argc, char **argv)
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
index 7c5b94c..88b5506 100644
--- a/usr.bin/oasm/parse.c
+++ b/usr.bin/oasm/parse.c
@@ -29,11 +29,13 @@
#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>
+static struct emit_state emit_state;
static const char *tokstr[] = {
[ TT_UNKNOWN] = "bad",
[ TT_ADD ] = "add",
@@ -95,20 +97,105 @@ static const char *tokstr[] = {
[ 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:
+ state->last = tok->type;
+ break;
+ default:
+ p = tokstr[state->last];
+ oasm_err("bad instruction '%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_osxm64(&emit_state, tok);
+ return 0;
+}
+
+static int
+parse_imm(struct oasm_token *tok, tt_t last)
+{
+ return 0;
+}
+
+static int
+parse_tok(struct oasm_state *state, struct oasm_token *tok)
+{
+ const char *p;
+ int error;
+
+ switch (tok->type) {
+ case TT_MOV:
+ state->last = tok->type;
+ emit_osxm64(&emit_state, tok);
+ break;
+ case TT_DEC:
+ state->last = tok->type;
+ emit_osxm64(&emit_state, tok);
+ break;
+ case TT_IMM:
+ p = tokstr[state->last];
+ if (!tok_is_xreg(state->last)) {
+ printf("expected X<n> but got %s\n", p);
+ return -1;
+ }
+ emit_osxm64(&emit_state, tok);
+ break;
+ default:
+ 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 (tok.raw != NULL) {
- free(tok.raw);
+ 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);
}