diff --git a/Makefile b/Makefile index c253f50..aa3ab02 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ all: kas kpc: + @rm -f vm/a.out @cd vm && make --no-print-directory kas: kpc as/k-as.py as/regs.lst diff --git a/as/k-as.py b/as/k-as.py index dda27ad..4ebd1ce 100755 --- a/as/k-as.py +++ b/as/k-as.py @@ -233,6 +233,24 @@ def parse_preproc(line): assert(written == 8) pdata += written + # buffer / bss + elif tok[2][0] == '[': + assert(tok[2][-1] == ']') + + s = tok[2][1:-1].strip() + if not is_number(s): + print("Invalid bss format: {}".format(line)) + leave() + sys.exit(1) + + i = int(s, base=0) + i = i + (8 - i % 8) + written = b_data.write(bytearray(i)) + assert(written == i) + + pdefs[label + "_len"] = s + pdata += written + # string data elif tok[2][0] in "'\"": s = tok[2].strip() diff --git a/ka/main.k b/ka/main.k index c912194..669d5be 100644 --- a/ka/main.k +++ b/ka/main.k @@ -7,10 +7,20 @@ main: enter + mov ax0, .buf + devctl 0, 1 + mov ax0, .buf call print - prn 10 + leave + ret + +.buf = [32] + +test: + enter + mov ax0, .msg call print @@ -28,13 +38,11 @@ main: mov ax1, .msg call strcmp - movt rax, rbx - leave ret .msg = "HelloWorld :)" -.buf = "!!!!!!!!!!!!!" +.buf = [32] ; ; Exit function diff --git a/vm/Makefile b/vm/Makefile index 551f60e..5bcada7 100644 --- a/vm/Makefile +++ b/vm/Makefile @@ -6,26 +6,30 @@ all: k.exe .PHONY: clean .INTERMEDIATE: %.o +dv_src = $(shell ls dv/*.c) in_src = $(shell ls in/*.c) pc_src = $(shell ls pc/*.c) -obj = pc/disd.o $(patsubst %.c,%.o,$(pc_src)) $(patsubst %.c,%.o,$(in_src)) +obj = pc/disd.o +obj += $(patsubst %.c,%.o,$(dv_src)) +obj += $(patsubst %.c,%.o,$(in_src)) +obj += $(patsubst %.c,%.o,$(pc_src)) FLAGS=-O2 -g -Wall -fno-builtin-log -I. -pc/disd.o: i_arch.h */*.h pc/decd.c +pc/disd.o: in/i_arch.h */*.h pc/decd.c @cc $(FLAGS) -D_NEED_DISASM -c pc/decd.c -o $@ -%.o: %.c i_arch.h */*.h $(src) +%.o: %.c in/i_arch.h */*.h $(src) @cc $(FLAGS) -c $< -o $@ -i_arch.h: in/INSTRS in/arch_i.py +in/i_arch.h: in/INSTRS in/arch_i.py @cd in && python3 arch_i.py clean: @rm -f */*.o in/arch_i.h -k.exe: i_arch.h $(obj) +k.exe: in/i_arch.h $(obj) @gcc -O2 -Wall $(obj) -o k.exe @rm in/arch_i.h @rm -f */*.o diff --git a/vm/dv/DEVAPI b/vm/dv/DEVAPI new file mode 100644 index 0000000..4e3866e --- /dev/null +++ b/vm/dv/DEVAPI @@ -0,0 +1,39 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +To communicate with devices, use: + devctl #dev #slot + iocall #dev #slot + +This will call a function from the device's slot table. +It will take registers ax0-ax7 as its parameters, and +return a value in rdx:rax. + +The return value in rax is a status value: + ≥0 ok (>0 only if meaningful) + -1 unspecified error + -2 no such device + -3 device powered off + -4 device fatal error + -5 device not plugged + -6 no such function slot + -7 slot not implemented + -8 slot reserved + -9 invalid parameters + -10 to -256 (reserved) + < -256 (left to device) + +The slots for "devctl" are architecture-rerserved. +They consist of the following functions: + Slot Param (ax0) Description + 0 ptr Write device type into buffer + 1 ptr Write device name into buffer + 2 ptr Write device model into buffer + 3 ptr Write device vendor into buffer + 4 rax=major, rdx=minor + 5 rax=feats, rdx=revis + 6-31 (reserved) + +The slots for "iocall" are device-defined. (They correspond +to the "fslots" array of the dev_t structure.) See that +particular device's documentation (if any). diff --git a/vm/dv/cpu.c b/vm/dv/cpu.c new file mode 100644 index 0000000..1e39869 --- /dev/null +++ b/vm/dv/cpu.c @@ -0,0 +1,17 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +dev_t cpudev = +{ + .type = "cpu", + .name = "K-CPU", + .modl = "K-CPU", + .vend = "The OS/K Team", + + .major = 0, + .minor = 1, + .revis = 0, +}; + diff --git a/vm/dv/dev.c b/vm/dv/dev.c new file mode 100644 index 0000000..7e15799 --- /dev/null +++ b/vm/dv/dev.c @@ -0,0 +1,128 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +static_assert(sizeof(dev_t) % 8 == 0, ""); + +dev_t *devalloc(void) +{ + return calloc(sizeof(dev_t)/sizeof(ulong), sizeof(ulong)); +} + +void devfree(dev_t *dev) +{ + assert(dev != NULL); + + free(dev); +} + +dev_t *devget(ctx_t *ctx, int idx) +{ + if (idx < 0) + return NULL; + + int i; + dev_t *dev; + + for (i = 0, dev = ctx->dh; dev && i != idx; dev = dev->next, i++); + + return dev; +} + +void devattach(ctx_t *ctx, dev_t *dev) +{ + dev_t *it; + + assert(dev != NULL); + + if (ctx->dh) { + for (it = ctx->dh; it->next != NULL; it = it->next); + + it->next = dev; + } + + else ctx->dh = dev; +} + +int devinit(ctx_t *ctx, dev_t *dev) +{ + if (!dev || dev->state != DEVPWOF) + return -1; + + if (dev->fpwon) + dev->fpwon(ctx, dev); + + else dev->state = DEVGOOD; + + if (!(dev->state == DEVPLUG || dev->state == DEVGOOD)) + return -1; + + dev->id = random(); + + devattach(ctx, dev); + + return 0; +} + +// NEVER detach while some assembly code +// may still be running on the vm! +void devdetach(ctx_t *ctx, dev_t *dev) +{ + dev_t *it; + + assert(dev != NULL); + + if (dev == ctx->dh) { + ctx->dh = dev->next; + } + + for (it = ctx->dh; it; it = it->next) { + if (!it) + break; + + if (it->next == dev) { + it->next = dev->next; + break; + } + } +} + +int devfini(ctx_t *ctx, dev_t *dev) +{ + if (dev->state == DEVPWOF || dev->state == DEVFERR) { + goto err; + } + + if (dev->fpwoff) + dev->fpwoff(ctx, dev); + + else dev->state = DEVPWOF; + + if (dev->state != DEVPWOF) + goto err; + + devdetach(ctx, dev); + return 0; + +err: + devdetach(ctx, dev); + return -1; +} + +int devinitall(ctx_t *ctx) +{ + return devinit(ctx, &cpudev); +} + +int devfiniall(ctx_t *ctx) +{ + int failed = 0; + + while (ctx->dh) + if (devfini(ctx, ctx->dh) < 0) + failed = -1; + + return failed; +} + diff --git a/vm/dv/dev.h b/vm/dv/dev.h new file mode 100644 index 0000000..db6e76f --- /dev/null +++ b/vm/dv/dev.h @@ -0,0 +1,61 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +#define DEVLEN 32 +#define DEVSLOTS 256 + +typedef void (*devfn_t)(ctx_t *, dev_t *); + +enum +{ + DEVPWOF, // Power off + DEVPLUG, // Unplugged or plugging + DEVGOOD, // Plugged and working + DEVFERR, // Fatal error +}; + +struct dev_t +{ + dev_t *next; + + char type[DEVLEN]; + char name[DEVLEN]; + char modl[DEVLEN]; + char vend[DEVLEN]; + + int major; + int minor; + int revis; + ulong feats; + + long id; + uint state; + void *data; + + devfn_t fpwon; + devfn_t fpwoff; + + devfn_t fplug; + devfn_t funplug; + + devfn_t fslots[DEVSLOTS]; +}; + +dev_t *devalloc(void); +void devfree(dev_t *); + +dev_t *devget(ctx_t *, int); + +void devattach(ctx_t *, dev_t *); +void devdetach(ctx_t *, dev_t *); + +int devinit(ctx_t *, dev_t *); +int devfini(ctx_t *, dev_t *); + +int devinitall(ctx_t *); +int devfiniall(ctx_t *); + +extern dev_t cpudev; + diff --git a/vm/dv/devctl.c b/vm/dv/devctl.c new file mode 100644 index 0000000..89cca7b --- /dev/null +++ b/vm/dv/devctl.c @@ -0,0 +1,90 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include + +// +// code common to devctl and iocall +// +dev_t *devctl_common(ctx_t *ctx, ulong v1, ulong v2) +{ + + dev_t *dev = devget(ctx, v1); + + if (!dev) + rax = -2; + + else if (dev->state == DEVPWOF) + rax = -3; + + else if (dev->state == DEVFERR) + rax = -4; + + else if (dev->state == DEVPLUG) + rax = -5; + + else + return dev; + + return NULL; +} + +void copystr(ctx_t *ctx, ulong addr, ulong maxn, char *str) +{ + for (; *str && maxn > 0; str++, addr++, maxn--) { + writemem8(ctx, *str, addr); + } + + writemem8(ctx, 0, addr); +} + +IMPL_START_2(devctl) +{ + CHK_SUPERV(); + + dev_t *dev = devctl_common(ctx, v1, v2); + + if (dev == NULL) + return; + + switch (v2) { + case 0: + copystr(ctx, ax0, DEVLEN, dev->type); + break; + + case 1: + copystr(ctx, ax0, DEVLEN, dev->name); + break; + + case 2: + copystr(ctx, ax0, DEVLEN, dev->modl); + break; + + case 3: + copystr(ctx, ax0, DEVLEN, dev->vend); + break; + + case 4: + rax = dev->major; + rdx = dev->minor; + break; + + case 5: + rax = dev->feats; + rdx = dev->revis; + break; + + default: + rax = -6; + break; + } +} +IMPL_END; + +IMPL_START_2(iocall) +{ + CHK_SUPERV(); +} +IMPL_END; + diff --git a/vm/in/INSTRS b/vm/in/INSTRS index 306e2c6..3754c53 100644 --- a/vm/in/INSTRS +++ b/vm/in/INSTRS @@ -177,6 +177,9 @@ popf cli sti +devctl rim rim +iocall rim rim + # # Misc. instructions # diff --git a/vm/pc/arch.h b/vm/pc/arch.h index d46c709..288a759 100644 --- a/vm/pc/arch.h +++ b/vm/pc/arch.h @@ -1,6 +1,11 @@ // The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#ifndef _ARCH_H +#define _ARCH_H + +#define dev_t stddev_t + #include #include #include @@ -8,6 +13,7 @@ #include #include +#undef dev_t #define packed __attribute__ ((__packed__)) #define static_assert _Static_assert #define alignof _Alignof @@ -23,6 +29,7 @@ typedef struct ctx_t ctx_t; typedef struct instr_t instr_t; typedef struct acc_t acc_t; typedef struct arch_t arch_t; +typedef struct dev_t dev_t; void log(const char *, ...); void vlog(const char *, va_list); @@ -101,6 +108,9 @@ struct ctx_t // For disassembly FILE *disf; + + // Devices list head + dev_t *dh; }; #define R(X) ctx->r[X].val @@ -160,3 +170,5 @@ void writemem(ctx_t *, ulong val, ulong addr, uint len); extern reg_t arch_r[NREGS]; extern instr_t arch_i[NINSTRS]; +#endif + diff --git a/vm/pc/except.c b/vm/pc/except.c index 0472da1..0cae9f2 100644 --- a/vm/pc/except.c +++ b/vm/pc/except.c @@ -1,7 +1,7 @@ // The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include +#include void _except(ctx_t *ctx, int code, char *fmt, ...) { @@ -22,6 +22,12 @@ void _except(ctx_t *ctx, int code, char *fmt, ...) if (ctx->mp) free(ctx->mp); + + if (devfiniall(ctx) < 0) { + log("Couldn't deinitialize devices\n"); + exit(-100 - code); + } + exit(code); } diff --git a/vm/pc/main.c b/vm/pc/main.c index 4f0a4be..2a2fe4a 100644 --- a/vm/pc/main.c +++ b/vm/pc/main.c @@ -1,7 +1,8 @@ // The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include +#include +#include #define FWPROGSIZE (1024 * 1024 * 1024) static ssize_t fwsize; @@ -40,11 +41,17 @@ ushort dget(ctx_t *ctx) return fwprog[i++]; } +ctx_t main_ctx; + int main(int argc, char **argv) { - ctx_t main_ctx; FILE *fwfile; + struct timeval time; + + gettimeofday(&time, NULL); + srandom((time.tv_sec * 1000) + (time.tv_usec / 1000)); + main_ctx.r = arch_r; main_ctx.i = arch_i; @@ -91,6 +98,12 @@ int main(int argc, char **argv) memcpy(&main_ctx.mp[addr2real(main_ctx.r[RIP].val)], fwprog, fwsize); + main_ctx.dh = 0; + if (devinitall(&main_ctx) < 0) { + log("Couldn't initialize devices\n"); + exit(-10); + } + while (1) { decode(&main_ctx); } diff --git a/vm/pc/regs.h b/vm/pc/regs.h index f474f95..08467a5 100644 --- a/vm/pc/regs.h +++ b/vm/pc/regs.h @@ -24,9 +24,26 @@ enum NX0, NX1, NX2, NX3, NX4, NX5, NX6, NX7, +#define nx0 R(NX0) +#define nx1 R(NX1) +#define nx2 R(NX2) +#define nx3 R(NX3) +#define nx4 R(NX4) +#define nx5 R(NX5) +#define nx6 R(NX6) +#define nx7 R(NX7) AX0, AX1, AX2, AX3, AX4, AX5, AX6, AX7, +#define ax0 R(AX0) +#define ax1 R(AX1) +#define ax2 R(AX2) +#define ax3 R(AX3) +#define ax4 R(AX4) +#define ax5 R(AX5) +#define ax6 R(AX6) +#define ax7 R(AX7) + CR0, CR1, CR2, CR3, CR4, CR5, CR6, CR7, @@ -34,9 +51,21 @@ enum #define cr1 R(CR1) #define cr2 R(CR2) #define cr3 R(CR3) +#define cr4 R(CR4) +#define cr5 R(CR5) +#define cr6 R(CR6) +#define cr7 R(CR7) SA0, SA1, SA2, SA3, SA4, SA5, SA6, SA7, +#define sa0 R(SA0) +#define sa1 R(SA1) +#define sa2 R(SA2) +#define sa3 R(SA3) +#define sa4 R(SA4) +#define sa5 R(SA5) +#define sa6 R(SA6) +#define sa7 R(SA7) NREGS };