fix several edge case interactions between page faults and instruction execution

This commit is contained in:
hyenasky 2023-03-14 08:24:49 -06:00
parent 7f482a809a
commit 8c4967cb13

View File

@ -506,32 +506,36 @@ static uint32_t vm_read_across(vm_t *vm, uint32_t address, int size) {
} }
void vm_write_across(vm_t *vm, uint32_t address, int size, uint32_t value) { void vm_write_across(vm_t *vm, uint32_t address, int size, uint32_t value) {
// calculate number of bytes for each page
int bytes_first = 0x1000 - (address & 0x00000FFF);
int address_second = (address + size) & 0xFFFFF000;
int bytes_second = (address + size) & 0x00000FFF;
// make sure both pages are resident before doing any writing
uint8_t *ptr_first = vm_findmemory(vm, address, bytes_first, true);
uint8_t *ptr_second = vm_findmemory(vm, address_second, bytes_second, true);
// write the first page // write the first page
int bytes = 0x1000 - (address & 0x00000FFF); while (bytes_first) {
uint8_t *ptr = vm_findmemory(vm, address, bytes, true); *ptr_first = value & 0xFF;
while (bytes) {
*ptr = value & 0xFF;
value >>= 8; value >>= 8;
ptr++; ptr_first++;
bytes--; bytes_first--;
} }
// write the second page // write the second page
bytes = (address + size) & 0x00000FFF; while (bytes_second) {
address = (address + size) & 0xFFFFF000; *ptr_second = value & 0xFF;
ptr = vm_findmemory(vm, address, bytes, true);
while (bytes) {
*ptr = value & 0xFF;
value >>= 8; value >>= 8;
ptr++; ptr_second++;
bytes--; bytes_second--;
} }
} }
@ -790,9 +794,18 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
break; \ break; \
} }
// make sure NOT to update the stack pointer until the full instruction has
// been read, and the target has been written. otherwise a pagefault halfway
// through could wreak havoc.
#define VM_IMPL_POP(_size, _vm_target, _vm_pop) { \ #define VM_IMPL_POP(_size, _vm_target, _vm_pop) { \
VM_PRELUDE_1(_size); \ VM_PRELUDE_1(_size); \
_vm_target(vm, instr.source, _vm_pop(vm)); \ uint32_t oldsp = vm->pointer_stack; \
uint32_t val = _vm_pop(vm); \
uint32_t newsp = vm->pointer_stack; \
vm->pointer_stack = oldsp; \
_vm_target(vm, instr.source, val); \
vm->pointer_stack = newsp; \
break; \ break; \
} }
@ -812,8 +825,8 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
VM_PRELUDE_1(_size); \ VM_PRELUDE_1(_size); \
_type v = _vm_source_stay(vm, instr.source); \ _type v = _vm_source_stay(vm, instr.source); \
_type x = ~v; \ _type x = ~v; \
vm->flag_zero = x == 0; \
_vm_target(vm, instr.source, x); \ _vm_target(vm, instr.source, x); \
vm->flag_zero = x == 0; \
break; \ break; \
} }
@ -821,9 +834,10 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
VM_PRELUDE_1(_size); \ VM_PRELUDE_1(_size); \
_type v = _vm_source_stay(vm, instr.source); \ _type v = _vm_source_stay(vm, instr.source); \
_type x; \ _type x; \
vm->flag_carry = _oper(v, 1, &x); \ bool carry = _oper(v, 1, &x); \
vm->flag_zero = x == 0; \
_vm_target(vm, instr.source, x); \ _vm_target(vm, instr.source, x); \
vm->flag_carry = carry; \
vm->flag_zero = x == 0; \
break; \ break; \
} }
@ -832,9 +846,10 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
_type a = (_type) _vm_source(vm, instr.source); \ _type a = (_type) _vm_source(vm, instr.source); \
_type b = (_type) _vm_source_stay(vm, instr.target); \ _type b = (_type) _vm_source_stay(vm, instr.target); \
_type x; \ _type x; \
vm->flag_carry = _oper(b, a, &x); \ bool carry = _oper(b, a, &x); \
vm->flag_zero = x == 0; \
_vm_target(vm, instr.target, (_type_target) x); \ _vm_target(vm, instr.target, (_type_target) x); \
vm->flag_carry = carry; \
vm->flag_zero = x == 0; \
break; \ break; \
} }
@ -843,8 +858,8 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
_type a = (_type) _vm_source(vm, instr.source); \ _type a = (_type) _vm_source(vm, instr.source); \
_type b = (_type) _vm_source_stay(vm, instr.target); \ _type b = (_type) _vm_source_stay(vm, instr.target); \
_type x = _oper(b, a); \ _type x = _oper(b, a); \
vm->flag_zero = x == 0; \
_vm_target(vm, instr.target, (_type_target) x); \ _vm_target(vm, instr.target, (_type_target) x); \
vm->flag_zero = x == 0; \
break; \ break; \
} }
@ -857,8 +872,8 @@ static void vm_skipparam(vm_t *vm, uint32_t size, uint8_t prtype) {
break; \ break; \
} \ } \
_type x = _oper(b, a); \ _type x = _oper(b, a); \
vm->flag_zero = x == 0; \
_vm_target(vm, instr.target, (_type_target) x); \ _vm_target(vm, instr.target, (_type_target) x); \
vm->flag_zero = x == 0; \
break; \ break; \
} }