diff options
Diffstat (limited to 'pu2/pu2.c')
| -rw-r--r-- | pu2/pu2.c | 407 |
1 files changed, 334 insertions, 73 deletions
@@ -2,6 +2,7 @@ #include "pu2.out.c" // #include <errno.h> +#include <libgen.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -9,7 +10,11 @@ #include <time.h> #include <unistd.h> -typedef char *string; +typedef char *string; +typedef unsigned char byte; +typedef byte bool; +const bool true = 1; +const bool false = 0; string read_file(string path, int *out_size) { FILE *f = fopen(path, "rb"); @@ -96,12 +101,42 @@ long powi(long x, unsigned n) { return p == 0 ? 0 : r; } -emu() { +typedef struct { + int pid; + int ring_level; + int *memory; + int mem_size; + + struct { + bool spawn_process : 1; + bool make_syscall : 1; + } permissions; +} emu_process; + +#define pid_count 512 +emu_process processes[ pid_count ]; // maximum process count +bool process_occupied[ pid_count ]; + +struct emu_return { + bool time_finished; + int e_code; +} emu(int time_slice, int pid) { + process_occupied[ pid ] = true; + emu_process process = processes[ pid ]; + int *m = process.memory; + while (1) { - pu2(); - int e_code = m[ 0 ]; + int remaining_time = pu2(time_slice, m, process.mem_size); + int e_code = m[ 0 ]; - if (e_code != 2) return e_code; + if (remaining_time <= 0 && time_slice != -1) { + // process_occupied[ pid ] = false; + return (struct emu_return) { true, e_code }; + } + if (e_code != 2) { + process_occupied[ pid ] = false; + return (struct emu_return) { false, e_code }; + } // handle hardware interrupts int int_code = m[ 1 ]; @@ -144,7 +179,7 @@ emu() { m[ 3 ] = val1 >> val2; } else if (op == 5) { // pow - if (val1 == 2) m[ 3 ] = val1 << val2; + if (val1 == 2) m[ 3 ] = 1 << val2; else { m[ 3 ] = powi(val1, val2); } } @@ -154,12 +189,147 @@ emu() { } } + // permission features + else if (int_code == 3) { + int op = m[ 2 ]; + + if (op == 0) { + // spawn process + int target_ring = m[ 10 ]; + int memory_start = m[ 11 ]; + int memory_length = m[ 12 ]; + int can_spawn_processes = m[ 13 ]; + int can_make_syscalls = m[ 14 ]; + int max_time_limit = m[ 15 ]; + + if (target_ring < process.ring_level) { + // error - process cannot spawn a process on a lower ring level + m[ 2 ] = 2; + goto HAD_ERROR; + } + + if ((can_spawn_processes && !(process.permissions.spawn_process & 0b1)) + || (can_make_syscalls && !(process.permissions.make_syscall & 0b1))) { + // error - host process cannot elevate permissions of the spawning process + m[ 2 ] = 3; + goto HAD_ERROR; + } + + int new_pid = 0; + + for (new_pid = 0; new_pid < pid_count; new_pid++) { + if (!process_occupied[ new_pid ]) goto FOUND; + } + + // error - process pool exhausted + m[ 2 ] = 2; + goto HAD_ERROR; + + FOUND:; + + int *new_process_memory = calloc(memory_length, sizeof(int)); + + process_occupied[ new_pid ] = true; + processes[ new_pid ] + = (emu_process) { .pid = new_pid, + .ring_level = target_ring, + .memory = new_process_memory, + .mem_size = memory_length, + .permissions = { .make_syscall = !!can_make_syscalls, + .spawn_process = !!can_spawn_processes } }; + + // copy memory + memcpy(new_process_memory, m + memory_start, memory_length * sizeof(int)); + + // run process + struct emu_return result = emu(max_time_limit, new_pid); + + // store results + m[ 2 ] = 0; + m[ 3 ] = new_pid; + m[ 4 ] = result.e_code; + m[ 5 ] = result.time_finished; + } else if (op == 1) { + // resume process pid (if it's halted) + int process_pid = m[ 10 ]; + int max_time_limit = m[ 11 ]; + + if (!process_occupied[ process_pid ]) { + // error - process is not running, start/initialize it first + m[ 2 ] = 2; + goto HAD_ERROR; + } + + if (processes[ process_pid ].ring_level < processes[ pid ].ring_level) { + // error - cannot interact with higher-privileged process + m[ 2 ] = 3; + goto HAD_ERROR; + } + + // run process + struct emu_return result = emu(max_time_limit, process_pid); + + // store results + m[ 2 ] = 0; + m[ 3 ] = result.e_code; + m[ 4 ] = result.time_finished; + } else if (op == 2) { + // read memory from another process + int process_pid = m[ 10 ]; + int memory_address = m[ 11 ]; + int read_length = m[ 12 ]; + int target_location = m[ 13 ]; + + if (processes[ process_pid ].ring_level < processes[ pid ].ring_level + || processes[ pid ].ring_level > 3) { + // error - cannot interact with higher-privileged process + m[ 2 ] = 2; + goto HAD_ERROR; + } + + // copy information + int *memory = processes[ process_pid ].memory; + memcpy(m + target_location, memory + memory_address, read_length * sizeof(int)); + + // done! + m[ 2 ] = 0; + } else if (op == 3) { + // write memory to target process + int process_pid = m[ 10 ]; + int memory_address = m[ 11 ]; + int write_length = m[ 12 ]; + int target_location = m[ 13 ]; + + if (processes[ process_pid ].ring_level < processes[ pid ].ring_level + || processes[ pid ].ring_level > 3) { + // error - cannot interact with higher-privileged process + m[ 2 ] = 2; + goto HAD_ERROR; + } + + // write information + int *memory = processes[ process_pid ].memory; + memcpy(memory + memory_address, m + target_location, write_length * sizeof(int)); + + // done! + m[ 2 ] = 0; + } + + else { + // unknown op, set m[2] + m[ 2 ] = 1; + } + } + else { // unknown interrupt. what to do? } + HAD_ERROR: m[ 0 ] = 0; } + + process_occupied[ pid ] = false; } skip_space(string *I) { @@ -175,11 +345,6 @@ struct { }; // clang-format on -typedef unsigned char byte; -typedef byte bool; -const bool true = 1; -const bool false = 0; - // use this instead of strdup'ing and allocating extra storage! typedef struct { int len; @@ -258,11 +423,11 @@ clean_slice_ref(slice_t *val) { free(val->ref); } } \ I++; \ str_len++; \ - int *dest_start = Data -= str_len; \ + int *dest_start = Data -= str_len + 1; \ int y; \ for (y = 0; y < str_len - 1; y++) { dest_start[ y ] = str_start[ y ]; } \ Data[ -1 ] = 0; \ - value = Data - m; \ + value = Data - assembly_target; \ } else if (*I == '&') { \ I++; \ string starting_I = I; \ @@ -299,6 +464,8 @@ clean_slice_ref(slice_t *val) { free(val->ref); } #define imm_in_mem(__mem, __imm) (imm(__mem), emit(opcode.cb3, __imm)) #define mov_mem_mem(__mem1, __mem2) (imm(__mem1), emit(opcode.cb4, __mem2)) #define mem_in_a(__mem) emit(opcode.cb2, __mem) +#define a_in_mem(__mem) emit(opcode.cb1, __mem) +#define deref_a() (op(b2u), swap(), load(), op(u2b)) #define perform_op(operation) \ ({ \ mem_in_a(mem2_index); \ @@ -315,9 +482,9 @@ string ERR_code; int *Code; int *Data; -init_ir2() { - Code = &m[ 4000 ]; - Data = &m[ S - 1 ]; // grows downwards +init_ir2(int *target_mem, int max_size) { + Code = &target_mem[ 4000 ]; + Data = &target_mem[ max_size - 1 ]; // grows downwards } __attribute__((always_inline)) emit(int op, int val) { @@ -347,6 +514,8 @@ __ir2_get_var_loc(slice_t name, label_t variables[ 1 << 11 ], string error_I, st string _ir2( string I, + string filepath, + int *assembly_target, macro_t *macros, label_t *labels, label_delegated_t *forward_refs, @@ -399,7 +568,7 @@ string _ir2( space; int *m_index = --Data; - int start_index = m_index - m; + int start_index = m_index - assembly_target; if (*I == ':') { I++; @@ -411,6 +580,7 @@ string _ir2( "expected memory index in variable declaration (i think i remember this " "one...)"); } + Data++; // free the taken space start_index = strtol(I, &I, 10); space; } @@ -437,7 +607,6 @@ string _ir2( imm_in_mem(start_index, scanvalue()); #endif } else if (varqual(*I)) { // memory address - I++; int mem_index = scanvar(); mov_mem_mem(start_index, mem_index); } else { @@ -469,6 +638,39 @@ string _ir2( continue; } + if (strncmp("import", I, 6) == 0 && isspace(I[ 6 ])) { + I += 6; + space; + slice_t path = { 0, I }; + while (*I != ';') { + I++; + path.len++; + if (*I == 0 || *I == '\n') + run_err(path.ref, "reached invalid character / EOF whilst reading import path"); + } + checkskip(';', "expected semicolon"); + + string output; + if (path.ref[ 0 ] == '/') asprintf(&output, "%.*s", path.len, path.ref); + else asprintf(&output, "%s/%.*s", dirname(filepath), path.len, path.ref); + + int out_size; + string text = read_file(output, &out_size); + if (text == NULL) { + printf("failed to import \"%s\"\n", output); + perror("unable to use import"); + free(output); + exit(1); + } + + _ir2(text, filepath, assembly_target, macros, labels, forward_refs, variables); + + free(output); + free(text); + + continue; + } + // register macros if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) { I += 6; @@ -543,7 +745,7 @@ string _ir2( } // emit exit calls - if (strncmp("exit", I, 4) == 0) { + if (strncmp("exit", I, 4) == 0 && !varqual(I[ 4 ])) { I += 4; checkskip('(', "expected open paren on exit blob"); @@ -566,7 +768,7 @@ string _ir2( } // emit system - if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) { + if (strncmp("system", I, 6) == 0 && !varqual(I[ 6 ])) { I += 6; space; checkskip('(', "expected open paren on system blob"); @@ -583,12 +785,12 @@ string _ir2( continue; } - if (strncmp("jump", I, 4) == 0 && !isalnum(I[ 4 ])) { + if (strncmp("jump", I, 4) == 0 && !varqual(I[ 4 ])) { I += 4; goto PARSE_JUMP_BLOB; } - if (strncmp("jmp", I, 3) == 0 && !isalnum(I[ 3 ])) { + if (strncmp("jmp", I, 3) == 0 && !varqual(I[ 3 ])) { I += 3; PARSE_JUMP_BLOB: space; @@ -641,8 +843,8 @@ string _ir2( continue; } - if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[ 3 ])) - || (strncmp("jz", I, 2) == 0 && !isalnum(I[ 2 ]))) { + if ((strncmp("jnz", I, 3) == 0 && !varqual(I[ 3 ])) + || (strncmp("jz", I, 2) == 0 && !varqual(I[ 2 ]))) { bool was_jnz = !!strncmp("jz", I, 2); string name = was_jnz ? "jnz" : "jz"; @@ -734,7 +936,7 @@ string _ir2( continue; } - if (strncmp("if", I, 2) == 0 && !isalnum(I[ 2 ])) { + if (strncmp("if", I, 2) == 0 && !varqual(I[ 2 ])) { // if statement I += 2; space; @@ -769,7 +971,7 @@ string _ir2( Data = Code = m2; // get new I location - string new_I = _ir2(I, macros, labels, forward_refs, variables_G); + string new_I = _ir2(I, filepath, m2, macros, labels, forward_refs, variables_G); I = new_I; // restore values Code = Code_B; @@ -779,8 +981,9 @@ string _ir2( free(variables_G); } else { // just... i mean, i guess run the code..? - string new_I = _ir2(I, macros, labels, forward_refs, variables); - I = new_I; + string new_I = _ir2( + I, filepath, assembly_target, macros, labels, forward_refs, variables); + I = new_I; } continue; @@ -810,15 +1013,16 @@ string _ir2( op(str); // handle the code stuff - string new_I = _ir2(I, macros, labels, forward_refs, variables); - I = new_I; + string new_I + = _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables); + I = new_I; - *patchback = Code - m; // patch the jump instruction + *patchback = Code - assembly_target; // patch the jump instruction continue; } - if (strncmp("while", I, 5) == 0 && !isalnum(I[ 5 ])) { + if (strncmp("while", I, 5) == 0 && !varqual(I[ 5 ])) { I += 5; space; checkskip('(', "expected open paren for while loop"); @@ -853,7 +1057,7 @@ string _ir2( Data = Code = m2; // get new I location - string new_I = _ir2(I, macros, labels, forward_refs, variables_G); + string new_I = _ir2(I, filepath, m2, macros, labels, forward_refs, variables_G); I = new_I; // restore values Code = Code_B; @@ -864,10 +1068,11 @@ string _ir2( } else { // run forever! - int start = Code - m; + int start = Code - assembly_target; - string new_I = _ir2(I, macros, labels, forward_refs, variables); - I = new_I; + string new_I = _ir2( + I, filepath, assembly_target, macros, labels, forward_refs, variables); + I = new_I; imm_in_mem(7, start); // always jump back to the start } @@ -898,13 +1103,14 @@ string _ir2( imm(7); op(str); - int start_index = Code - m; + int start_index = Code - assembly_target; // handle the code stuff - string new_I = _ir2(I, macros, labels, forward_refs, variables); - I = new_I; + string new_I + = _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables); + I = new_I; - *patchback = Code - m; // patch the jump instruction + *patchback = Code - assembly_target; // patch the jump instruction // check the condition and jump back if true mem_in_a(mem_index); @@ -946,7 +1152,7 @@ string _ir2( FOUND_SLOT: slot->name = name; - slot->location = Code - m; + slot->location = Code - assembly_target; continue; } @@ -1075,7 +1281,7 @@ string _ir2( new.ref[ used ] = 0; - _ir2(new.ref, macros, labels, forward_refs, variables); + _ir2(new.ref, filepath, assembly_target, macros, labels, forward_refs, variables); continue; } @@ -1083,7 +1289,14 @@ string _ir2( REST_AFTER_MACRO_CALL: // handle assignments! - if (varqual(T)) { + if (T == '*' || varqual(T)) { + bool lhs_deref = T == '*'; + if (lhs_deref) { + I++; + space; + if (!varqual(*I)) run_err(I, "expected memory index or variable after dereference"); + } + string starting_qual = I; int mem_index = scanvar(); space; @@ -1092,12 +1305,14 @@ string _ir2( I += 2; space; checkskip(';', "expected semicolon"); - imm(1); - swap(); mem_in_a(mem_index); + if (lhs_deref) deref_a(); + emit(opcode.acc, 1); + op(u2b); op(sub); swap(); - imm(mem_index); + if (lhs_deref) mem_in_a(mem_index); + else { imm(mem_index); } store(); continue; @@ -1107,18 +1322,21 @@ string _ir2( I += 2; space; checkskip(';', "expected semicolon"); - imm(1); - swap(); mem_in_a(mem_index); + if (lhs_deref) deref_a(); + emit(opcode.acc, 1); + op(u2b); op(add); swap(); - imm(mem_index); + if (lhs_deref) mem_in_a(mem_index); + else { imm(mem_index); } store(); continue; } - char extra_op = '='; + string expr_I = I; + char extra_op = '='; if (*I == '+' || *I == '-' || *I == '&' || *I == '!') extra_op = *I++; checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)"); space; @@ -1129,12 +1347,42 @@ string _ir2( printf(" if this behavior is intended, use the jump blob instead.\n\n"); } - if (varqual(*I)) { + if (*I == '*' || varqual(*I)) { + bool rhs_deref = *I == '*'; + if (rhs_deref) { + I++; + space; + if (!varqual(*I)) + run_err(I, "expected memory index or variable after dereference"); + } + + if ((lhs_deref || rhs_deref) && extra_op != '=') { + run_err(expr_I, "dereferencing is not possible with arithmetic. (i was lazy)"); + } + int mem2_index = scanvar(); space; if (extra_op == '=') { - mov_mem_mem(mem_index, mem2_index); + if (lhs_deref) { + // m[m[a]] = m[b] + // m[m[a]] = m[m[b]] + mem_in_a(mem2_index); + if (rhs_deref) deref_a(); + swap(); + mem_in_a(mem_index); + store(); + } else { + if (rhs_deref) { + // m[a] = m[m[b]] + mem_in_a(mem2_index); + deref_a(); + a_in_mem(mem_index); + } else { + // m[a] = m[b] + mov_mem_mem(mem_index, mem2_index); + } + } } else if (extra_op == '+') { perform_op(add); } else if (extra_op == '-') { @@ -1196,7 +1444,7 @@ string _ir2( return I; } -ir2(string I) { +ir2(string I, string filepath, int *assembly_target) { const int macros_n = 1 << 9; const int labels_n = 1 << 10; const int vars_n = 1 << 11; @@ -1212,7 +1460,7 @@ ir2(string I) { exit(1); } - _ir2(I, macros, labels, forward_refs, variables); + _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables); label_delegated_t *curf = forward_refs; // handle forward references! @@ -1272,21 +1520,21 @@ clock_t ntime() { #endif // bench: measure using clock() -double bench_cycle(int instr) { +double bench_cycle(int instr, int *m, int mem_size) { int i; - for (i = 0; i < S - 2; i += 2) { + for (i = 16; i < S - 2; i += 2) { m[ i ] = instr; m[ i + 1 ] = 10; } m[ S - 2 ] = 0; m[ S - 1 ] = 0; - m[ 7 ] = 0; + m[ 7 ] = 16; c = 0; clock_t start = ntime(); int wstart = rdtsc(); - pu2(); + pu2(-1, m, mem_size); int wend = rdtsc(); clock_t end = ntime(); @@ -1307,20 +1555,20 @@ double bench_cycle(int instr) { } // bench2: measure using rdtsc -double bench2_cycle(int instr) { +double bench2_cycle(int instr, int *m, int mem_size) { unsigned long long start, end; double vminst_count, cpu_cycles; int i; - for (i = 0; i < S - 2; i += 2) { + for (i = 16; i < S - 2; i += 2) { m[ i ] = instr; m[ i + 1 ] = 5; } m[ S - 2 ] = 0; m[ S - 1 ] = 0; - m[ 7 ] = 0; + m[ 7 ] = 16; c = 0; start = rdtsc(); - pu2(); + pu2(-1, m, mem_size); end = rdtsc(); cpu_cycles = (double) (end - start); vminst_count = (double) m[ 7 ] / 2; @@ -1356,7 +1604,7 @@ inline() sleep_micro(int microseconds) { sleep_nano(microseconds * 1e3); } inline() sleep_milli(int milliseconds) { sleep_nano(milliseconds * 1e6); } // benchmark: run target for all opcodes and print summary -benchmark(double (*target)(int), const char *mode_label) { +benchmark(double (*target)(int, int *, int), const char *mode_label, int *m, int mem_size) { double results[ 19 ]; double sum = 0; int count = 0; @@ -1368,7 +1616,7 @@ benchmark(double (*target)(int), const char *mode_label) { for (i = 1; i < 19; i++) { // printf("running: %s\n", op_names[ i ]); - results[ i ] = target(i); + results[ i ] = target(i, m, mem_size); sum += results[ i ]; count++; } @@ -1412,11 +1660,14 @@ main(int argc, char **argv) { return 1; } - init_pu2(); - init_ir2(); + int *assembly_target = calloc(S, sizeof(int)); + + init_ir2(assembly_target, S); if (strcmp(argv[ 1 ], "benchmark") == 0) { - benchmark(bench_cycle, "time"); + int *m = init_pu2(); + int mem_size = S; + benchmark(bench_cycle, "time", m, mem_size); const long N = S / 2; // printably the same insts you report long sum = 0; @@ -1449,10 +1700,10 @@ main(int argc, char **argv) { int o_size; long before = ntime(); long cycles_bef = rdtsc(); - ir2(contents); - long cycles_aft = rdtsc(); - long after = ntime(); - m[ 7 ] = 4000; + ir2(contents, filename, assembly_target); + long cycles_aft = rdtsc(); + long after = ntime(); + assembly_target[ 7 ] = 4000; /*int j = 0; for(j = 0; j < 64; j++) { @@ -1464,7 +1715,17 @@ main(int argc, char **argv) { free(contents); - int res_size = Code - &m[ 4000 ]; + // int res_size = Code - &m[ 4000 ]; + + // run the kernel (ring zero) forever (time slice -1) + int mem_size = S; + + // pid zero - kernel + processes[ 0 ] + = (emu_process) { .mem_size = S, + .memory = assembly_target, + .ring_level = 0, + .permissions = { .make_syscall = true, .spawn_process = true } }; - emu(); + emu(-1, 0); } |
