From 3213bff49a54f4ed147a501432511135563ade9e Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 26 Apr 2020 01:59:12 +0200 Subject: [PATCH 001/165] Created structs for regs and v8086 machine --- os/kernel/src/kernel.c | 5 ++- os/kernel/src/v8086/v8086.c | 48 ++++++++++++++++++++++ os/kernel/src/v8086/v8086.h | 81 +++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 os/kernel/src/v8086/v8086.c create mode 100644 os/kernel/src/v8086/v8086.h diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index acbf8971..5bfd22f7 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -35,6 +35,8 @@ #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" +#include "v8086/v8086.h" + typedef struct _linesStruct { uint16_t ax; @@ -393,6 +395,7 @@ int kmain() vga_clear_screen(); switch_active_terminal(0); + v8086* v8086 = v8086_create_machine(); // terminal_manager_print_string(p, "CIASTKO"); // p = process_manager_create_process("A:/ENV/SHELL.ELF", "", 1000, false); // attach_process_to_terminal(ts[0].terminal_id, process_manager_get_process(p)); @@ -402,7 +405,7 @@ int kmain() // terminal_manager_print_string(p, "CZEKOLAAAAAAAAADA!"); //terminal_manager_print_string(ts[1].active_process->id, "KARMAEL"); //terminal_manager_print_string(ts[2].active_process->id, "CZEKOLADA!"); - process_manager_run(); + //process_manager_run(); //destroy_active_terminal(); while (1); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c new file mode 100644 index 00000000..56f5cbb3 --- /dev/null +++ b/os/kernel/src/v8086/v8086.c @@ -0,0 +1,48 @@ +#include "v8086.h" +#include "../memory/heap/heap.h" +#include + +#define get_absolute_address(segment, offset) (((segment) * 16) + (offset)) +#define read_16_from_pointer(memory, pointer) (*((uint16_t*)(memory + pointer))) +#define write_16_to_pointer(memory, pointer, value) read_16_from_pointer(memory, pointer) = (value) +#define read_16_from_double_pointer(memory, pointer) (*((uint16_t*)(memory + read_16_from_pointer(memory, pointer)))) +#define write_16_to_double_pointer(memory, pointer, value) read_16_from_double_pointer(memory, pointer) = (value) + +#define push_16(machine, value) write_16_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value) +#define pop_16(machine, value) read_16_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp += 2)) + +v8086* v8086_create_machine() +{ + v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); + if(machine == NULL) return NULL; + memset(machine, 0, sizeof(v8086)); + machine->regs.x.flags = 0x2; + machine->sregs.cs = 0xf000; + machine->IP = 0xfff0; + memcpy(machine->Memory, 0xc0000000, 0x100000); + + return machine; +} + +int16_t v8086_call_function(v8086* machine) +{ + while(!(machine->IP == 0xFFFF && machine->sregs.cs == 0xFFFF)) + { + int x = -1; + if(x) return x; + } + return 0; +} + +int16_t v8086_call_int(v8086* machine, int16_t num) +{ + if ((num < 0) || (num > 0xFF)) return -1; + machine -> IP = read_16_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4)); + machine -> sregs.cs = read_16_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + push_16(machine, machine->regs.w.flags); + push_16(machine, 0xFFFF); + push_16(machine, 0xFFFF); + int x = v8086_call_function(machine); + if(x) return -2; + return num; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h new file mode 100644 index 00000000..8e0cefc7 --- /dev/null +++ b/os/kernel/src/v8086/v8086.h @@ -0,0 +1,81 @@ +#ifndef V8086_H +#define V8086_H + +#include + +struct DWORDREGS { + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t cflag; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint16_t eflags; + uint32_t esp; +}; + +struct WORDREGS { + uint16_t di, _upper_di; + uint16_t si, _upper_si; + uint16_t bp, _upper_bp; + uint16_t cflag, _upper_cflag; + uint16_t bx, _upper_bx; + uint16_t dx, _upper_dx; + uint16_t cx, _upper_cx; + uint16_t ax, _upper_ax; + uint16_t flags; + uint16_t sp, _upper_sp; +}; + +struct BYTEREGS { + uint16_t di, _upper_di; + uint16_t si, _upper_si; + uint16_t bp, _upper_bp; + uint32_t cflag; + uint8_t bl; + uint8_t bh; + uint16_t _upper_bx; + uint8_t dl; + uint8_t dh; + uint16_t _upper_dx; + uint8_t cl; + uint8_t ch; + uint16_t _upper_cx; + uint8_t al; + uint8_t ah; + uint16_t _upper_ax; + uint16_t flags; + uint16_t sp, _upper_sp; +}; + +union REGS { /* Compatible with DPMI structure, except cflag */ + struct DWORDREGS d; + struct WORDREGS x; + struct WORDREGS w; + struct BYTEREGS h; +}; + +struct SREGS { + unsigned short es; + unsigned short ds; + unsigned short fs; + unsigned short gs; + unsigned short cs; + unsigned short ss; +}; + +typedef struct _v8086 +{ + union REGS regs; + struct SREGS sregs; + uint16_t IP; + uint8_t Memory[0x100000]; +} v8086; + + +v8086* v8086_create_machine(); +int16_t v8086_call_int(v8086* machine, int16_t num) + +#endif \ No newline at end of file From 7ba502abb5a8fa0d3cc45ba8267ff18aa7c1f748 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 28 Apr 2020 02:52:23 +0200 Subject: [PATCH 002/165] Started work with ADD opcodes --- os/kernel/src/v8086/v8086.c | 136 ++++++++++++++++++++++++++++++++---- os/kernel/src/v8086/v8086.h | 2 +- 2 files changed, 125 insertions(+), 13 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 56f5cbb3..e5c593a2 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -2,14 +2,59 @@ #include "../memory/heap/heap.h" #include -#define get_absolute_address(segment, offset) (((segment) * 16) + (offset)) -#define read_16_from_pointer(memory, pointer) (*((uint16_t*)(memory + pointer))) -#define write_16_to_pointer(memory, pointer, value) read_16_from_pointer(memory, pointer) = (value) -#define read_16_from_double_pointer(memory, pointer) (*((uint16_t*)(memory + read_16_from_pointer(memory, pointer)))) -#define write_16_to_double_pointer(memory, pointer, value) read_16_from_double_pointer(memory, pointer) = (value) +enum WORD_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; -#define push_16(machine, value) write_16_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value) -#define pop_16(machine, value) read_16_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp += 2)) +int16_t parse_instruction(v8086* machine); + +static inline uint16_t get_absolute_address(uint16_t segment, uint16_t offset) +{ + return segment * 16 + offset; +} + +static inline uint8_t* get_byte_pointer(uint8_t* memory, uint16_t offset) +{ + return memory + offset; +} + +static inline uint16_t* get_word_pointer(uint8_t* memory, uint16_t offset) +{ + return (uint16_t*)(memory + offset); +} + +static inline uint8_t read_byte_from_pointer(uint8_t* memory, uint16_t offset) +{ + return *(memory + offset); +} + +static inline uint16_t read_word_from_pointer(uint8_t* memory, uint16_t offset) +{ + return *get_word_pointer(memory, offset); +} + +static inline void write_word_to_pointer(uint8_t* memory, uint16_t offset, uint16_t value) +{ + *(get_word_pointer(memory, offset)) = value; +} + +static inline uint16_t read_word_from_double_pointer(uint8_t* memory, uint16_t offset) +{ + *(get_word_pointer(memory, read_word_from_pointer(memory, offset))); +} + +static inline void write_word_from_double_pointer(uint8_t memory, uint16_t offset, uint16_t value) +{ + *(get_word_pointer(memory, read_word_from_pointer(memory, offset))) = value; +} + +static inline void push_word(v8086* machine, uint16_t value) +{ + write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); +} + +static inline uint16_t pop_word(v8086* machine, uint16_t value) +{ + return read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp += 2)); +} v8086* v8086_create_machine() { @@ -37,12 +82,79 @@ int16_t v8086_call_function(v8086* machine) int16_t v8086_call_int(v8086* machine, int16_t num) { if ((num < 0) || (num > 0xFF)) return -1; - machine -> IP = read_16_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4)); - machine -> sregs.cs = read_16_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); - push_16(machine, machine->regs.w.flags); - push_16(machine, 0xFFFF); - push_16(machine, 0xFFFF); + machine -> IP = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4)); + machine -> sregs.cs = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + push_word(machine, machine->regs.w.flags); + push_word(machine, 0xFFFF); + push_word(machine, 0xFFFF); int x = v8086_call_function(machine); if(x) return -2; return num; +} + +static inline uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) +{ + switch(reg_field) + { + case AL: + return &(machine->regs.h.al); + case AH: + return &(machine->regs.h.ah); + case BL: + return &(machine->regs.h.bl); + case BH: + return &(machine->regs.h.bh); + case CL: + return &(machine->regs.h.cl); + case CH: + return &(machine->regs.h.ch); + case DL: + return &(machine->regs.h.dl); + case DH: + return &(machine->regs.h.dh); + } +} + +static inline uint8_t* get_byte_memory(v8086* machine, uint8_t mod_rm) +{ + +} + +int16_t parse_and_execute_instruction(v8086* machine) +{ + //Maybe opcode, an be also prefix + uint8_t opcode = read_byte_from_pointer(machine->Memory, machine->IP); + + //Aritmetic operations + //ADD + if(opcode > 0 && opcode <= 5) + { + //Maybe Mod/RM, Can be Immediate + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, machine->IP + 1); + + if(opcode % 2) //Odd Opcode means 16 or 32 bit operands + { + + } + else + { + uint8_t* reg = NULL; + uint8_t* mem = NULL; + uint16_t result = 0; + switch(opcode) + { + case 0: //ADD r/m8, r8 + *reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + result = *reg + *mem; + *mem = result & 0xFF; + case 2: //ADD r8, r/m8 + *reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + result = *reg + *mem; + *reg = result & 0xFF; + case 4: //ADD AL, imm8 + result = machine->regs.h.al + mod_rm_or_immediate; + machine->regs.h.al = result & 0xFF; + } + } + } } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 8e0cefc7..9b421658 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -76,6 +76,6 @@ typedef struct _v8086 v8086* v8086_create_machine(); -int16_t v8086_call_int(v8086* machine, int16_t num) +int16_t v8086_call_int(v8086* machine, int16_t num); #endif \ No newline at end of file From 8220a7dfc962055242caa07336ef71f6cd50daad Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 28 Apr 2020 02:53:31 +0200 Subject: [PATCH 003/165] Skeleton for get_byte_memtory function od mod/rm parser --- os/kernel/src/v8086/v8086.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e5c593a2..0c49de5e 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -117,7 +117,13 @@ static inline uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) static inline uint8_t* get_byte_memory(v8086* machine, uint8_t mod_rm) { - + switch(mod_rm >> 6) + { + case 0: + case 1: + case 2: + case 3: + } } int16_t parse_and_execute_instruction(v8086* machine) From 460dcb4d986807d5cbbdbb9fa2472eccb59bae8e Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 29 Apr 2020 02:04:48 +0200 Subject: [PATCH 004/165] Added some helper functions, and parsing Mod/RM. Added logic to ADD but without Flags --- os/kernel/src/v8086/v8086.c | 246 ++++++++++++++++++++++++++++++++++-- os/kernel/src/v8086/v8086.h | 6 + 2 files changed, 238 insertions(+), 14 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 0c49de5e..e909d8d6 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -2,7 +2,9 @@ #include "../memory/heap/heap.h" #include -enum WORD_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; +enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; +enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; +enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; int16_t parse_instruction(v8086* machine); @@ -21,6 +23,26 @@ static inline uint16_t* get_word_pointer(uint8_t* memory, uint16_t offset) return (uint16_t*)(memory + offset); } +static inline uint32_t* get_dword_pointer(uint8_t* memory, uint16_t offset) +{ + return (uint32_t*)(memory + offset); +} + +static inline void* get_variable_length_pointer(uint8_t* memory, uint16_t offset, uint8_t width) +{ + switch(width) + { + case 8: + return get_byte_pointer(memory, offset); + case 16: + return get_word_pointer(memory, offset); + case 32: + return get_dword_pointer(memory, offset); + default: + return NULL; + } +} + static inline uint8_t read_byte_from_pointer(uint8_t* memory, uint16_t offset) { return *(memory + offset); @@ -31,6 +53,11 @@ static inline uint16_t read_word_from_pointer(uint8_t* memory, uint16_t offset) return *get_word_pointer(memory, offset); } +static inline uint32_t read_dword_from_pointer(uint8_t* memory, uint16_t offset) +{ + return *get_dword_pointer(memory, offset); +} + static inline void write_word_to_pointer(uint8_t* memory, uint16_t offset, uint16_t value) { *(get_word_pointer(memory, offset)) = value; @@ -38,10 +65,10 @@ static inline void write_word_to_pointer(uint8_t* memory, uint16_t offset, uint1 static inline uint16_t read_word_from_double_pointer(uint8_t* memory, uint16_t offset) { - *(get_word_pointer(memory, read_word_from_pointer(memory, offset))); + return *(get_word_pointer(memory, read_word_from_pointer(memory, offset))); } -static inline void write_word_from_double_pointer(uint8_t memory, uint16_t offset, uint16_t value) +static inline void write_word_from_double_pointer(uint8_t* memory, uint16_t offset, uint16_t value) { *(get_word_pointer(memory, read_word_from_pointer(memory, offset))) = value; } @@ -64,7 +91,7 @@ v8086* v8086_create_machine() machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; machine->IP = 0xfff0; - memcpy(machine->Memory, 0xc0000000, 0x100000); + memcpy(machine->Memory, (void*)0xc0000000, 0x100000); return machine; } @@ -92,7 +119,7 @@ int16_t v8086_call_int(v8086* machine, int16_t num) return num; } -static inline uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) +uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) { switch(reg_field) { @@ -113,34 +140,219 @@ static inline uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) case DH: return &(machine->regs.h.dh); } + return NULL; } -static inline uint8_t* get_byte_memory(v8086* machine, uint8_t mod_rm) +uint16_t* get_word_register(v8086* machine, uint8_t reg_field) { - switch(mod_rm >> 6) + switch(reg_field) + { + case AX: + return &(machine->regs.x.ax); + case CX: + return &(machine->regs.x.cx); + case DX: + return &(machine->regs.x.dx); + case BX: + return &(machine->regs.x.bx); + case SP: + return &(machine->regs.x.sp); + case BP: + return &(machine->regs.x.bp); + case SI: + return &(machine->regs.x.si); + case DI: + return &(machine->regs.x.di); + } + return NULL; +} + +uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) +{ + switch(reg_field) + { + case EAX: + return &(machine->regs.d.eax); + case ECX: + return &(machine->regs.d.ecx); + case EDX: + return &(machine->regs.d.edx); + case EBX: + return &(machine->regs.d.ebx); + case ESP: + return &(machine->regs.d.esp); + case EBP: + return &(machine->regs.d.ebp); + case ESI: + return &(machine->regs.d.esi); + case EDI: + return &(machine->regs.d.edi); + } + return NULL; +} + +void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) +{ + switch(mod_rm >> 6) //Parsing mod than parsing rm { case 0: - case 1: - case 2: + switch(mod_rm & 7){ + case 0: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si), width); + case 1: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di), width); + case 2: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si), width); + case 3: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di), width); + case 4: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si), width); + case 5: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di), width); + case 6:{ + void* ptr = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset)))), width); + machine->internal_state.IPOffset += 1; + return ptr; + } + case 7: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx), width); + default: + return NULL; + } + case 1:{ + int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + switch(mod_rm & 7){ + case 0: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si + disp), width); + case 1: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di + disp), width); + case 2: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si + disp), width); + case 3: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di + disp), width); + case 4: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si + disp), width); + case 5: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di + disp), width); + case 6: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + disp), width); + case 7: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + disp), width); + default: + return NULL; + } + } + case 2:{ + uint16_t disp = (uint16_t) read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + switch(mod_rm & 7){ + case 0: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si + disp), width); + case 1: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di + disp), width); + case 2: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si + disp), width); + case 3: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di + disp), width); + case 4: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si + disp), width); + case 5: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di + disp), width); + case 6: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + disp), width); + case 7: + return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + disp), width); + default: + return NULL; + } + } case 3: + switch(width){ + case 8: + return get_byte_register(machine, mod_rm & 7); + case 16: + return get_word_register(machine, mod_rm & 7); + case 32: + return get_dword_register(machine, mod_rm & 7); + default: + return NULL; + } } + return NULL; } int16_t parse_and_execute_instruction(v8086* machine) { + machine->internal_state.IPOffset = 0; + machine->internal_state.operand_32_bit = 0; + //Maybe opcode, an be also prefix - uint8_t opcode = read_byte_from_pointer(machine->Memory, machine->IP); + uint8_t opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; //Aritmetic operations //ADD if(opcode > 0 && opcode <= 5) { //Maybe Mod/RM, Can be Immediate - uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, machine->IP + 1); + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; if(opcode % 2) //Odd Opcode means 16 or 32 bit operands { - + if(machine->internal_state.operand_32_bit) + { + uint32_t* reg = NULL; + uint32_t* mem = NULL; + uint64_t result = 0; + switch(opcode) + { + case 1: //ADD r/m8, r8 + reg = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 32); + result = *reg + *mem; + *mem = result & 0xFFFFFFFF; + break; + case 3: //ADD r32, r/m32 + reg = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 32); + result = *reg + *mem; + *reg = result & 0xFFFFFFFF; + break; + case 5: //ADD EAX, imm32 + result = machine->regs.d.eax + read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 3; + machine->regs.d.eax = result & 0xFFFFFFFF; + break; + } + } + else + { + uint16_t* reg = NULL; + uint16_t* mem = NULL; + uint32_t result = 0; + switch(opcode) + { + case 1: //ADD r/m16, r16 + reg = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 16); + result = *reg + *mem; + *mem = result & 0xFFFF; + break; + case 3: //ADD r16, r/m16 + reg = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 16); + result = *reg + *mem; + *reg = result & 0xFFFF; + break; + case 5: //ADD AX, imm16 + result = machine->regs.x.ax + read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + machine->regs.x.ax = result & 0xFFFF; + break; + } + } } else { @@ -150,17 +362,23 @@ int16_t parse_and_execute_instruction(v8086* machine) switch(opcode) { case 0: //ADD r/m8, r8 - *reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 8); result = *reg + *mem; *mem = result & 0xFF; + break; case 2: //ADD r8, r/m8 - *reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + mem = get_memory_from_mode(machine, mod_rm_or_immediate, 8); result = *reg + *mem; *reg = result & 0xFF; + break; case 4: //ADD AL, imm8 result = machine->regs.h.al + mod_rm_or_immediate; machine->regs.h.al = result & 0xFF; + break; } } } + return 0; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 9b421658..c5945c4a 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -66,11 +66,17 @@ struct SREGS { unsigned short ss; }; +typedef struct _is{ + uint32_t operand_32_bit; + uint16_t IPOffset; +} _internal_state; + typedef struct _v8086 { union REGS regs; struct SREGS sregs; uint16_t IP; + _internal_state internal_state; uint8_t Memory[0x100000]; } v8086; From 0324aadf21d92a34eb1401bbf168d28b19905ceb Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 30 Apr 2020 01:23:05 +0200 Subject: [PATCH 005/165] Added flags cheking to ADD operations, and tiny refactor --- os/kernel/src/v8086/v8086.c | 114 ++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 37 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e909d8d6..173ba01a 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -2,6 +2,19 @@ #include "../memory/heap/heap.h" #include +#define bit_get(p,m) ((p) & (m)) +#define bit_set(p,m) ((p) |= (m)) +#define bit_clear(p,m) ((p) &= ~(m)) +#define bit_flip(p,m) ((p) ^= (m)) +#define bit_write(p,m,v) (v ? bit_set(p,m) : bit_clear(p,m)) + +#define CARRY_FLAG_BIT 0 +#define PARITY_FLAG_BIT 2 +#define AUX_CARRY_FLAG_BIT 4 +#define ZERO_FLAG_BIT 6 +#define SIGN_FLAG_BIT 7 +#define OVERFLOW_FLAG_BIT 11 + enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; @@ -303,81 +316,108 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit) { - uint32_t* reg = NULL; - uint32_t* mem = NULL; + uint32_t* source = NULL; + uint32_t* dest = NULL; uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking switch(opcode) { - case 1: //ADD r/m8, r8 - reg = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 32); - result = *reg + *mem; - *mem = result & 0xFFFFFFFF; + case 1: //ADD r/m32, r32 + source = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, 32); break; case 3: //ADD r32, r/m32 - reg = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 32); - result = *reg + *mem; - *reg = result & 0xFFFFFFFF; + dest = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm_or_immediate, 32); break; case 5: //ADD EAX, imm32 - result = machine->regs.d.eax + read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + dest = get_dword_register(machine, EAX); + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 3; - machine->regs.d.eax = result & 0xFFFFFFFF; break; } + dest_before = *dest; + result = *dest + *source; + *dest = result & 0xFFFFFFFF; + bit_write(machine->regs.d.eflags, 1<> 32) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) + parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 31); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> 31) != (dest_before >> 31)); //OVERFLOW FLAG } else { - uint16_t* reg = NULL; - uint16_t* mem = NULL; + uint16_t* source = NULL; + uint16_t* dest = NULL; uint32_t result = 0; + uint16_t dest_before; switch(opcode) { case 1: //ADD r/m16, r16 - reg = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 16); - result = *reg + *mem; - *mem = result & 0xFFFF; + source = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, 16); break; case 3: //ADD r16, r/m16 - reg = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 16); - result = *reg + *mem; - *reg = result & 0xFFFF; + dest = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm_or_immediate, 16); break; case 5: //ADD AX, imm16 - result = machine->regs.x.ax + read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + dest = get_word_register(machine, AX); + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - machine->regs.x.ax = result & 0xFFFF; break; } + dest_before = *dest; + result = *dest + *source; + *dest = result & 0xFFFF; + bit_write(machine->regs.d.eflags, 1<> 16) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) + parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 15); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> 15) != (dest_before >> 15)); //OVERFLOW FLAG } } else { - uint8_t* reg = NULL; - uint8_t* mem = NULL; + uint8_t* source = NULL; + uint8_t* dest = NULL; uint16_t result = 0; + uint8_t dest_before; switch(opcode) { case 0: //ADD r/m8, r8 - reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - result = *reg + *mem; - *mem = result & 0xFF; + source = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; case 2: //ADD r8, r/m8 - reg = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); - mem = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - result = *reg + *mem; - *reg = result & 0xFF; + dest = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; case 4: //ADD AL, imm8 - result = machine->regs.h.al + mod_rm_or_immediate; - machine->regs.h.al = result & 0xFF; + dest = get_byte_register(machine, AL); + source = &(mod_rm_or_immediate); break; } + dest_before = *dest; + result = *dest + *source; + *dest = result & 0xFF; + bit_write(machine->regs.d.eflags, 1<> 8) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) + parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> 7) != (dest_before >> 7)); //OVERFLOW FLAG } } return 0; From df2cdf4e0bcfbcbb7934614fca8995f4f748f1bd Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 01:09:17 +0200 Subject: [PATCH 006/165] Refactored ADD operand --- os/kernel/src/v8086/v8086.c | 149 +++++++++++++++++------------------- 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 173ba01a..a070c0a0 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -204,6 +204,21 @@ uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) return NULL; } +void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width) +{ + switch (width) + { + case 8: + return get_byte_register(machine, reg_field); + case 16: + return get_word_register(machine, reg_field); + case 32: + return get_dword_register(machine, reg_field); + default: + return NULL; + } +} + void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) { switch(mod_rm >> 6) //Parsing mod than parsing rm @@ -295,6 +310,41 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) return NULL; } +int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return -1; + result = dest_before + source_before + carry; + bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) + parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + if(width == 8){ + *((uint8_t*)dest) = result & 0xFF; + } else if(width == 16){ + *((uint16_t*)dest) = result & 0xFFFF; + } else if(width == 32){ + *((uint32_t*)dest) = result & 0xFFFFFFFF; + } else return -1; + return 0; +} + int16_t parse_and_execute_instruction(v8086* machine) { machine->internal_state.IPOffset = 0; @@ -314,83 +364,35 @@ int16_t parse_and_execute_instruction(v8086* machine) if(opcode % 2) //Odd Opcode means 16 or 32 bit operands { - if(machine->internal_state.operand_32_bit) - { - uint32_t* source = NULL; - uint32_t* dest = NULL; - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - switch(opcode) - { - case 1: //ADD r/m32, r32 - source = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, 32); - break; - case 3: //ADD r32, r/m32 - dest = get_dword_register(machine, (mod_rm_or_immediate >> 3) & 7); - source = get_memory_from_mode(machine, mod_rm_or_immediate, 32); - break; - case 5: //ADD EAX, imm32 - dest = get_dword_register(machine, EAX); - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 3; - break; - } - dest_before = *dest; - result = *dest + *source; - *dest = result & 0xFFFFFFFF; - bit_write(machine->regs.d.eflags, 1<> 32) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) - parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 31); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> 31) != (dest_before >> 31)); //OVERFLOW FLAG - } - else + uint8_t width = 16; + void* source = NULL; + void* dest = NULL; + if(machine->internal_state.operand_32_bit) width = 32; + switch(opcode) { - uint16_t* source = NULL; - uint16_t* dest = NULL; - uint32_t result = 0; - uint16_t dest_before; - switch(opcode) - { - case 1: //ADD r/m16, r16 - source = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, 16); + case 1: //ADD r/m32, r32 or ADD r/m16, r16 + source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); break; - case 3: //ADD r16, r/m16 - dest = get_word_register(machine, (mod_rm_or_immediate >> 3) & 7); - source = get_memory_from_mode(machine, mod_rm_or_immediate, 16); + case 3: //ADD r32, r/m32 or ADD r16, r/m16 + dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + source = get_memory_from_mode(machine, mod_rm_or_immediate, width); break; - case 5: //ADD AX, imm16 - dest = get_word_register(machine, AX); - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; + case 5: //ADD EAX, imm32 or ADD AX, imm16 + dest = get_variable_length_register(machine, AX, width); + if(width == 32) + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + else + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += ((width / 8) - 1); break; - } - dest_before = *dest; - result = *dest + *source; - *dest = result & 0xFFFF; - bit_write(machine->regs.d.eflags, 1<> 16) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) - parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 15); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> 15) != (dest_before >> 15)); //OVERFLOW FLAG } + perform_adding(machine, dest, source, width, 0); } else { uint8_t* source = NULL; uint8_t* dest = NULL; - uint16_t result = 0; - uint8_t dest_before; switch(opcode) { case 0: //ADD r/m8, r8 @@ -406,18 +408,7 @@ int16_t parse_and_execute_instruction(v8086* machine) source = &(mod_rm_or_immediate); break; } - dest_before = *dest; - result = *dest + *source; - *dest = result & 0xFF; - bit_write(machine->regs.d.eflags, 1<> 8) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) - parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> 7) != (dest_before >> 7)); //OVERFLOW FLAG + perform_adding(machine, dest, source, 8, 0); } } return 0; From 790cc8077d843a3267cd2cbe83a4fbdb5f0d3d41 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 01:32:26 +0200 Subject: [PATCH 007/165] Tiny style-coding corrections --- os/kernel/src/v8086/v8086.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index a070c0a0..435009c1 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -208,14 +208,14 @@ void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t wi { switch (width) { - case 8: - return get_byte_register(machine, reg_field); - case 16: - return get_word_register(machine, reg_field); - case 32: - return get_dword_register(machine, reg_field); - default: - return NULL; + case 8: + return get_byte_register(machine, reg_field); + case 16: + return get_word_register(machine, reg_field); + case 32: + return get_dword_register(machine, reg_field); + default: + return NULL; } } @@ -328,20 +328,16 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, result = dest_before + source_before + carry; bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) - parrity ^= (result >> i) & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - if(width == 8){ - *((uint8_t*)dest) = result & 0xFF; - } else if(width == 16){ - *((uint16_t*)dest) = result & 0xFFFF; - } else if(width == 32){ - *((uint32_t*)dest) = result & 0xFFFFFFFF; - } else return -1; + if(width == 8) *((uint8_t*)dest) = result & 0xFF; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + else return -1; return 0; } From 5ac761c154cc423974f75c045004cc35e86c089d Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 15:28:50 +0200 Subject: [PATCH 008/165] More refactor, Added ADC operation --- os/kernel/src/v8086/v8086.c | 110 ++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 435009c1..f16b657c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -341,71 +341,81 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, return 0; } -int16_t parse_and_execute_instruction(v8086* machine) +int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { - machine->internal_state.IPOffset = 0; - machine->internal_state.operand_32_bit = 0; - - //Maybe opcode, an be also prefix - uint8_t opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - //Aritmetic operations - //ADD - if(opcode > 0 && opcode <= 5) + //Maybe Mod/RM, Can be Immediate + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(recalculated_opcode % 2) //Odd Opcode means 16 or 32 bit operands { - //Maybe Mod/RM, Can be Immediate - uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - if(opcode % 2) //Odd Opcode means 16 or 32 bit operands + uint8_t width = 16; + void* source = NULL; + void* dest = NULL; + if(machine->internal_state.operand_32_bit) width = 32; + switch(recalculated_opcode) { - uint8_t width = 16; - void* source = NULL; - void* dest = NULL; - if(machine->internal_state.operand_32_bit) width = 32; - switch(opcode) - { - case 1: //ADD r/m32, r32 or ADD r/m16, r16 - source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); - break; - case 3: //ADD r32, r/m32 or ADD r16, r/m16 - dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); - source = get_memory_from_mode(machine, mod_rm_or_immediate, width); - break; - case 5: //ADD EAX, imm32 or ADD AX, imm16 - dest = get_variable_length_register(machine, AX, width); - if(width == 32) - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - else - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += ((width / 8) - 1); - break; - } - perform_adding(machine, dest, source, width, 0); + case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 + source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); + break; + case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 + dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + source = get_memory_from_mode(machine, mod_rm_or_immediate, width); + break; + case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 + dest = get_variable_length_register(machine, AX, width); + if(width == 32) + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + else + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += ((width / 8) - 1); + break; } - else + perform_adding(machine, dest, source, width, carry); + } + else + { + uint8_t* source = NULL; + uint8_t* dest = NULL; + switch(recalculated_opcode) { - uint8_t* source = NULL; - uint8_t* dest = NULL; - switch(opcode) - { - case 0: //ADD r/m8, r8 + case 0: //OPERATION r/m8, r8 source = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; - case 2: //ADD r8, r/m8 + case 2: //OPERATION r8, r/m8 dest = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; - case 4: //ADD AL, imm8 + case 4: //OPERATION AL, imm8 dest = get_byte_register(machine, AL); source = &(mod_rm_or_immediate); break; - } - perform_adding(machine, dest, source, 8, 0); } + operation(machine, dest, source, 8, carry); + } + return 0; +} + +int16_t parse_and_execute_instruction(v8086* machine) +{ + machine->internal_state.IPOffset = 0; + machine->internal_state.operand_32_bit = 0; + + //Maybe opcode, an be also prefix + uint8_t opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + //Aritmetic operations + //ADD + if(opcode <= 5) + { + perform_artihmetic_or_logical_instruction(machine, opcode, 0, perform_adding); + } + //ADC + else if(opcode >= 0x10 && opcode <= 0x15) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1<> CARRY_FLAG_BIT, perform_adding); } return 0; } \ No newline at end of file From aa30957aa67e4c479ee66548e1a9c6f6ca89fd05 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 15:45:37 +0200 Subject: [PATCH 009/165] Another refactor --- os/kernel/src/v8086/v8086.c | 84 ++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 47 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f16b657c..b76acdda 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -345,55 +345,45 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc { //Maybe Mod/RM, Can be Immediate uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - if(recalculated_opcode % 2) //Odd Opcode means 16 or 32 bit operands - { - uint8_t width = 16; - void* source = NULL; - void* dest = NULL; - if(machine->internal_state.operand_32_bit) width = 32; - switch(recalculated_opcode) - { - case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 - source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); - break; - case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 - dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); - source = get_memory_from_mode(machine, mod_rm_or_immediate, width); - break; - case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 - dest = get_variable_length_register(machine, AX, width); - if(width == 32) - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - else - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += ((width / 8) - 1); - break; - } - perform_adding(machine, dest, source, width, carry); - } - else + machine->internal_state.IPOffset += 1; + + uint8_t width = 16; + void* source = NULL; + void* dest = NULL; + if(!(recalculated_opcode % 2)) width = 8; //Odd Opcode means 16 or 32 bit operands + else if(machine->internal_state.operand_32_bit) width = 32; + switch(recalculated_opcode) { - uint8_t* source = NULL; - uint8_t* dest = NULL; - switch(recalculated_opcode) - { - case 0: //OPERATION r/m8, r8 - source = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - break; - case 2: //OPERATION r8, r/m8 - dest = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); - source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - break; - case 4: //OPERATION AL, imm8 - dest = get_byte_register(machine, AL); - source = &(mod_rm_or_immediate); - break; - } - operation(machine, dest, source, 8, carry); + case 0: //OPERATION r/m8, r8 + source = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + break; + case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 + source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); + break; + case 2: //OPERATION r8, r/m8 + dest = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + break; + case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 + dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + source = get_memory_from_mode(machine, mod_rm_or_immediate, width); + break; + case 4: //OPERATION AL, imm8 + dest = get_byte_register(machine, AL); + source = &(mod_rm_or_immediate); + break; + case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 + dest = get_variable_length_register(machine, AX, width); + if(width == 32) + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + else + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += ((width / 8) - 1); + break; } + perform_adding(machine, dest, source, width, carry); return 0; } From cfe488707648166e527a8907c8bc39ff38e8144b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 16:23:47 +0200 Subject: [PATCH 010/165] Added SUB and SBB operations --- os/kernel/src/v8086/v8086.c | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index b76acdda..20d0036a 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -341,6 +341,37 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, return 0; } +int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return -1; + result = dest_before - (source_before + carry); + bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + if(width == 8) *((uint8_t*)dest) = result & 0xFF; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + else return -1; + return 0; +} + int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { //Maybe Mod/RM, Can be Immediate @@ -407,5 +438,15 @@ int16_t parse_and_execute_instruction(v8086* machine) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1<> CARRY_FLAG_BIT, perform_adding); } + //SBB + else if(opcode >= 0x18 && opcode <= 0x1d) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1<> CARRY_FLAG_BIT, perform_subtracting); + } + //SUB + else if(opcode >= 0x28 && opcode <= 0x2d) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); + } return 0; } \ No newline at end of file From a10523ed5b65a733ea6bd728e834e6937c69d14b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 16:57:25 +0200 Subject: [PATCH 011/165] Added OR and AND operations --- os/kernel/src/v8086/v8086.c | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 20d0036a..99fee518 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -372,6 +372,60 @@ int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t wi return 0; } +int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + { + result = *((uint8_t*)dest) | *((uint8_t*)source); + } else if(width == 16) + { + result = *((uint16_t*)dest) | *((uint16_t*)source); + } else if(width == 32) + { + result = *((uint32_t*)dest) | *((uint32_t*)source); + } + else return -1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFF; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; +} + +int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + { + result = *((uint8_t*)dest) & *((uint8_t*)source); + } else if(width == 16) + { + result = *((uint16_t*)dest) & *((uint16_t*)source); + } else if(width == 32) + { + result = *((uint32_t*)dest) & *((uint32_t*)source); + } + else return -1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFF; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; +} + int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { //Maybe Mod/RM, Can be Immediate @@ -448,5 +502,16 @@ int16_t parse_and_execute_instruction(v8086* machine) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); } + //LOGICAL operations + //OR + if(opcode >= 0x08 && opcode <= 0x0d) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, 0, perform_or); + } + //AND + if(opcode >= 0x20 && opcode <= 0x25) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); + } return 0; } \ No newline at end of file From ff307684233a5fa37db284a9307c2d3751d45bdf Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 17:56:21 +0200 Subject: [PATCH 012/165] Addes XOR and CMP operations --- os/kernel/src/v8086/v8086.c | 74 ++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 99fee518..d4cfe962 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -426,6 +426,60 @@ int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uin else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; } +int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + { + result = *((uint8_t*)dest) ^ *((uint8_t*)source); + } else if(width == 16) + { + result = *((uint16_t*)dest) ^ *((uint16_t*)source); + } else if(width == 32) + { + result = *((uint32_t*)dest) ^ *((uint32_t*)source); + } + else return -1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFF; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; +} + +int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return -1; + result = dest_before - (source_before + carry); + bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + return 0; +} + int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { //Maybe Mod/RM, Can be Immediate @@ -502,16 +556,32 @@ int16_t parse_and_execute_instruction(v8086* machine) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); } + //INC general registers 16 or 32-bit + else if(opcode >= 0x40 && opcode <= 0x47) + { + uint8_t width = 16; + if(machine->) + } //LOGICAL operations //OR - if(opcode >= 0x08 && opcode <= 0x0d) + else if(opcode >= 0x08 && opcode <= 0x0d) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, 0, perform_or); } //AND - if(opcode >= 0x20 && opcode <= 0x25) + else if(opcode >= 0x20 && opcode <= 0x25) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); } + //XOR + else if(opcode >- 0x30 && opcode <= 0x35) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_xor); + } + //CMP + else if(opcode >= 0x38 && opcode <= 0x3d) + { + perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); + } return 0; } \ No newline at end of file From a623c90ddcbb9446dfbee2105225df9b103b93f9 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 18:06:52 +0200 Subject: [PATCH 013/165] Added INC and DEC operations --- os/kernel/src/v8086/v8086.c | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index d4cfe962..4ab49649 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -560,7 +560,51 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode >= 0x40 && opcode <= 0x47) { uint8_t width = 16; - if(machine->) + void* dest = NULL + uint64_t result = 0; + uint32_t dest_before; + if(machine->internal_state.operand_32_bit) width=32; + dest = get_variable_length_register(machine, opcode & 7, width); + if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return -1; + + result = dest_before + 1; + + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + } + //DEC general registers 16 or 32-bit + else if(opcode >= 0x48 && opcode <= 0x4f) + { + uint8_t width = 16; + void* dest = NULL + uint64_t result = 0; + uint32_t dest_before; + if(machine->internal_state.operand_32_bit) width=32; + dest = get_variable_length_register(machine, opcode & 7, width); + if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return -1; + + result = dest_before - 1; + + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; } //LOGICAL operations //OR From bf38f9f8481fa0eab1d5febbbd730f241d89d859 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 20:54:07 +0200 Subject: [PATCH 014/165] Added PUSH and POP GPR opcodes --- os/kernel/src/v8086/v8086.c | 44 ++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 4ab49649..ebd4adb2 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -91,9 +91,23 @@ static inline void push_word(v8086* machine, uint16_t value) write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); } -static inline uint16_t pop_word(v8086* machine, uint16_t value) +static inline void push_dword(v8086* machine, uint32_t value) { - return read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp += 2)); + write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 4), value); +} + +static inline uint16_t pop_word(v8086* machine) +{ + uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + machine->regs.w.sp += 2; + return v; +} + +static inline uint32_t pop_word(v8086* machine) +{ + uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + machine->regs.w.sp += 4; + return v; } v8086* v8086_create_machine() @@ -599,7 +613,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t parrity = result & 1; for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG @@ -627,5 +641,29 @@ int16_t parse_and_execute_instruction(v8086* machine) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); } + //PUSH Operations + //PUSH General purpose registers + else if(opcode >= 0x50 && opcode <= 0x57) + { + uint8_t width = 16; + void* reg = NULL; + if(machine->internal_state.operand_32_bit) width = 16; + reg = get_variable_length_register(machine, opcode & 7, width); + if(width==16) push_word(machine, *((uint16_t)reg)); + else if(width==32) push_dword(machine, *((uint32_t)reg)); + else return -1; + } + //POP Operations + //POP General purpose registers + else if(opcode >= 0x50 && opcode <= 0x57) + { + uint8_t width = 16; + void* reg = NULL; + if(machine->internal_state.operand_32_bit) width = 16; + reg = get_variable_length_register(machine, opcode & 7, width); + if(width==16) *((uint16_t)reg)) = pop_word(machine); + else if(width==32) *((uint32_t)reg)) pop_dword(machine); + else return -1; + } return 0; } \ No newline at end of file From 1f4838b09b66de4ae10268c02553107cbce48168 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 22:16:19 +0200 Subject: [PATCH 015/165] Refactored types do sregs, Added PUSH for CS DS ES SS and POP DS ES SS --- os/kernel/src/v8086/v8086.c | 21 +++++++++++++++++++++ os/kernel/src/v8086/v8086.h | 12 ++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index ebd4adb2..2107c2ce 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -653,6 +653,18 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width==32) push_dword(machine, *((uint32_t)reg)); else return -1; } + //PUSH CS + else if(opcode == 0x0e) + push_word(machine, machine->sregs.cs); + //PUSH DS + else if(opcode == 0x1e) + push_word(machine, machine->sregs.ds); + //PUSH ES + else if(opcode == 0x06) + push_word(machine, machine->sregs.es); + //PUSH SS + else if(opcode == 0x16) + push_word(machine, machine->sregs.ss); //POP Operations //POP General purpose registers else if(opcode >= 0x50 && opcode <= 0x57) @@ -665,5 +677,14 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width==32) *((uint32_t)reg)) pop_dword(machine); else return -1; } + //POP DS + else if(opcode == 0x1f) + machine->sregs.ds = pop_word(machine); + //POP ES + else if(opcode == 0x07) + machine->sregs.es = pop_word(machine); + //POP SS + else if(opcode == 0x17) + machine->sregs.ss = pop_word(machine); return 0; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index c5945c4a..d887b42e 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -58,12 +58,12 @@ union REGS { /* Compatible with DPMI structure, except cflag */ }; struct SREGS { - unsigned short es; - unsigned short ds; - unsigned short fs; - unsigned short gs; - unsigned short cs; - unsigned short ss; + uint16_t es; + uint16_t ds; + uint16_t fs; + uint16_t gs; + uint16_t cs; + uint16_t ss; }; typedef struct _is{ From c2707c83e8f16d382b623c1d47f6d00eacd65059 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 1 May 2020 23:05:07 +0200 Subject: [PATCH 016/165] Added XCHG for GPR --- os/kernel/src/v8086/v8086.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 2107c2ce..77aea18b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -686,5 +686,31 @@ int16_t parse_and_execute_instruction(v8086* machine) //POP SS else if(opcode == 0x17) machine->sregs.ss = pop_word(machine); + //XCHG group + //XCHG GRP with AX or EAX + else if(opcode >= 90 && opcode <= 97) + { + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + if(width == 16) + { + uint16_t temp; + uint16_t* regA = get_word_register(machine, AX); + uint16_t* regB = get_word_register(machine, opcode & 7); + temp = *regA; + *regA = *regB; + *regB = temp; + } + else if(width == 32) + { + uint16_t temp; + uint16_t* regA = get_dword_register(machine, EAX); + uint16_t* regB = get_dword_register(machine, opcode & 7); + temp = *regA; + *regA = *regB; + *regB = temp; + } + else return -1; + } return 0; } \ No newline at end of file From 32dcae59a14c81554161e0ef5df6cd7a78c9c4a6 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 May 2020 00:50:36 +0200 Subject: [PATCH 017/165] Added segment prefixes opcodes --- os/kernel/src/v8086/v8086.c | 101 ++++++++++++++++++++++++++---------- os/kernel/src/v8086/v8086.h | 5 ++ 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 77aea18b..50769401 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -233,31 +233,71 @@ void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t wi } } +uint16_t* select_segment_register(v8086* machine, segment_register_select select) +{ + switch(select) + { + case CS: + return &(machine->sregs.cs) + case DS: + return &(machine->sregs.cs) + case SS: + return &(machine->sregs.cs) + case ES: + return &(machine->sregs.cs) + default: + return NULL; + } +} + void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) { + uint16_t* segment_register = NULL; + if(machine->internal_state.segment_reg_select != DEFAULT) + segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); + else + { + switch (mod_rm & 7) + { + case 0: + case 1: + case 4: + case 5: + case 7: + segment_register = select_segment_register(machine, DS); + break; + case 6: + if((mod_rm >> 6) == 0) segment_register = select_segment_register(machine, DS); + else segment_register = select_segment_register(machine, SS); + default: + break; + } + } + + switch(mod_rm >> 6) //Parsing mod than parsing rm { case 0: switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si), width); case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di), width); case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si), width); case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di), width); case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si), width); case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di), width); case 6:{ - void* ptr = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset)))), width); + void* ptr = get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset)))), width); machine->internal_state.IPOffset += 1; return ptr; } case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx), width); default: return NULL; } @@ -266,21 +306,21 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) machine->internal_state.IPOffset += 1; switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si + disp), width); case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di + disp), width); case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si + disp), width); case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di + disp), width); case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si + disp), width); case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di + disp), width); case 6: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + disp), width); case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + disp), width); default: return NULL; } @@ -290,21 +330,21 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) machine->internal_state.IPOffset += 2; switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si + disp), width); case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di + disp), width); case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si + disp), width); case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di + disp), width); case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.si + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si + disp), width); case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.di + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di + disp), width); case 6: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.x.bp + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + disp), width); case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.ds, machine->regs.x.bx + disp), width); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + disp), width); default: return NULL; } @@ -544,14 +584,23 @@ int16_t parse_and_execute_instruction(v8086* machine) { machine->internal_state.IPOffset = 0; machine->internal_state.operand_32_bit = 0; + machine->internal_state.segment_reg_select = DEFAULT; //Maybe opcode, an be also prefix - uint8_t opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t opcode; + decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; + //PREFIXES + //Segment Prefix + if((opcode & 0x7) == 0x6 && ((opcode >> 5) & 0x7) == 0x1) //001XX110 + { + machine->internal_state.segment_reg_select = (opcode >> 3) & 0x3; + goto decode; //continue parsing opcode; + } //Aritmetic operations //ADD - if(opcode <= 5) + else if(opcode <= 5) { perform_artihmetic_or_logical_instruction(machine, opcode, 0, perform_adding); } diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index d887b42e..ddcbf492 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -3,6 +3,10 @@ #include +typedef enum _segment_register_select { + ES, CS, SS, DS, DEFAULT +} segment_register_select; + struct DWORDREGS { uint32_t edi; uint32_t esi; @@ -68,6 +72,7 @@ struct SREGS { typedef struct _is{ uint32_t operand_32_bit; + segment_register_select segment_reg_select; uint16_t IPOffset; } _internal_state; From 508319051c423f57c480bc543a34c0e955733d7b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 May 2020 01:03:52 +0200 Subject: [PATCH 018/165] Corrected mistakes, added sement overrides for FS and GS --- os/kernel/src/v8086/v8086.c | 28 ++++++++++++++++++++++------ os/kernel/src/v8086/v8086.h | 2 +- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 50769401..1841d67a 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -238,13 +238,17 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select switch(select) { case CS: - return &(machine->sregs.cs) + return &(machine->sregs.cs); case DS: - return &(machine->sregs.cs) + return &(machine->sregs.ds); case SS: - return &(machine->sregs.cs) + return &(machine->sregs.ss); case ES: - return &(machine->sregs.cs) + return &(machine->sregs.es); + case FS: + return &(machine->sregs.fs); + case FS: + return &(machine->sregs.gs); default: return NULL; } @@ -592,12 +596,24 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; //PREFIXES - //Segment Prefix - if((opcode & 0x7) == 0x6 && ((opcode >> 5) & 0x7) == 0x1) //001XX110 + //Segment Prefix CS DS ES SS + if((opcode & 0x7) == 0x6 && ((opcode >> 5) & 0x7) == 0x1) //001XX110 pattern where XX is number of segment { machine->internal_state.segment_reg_select = (opcode >> 3) & 0x3; goto decode; //continue parsing opcode; } + //Segment Prefix FS + else if(opcode == 0x64) + { + machine->internal_state.segment_reg_select = FS; + goto decode; //continue parsing opcode; + } + //Segment Prefix FS + else if(opcode == 0x64) + { + machine->internal_state.segment_reg_select = GS; + goto decode; //continue parsing opcode; + } //Aritmetic operations //ADD else if(opcode <= 5) diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index ddcbf492..a70ec826 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -4,7 +4,7 @@ #include typedef enum _segment_register_select { - ES, CS, SS, DS, DEFAULT + ES, CS, SS, DS, FS, GS, DEFAULT } segment_register_select; struct DWORDREGS { From e30a1c1bd3ce811dbe24d7a078c5d1e8935c4316 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 May 2020 01:10:38 +0200 Subject: [PATCH 019/165] Corrected mistake in GS Segment prefix opcode number and added Operand Size prefix --- os/kernel/src/v8086/v8086.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 1841d67a..1fd54dcf 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -609,11 +609,17 @@ int16_t parse_and_execute_instruction(v8086* machine) goto decode; //continue parsing opcode; } //Segment Prefix FS - else if(opcode == 0x64) + else if(opcode == 0x65) { machine->internal_state.segment_reg_select = GS; goto decode; //continue parsing opcode; } + //Operand Size Prefix + else if(opcode == 0x66) + { + machine->internal_state.operand_32_bit = 1; + goto decode; + } //Aritmetic operations //ADD else if(opcode <= 5) From 6025360a23b6d84364377840e33508264e729c12 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 May 2020 16:31:05 +0200 Subject: [PATCH 020/165] Added Short Jumps --- os/kernel/src/v8086/v8086.c | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 1fd54dcf..aef27a36 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -608,7 +608,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.segment_reg_select = FS; goto decode; //continue parsing opcode; } - //Segment Prefix FS + //Segment Prefix GS else if(opcode == 0x65) { machine->internal_state.segment_reg_select = GS; @@ -618,7 +618,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0x66) { machine->internal_state.operand_32_bit = 1; - goto decode; + goto decode; //continue parsing opcode; } //Aritmetic operations //ADD @@ -783,5 +783,67 @@ int16_t parse_and_execute_instruction(v8086* machine) } else return -1; } + //SHORT JUMPS + else if(opcode >= 0x70 && opcode <= 0x7f) + { + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint32_t tempIP = machine->IP; + uint8_t jump = 0; + switch(opcode & 0x0f) + { + case 0: //JO + if(bit_get(machine->regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1< 0xFFFF) return -1; + machine->IP = tempIP; + } return 0; } \ No newline at end of file From 1752918248af152edd9e5d7d88881a4ed4af3afb Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 May 2020 17:28:44 +0200 Subject: [PATCH 021/165] Added MOV reg imm for 8, 16 and 32 --- os/kernel/src/v8086/v8086.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index aef27a36..fd096217 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -845,5 +845,31 @@ int16_t parse_and_execute_instruction(v8086* machine) if(tempIP > 0xFFFF) return -1; machine->IP = tempIP; } + //MOV r8, imm8 + else if(opcode >= 0xb0 && opcode <= 0xb7) + { + uint8_t* reg = get_byte_register(machine, opcode & 0x7); + uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + *reg = imm; + } + //MOV r16, imm16 or r32, imm32 + else if(opcode >= 0xb8 && opcode <= 0xbf) + { + if(machine->internal_state.operand_32_bit) + { + uint32_t* reg = get_dword_register(machine, (opcode - 0xb8) & 0x7); + uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + *reg = imm; + } + else + { + uint16_t* reg = get_word_register(machine, (opcode - 0xb8) & 0x7); + uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + *reg = imm; + } + } return 0; } \ No newline at end of file From 8c31bf97820667fbd5adc5f7331ff258c044196c Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 00:37:39 +0200 Subject: [PATCH 022/165] Corrected Mistakes and added TEST r, r/m --- os/kernel/src/v8086/v8086.c | 60 ++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index fd096217..d8498437 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -247,7 +247,7 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select return &(machine->sregs.es); case FS: return &(machine->sregs.fs); - case FS: + case GS: return &(machine->sregs.gs); default: return NULL; @@ -645,7 +645,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode >= 0x40 && opcode <= 0x47) { uint8_t width = 16; - void* dest = NULL + void* dest = NULL; uint64_t result = 0; uint32_t dest_before; if(machine->internal_state.operand_32_bit) width=32; @@ -663,14 +663,14 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; } //DEC general registers 16 or 32-bit else if(opcode >= 0x48 && opcode <= 0x4f) { uint8_t width = 16; - void* dest = NULL + void* dest = NULL; uint64_t result = 0; uint32_t dest_before; if(machine->internal_state.operand_32_bit) width=32; @@ -688,7 +688,7 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; } //LOGICAL operations @@ -720,8 +720,8 @@ int16_t parse_and_execute_instruction(v8086* machine) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; reg = get_variable_length_register(machine, opcode & 7, width); - if(width==16) push_word(machine, *((uint16_t)reg)); - else if(width==32) push_dword(machine, *((uint32_t)reg)); + if(width==16) push_word(machine, *((uint16_t*)reg)); + else if(width==32) push_dword(machine, *((uint32_t*)reg)); else return -1; } //PUSH CS @@ -744,8 +744,8 @@ int16_t parse_and_execute_instruction(v8086* machine) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; reg = get_variable_length_register(machine, opcode & 7, width); - if(width==16) *((uint16_t)reg)) = pop_word(machine); - else if(width==32) *((uint32_t)reg)) pop_dword(machine); + if(width==16) *((uint16_t*)reg) = pop_word(machine); + else if(width==32) *((uint32_t*)reg) = pop_dword(machine); else return -1; } //POP DS @@ -802,7 +802,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(bit_get(machine->regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1< 0xFFFF) return -1; machine->IP = tempIP; } + //MOV Group //MOV r8, imm8 else if(opcode >= 0xb0 && opcode <= 0xb7) { @@ -871,5 +872,44 @@ int16_t parse_and_execute_instruction(v8086* machine) *reg = imm; } } + //TEST GROUP + else if(opcode == 0x84) + { + //Mod/RM + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t* reg = get_byte_register(machine, (mod_rm >> 3) & 7); + uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); + uint8_t result = *reg & *memory; + bit_clear(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG + } + else if(opcode == 0x85) + { + //Mod/RM + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + uint32_t result; + void* source = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + void* dest = get_memory_from_mode(machine, mod_rm, width); + + if(width == 16) + result = *((uint16_t*) source) & *((uint16_t*) dest); + else if(width == 32) + result = *((uint32_t*) source) & *((uint32_t*) dest); + + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + } return 0; } \ No newline at end of file From 5f2542b0060be1ef64792b3288c00ff643298b0f Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 01:03:58 +0200 Subject: [PATCH 023/165] Added TEST with Immediates --- os/kernel/src/v8086/v8086.c | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index d8498437..a29a528f 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -911,5 +911,51 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG } + else if(opcode == 0xa8) + { + //Mod/RM + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t* reg = get_byte_register(machine, AL); + uint8_t result = *reg & immediate; + bit_clear(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG + } + else if(opcode == 0xa9) + { + //Mod/RM + uint32_t immediate; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + uint32_t result; + if(width == 16) + { + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } + else if(width == 32) + { + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + } + + void* reg = get_variable_length_register(machine, AX, width); + + if(width == 16) + result = *((uint16_t*) reg) & immediate; + else if(width == 32) + result = *((uint32_t*) reg) & immediate; + + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + } return 0; } \ No newline at end of file From be984a0ded230492fb3a460af5ca9f0ffe1ea302 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 01:41:08 +0200 Subject: [PATCH 024/165] Added MOV AL/AX/EAX, moffs8/moffs16/moffs32 --- os/kernel/src/v8086/v8086.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index a29a528f..e3722656 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -71,11 +71,21 @@ static inline uint32_t read_dword_from_pointer(uint8_t* memory, uint16_t offset) return *get_dword_pointer(memory, offset); } +static inline void write_byte_to_pointer(uint8_t* memory, uint16_t offset, uint8_t value) +{ + *(get_byte_pointer(memory, offset)) = value; +} + static inline void write_word_to_pointer(uint8_t* memory, uint16_t offset, uint16_t value) { *(get_word_pointer(memory, offset)) = value; } +static inline void write_dword_to_pointer(uint8_t* memory, uint16_t offset, uint32_t value) +{ + *(get_dword_pointer(memory, offset)) = value; +} + static inline uint16_t read_word_from_double_pointer(uint8_t* memory, uint16_t offset) { return *(get_word_pointer(memory, read_word_from_pointer(memory, offset))); @@ -872,6 +882,31 @@ int16_t parse_and_execute_instruction(v8086* machine) *reg = imm; } } + //MOV AL/AX/EAX, moffs8/moffs16/moffs32 + else if(opcode >= 0xa0 &&& opcode <= 0xa3) + { + uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + uint16_t segment = *select_segment_register(machine, DS) ? machine->internal_state.segment_reg_select == DEFAULT : *select_segment_register(machine, machine->internal_state.segment_reg_select); + + switch (opcode) + { + case 0xa0: + machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(segment, offset)); + break; + case 0xa1: + if(machine->internal_state.operand_32_bit) machine->regs.d.eax = read_dword_from_pointer(machine->Memory, get_absolute_address(segment, offset)); + else machine->regs.x.ax = read_word_from_pointer(machine->Memory, get_absolute_address(segment, offset)); + break; + case 0xa2: + write_byte_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.h.al); + break; + case 0xa3: + if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.d.eax); + else write_word_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.x.ax); + break; + } + } //TEST GROUP else if(opcode == 0x84) { From 6ad8cf28664584c74e3a7301a822065fb7374955 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 01:42:34 +0200 Subject: [PATCH 025/165] Corrected annotation - missing MOV moffs8/moffs16/moffs32, AL/AX/EAX --- os/kernel/src/v8086/v8086.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e3722656..48210b80 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -882,7 +882,7 @@ int16_t parse_and_execute_instruction(v8086* machine) *reg = imm; } } - //MOV AL/AX/EAX, moffs8/moffs16/moffs32 + //MOV AL/AX/EAX, moffs8/moffs16/moffs32 or MOV moffs8/moffs16/moffs32, AL/AX/EAX else if(opcode >= 0xa0 &&& opcode <= 0xa3) { uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); From 1e5c7a8e89720eddc8793391f6090f81ab1b2a62 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 02:10:53 +0200 Subject: [PATCH 026/165] Added MOV r8/r16/r32, rm8/rm16/rm32 and MOV rm8/rm16/rm32, r8/r16/r32 --- os/kernel/src/v8086/v8086.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 48210b80..63cbf381 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -883,7 +883,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } } //MOV AL/AX/EAX, moffs8/moffs16/moffs32 or MOV moffs8/moffs16/moffs32, AL/AX/EAX - else if(opcode >= 0xa0 &&& opcode <= 0xa3) + else if(opcode >= 0xa0 && opcode <= 0xa3) { uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; @@ -907,6 +907,41 @@ int16_t parse_and_execute_instruction(v8086* machine) break; } } + //MOV r8/r16/r32, rm8/rm16/rm32 or MOV rm8/rm16/rm32, r8/r16/r32 + else if(opcode >= 0x88 && opcode <= 0x8b) + { + //Mod/RM + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + void* source = NULL; + void* dest = NULL; + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + switch (opcode) + { + case 0x88: + source = get_byte_register(machine, (mod_rm >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm, 8); + *((uint8_t*)dest) = *((uint8_t*) source); + break; + case 0x89: + source = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + dest = get_memory_from_mode(machine, mod_rm, width); + if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); + else *((uint32_t*)dest) = *((uint32_t*) source); + break; + case 0x8a: + dest = get_byte_register(machine, (mod_rm >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm, 8); + *((uint8_t*)dest) = *((uint8_t*) source); + break; + case 0x8b: + dest = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + source = get_memory_from_mode(machine, mod_rm, width); + if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); + else *((uint32_t*)dest) = *((uint32_t*) source); + break; + } + } //TEST GROUP else if(opcode == 0x84) { From 83b9be21f73f90706080ac5c33bade9893a669f2 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 3 May 2020 21:39:52 +0200 Subject: [PATCH 027/165] added MOV segment register to/from rm --- os/kernel/src/v8086/v8086.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 63cbf381..21580cf0 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -284,6 +284,7 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) if((mod_rm >> 6) == 0) segment_register = select_segment_register(machine, DS); else segment_register = select_segment_register(machine, SS); default: + segment_register = select_segment_register(machine, SS); break; } } @@ -942,6 +943,25 @@ int16_t parse_and_execute_instruction(v8086* machine) break; } } + //MOV Segment to/from r/m + else if(opcode == 0x8c || opcode == 0x8e) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint16_t* source = NULL; + uint16_t* dest = NULL; + if(opcode == 0x8c) + { + source = select_segment_register(machine, (mod_rm >> 3) & 7); + dest = get_memory_from_mode(machine, mod_rm, 16); + } + else + { + dest = select_segment_register(machine, (mod_rm >> 3) & 7); + source = get_memory_from_mode(machine, mod_rm, 16); + } + *dest = *source; + } //TEST GROUP else if(opcode == 0x84) { From da260d65bc2fd3d2f358278659b16d2ddd6b0863 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Mon, 4 May 2020 00:06:07 +0200 Subject: [PATCH 028/165] Added MOV rm, imm --- os/kernel/src/v8086/v8086.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 21580cf0..2355468e 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -962,6 +962,38 @@ int16_t parse_and_execute_instruction(v8086* machine) } *dest = *source; } + //MOV rm, imm + else if(opcode >= 0xc6 && opcode <= 0xc7) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(opcode == 0xc6) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); + *mem = immediate; + } + else + { + if(machine->internal_state.operand_32_bit) + { + uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); + *mem = immediate; + } + else + { + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); + *mem = immediate; + } + + } + + } //TEST GROUP else if(opcode == 0x84) { From 8e5b1f4779f3111b7729dc96b62351240e2a2b62 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 5 May 2020 23:44:59 +0200 Subject: [PATCH 029/165] Added XCHG r8, rm8 or XCHG r16, rm16 or XCHG r32, rm32 --- os/kernel/src/v8086/v8086.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 2355468e..10646b94 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -794,6 +794,43 @@ int16_t parse_and_execute_instruction(v8086* machine) } else return -1; } + //XCHG r8, rm8 or XCHG r16, rm16 or XCHG r32, rm32 + else if(opcode >= 0x86 && opcode <= 0x87) + { + int8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(opcode == 0x86) + { + uint8_t* source = get_byte_register(machine, (mod_rm >> 3) & 7); + uint8_t* dest = get_memory_from_mode(machine, mod_rm, 8); + uint8_t temp; + temp = *source; + *source = *dest; + *dest = temp; + } + else if(opcode == 0x87) + { + if(machine->internal_state.operand_32_bit) + { + uint32_t* source = get_dword_register(machine, (mod_rm >> 3) & 7); + uint32_t* dest = get_memory_from_mode(machine, mod_rm, 32); + uint32_t temp; + temp = *source; + *source = *dest; + *dest = temp; + } + else + { + uint16_t* source = get_word_register(machine, (mod_rm >> 3) & 7); + uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); + uint16_t temp; + temp = *source; + *source = *dest; + *dest = temp; + } + + } + } //SHORT JUMPS else if(opcode >= 0x70 && opcode <= 0x7f) { From a045c2a6afb2154a404fd0ef8b31b9e2b4eedeb8 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 6 May 2020 23:41:20 +0200 Subject: [PATCH 030/165] Ommiting Lock Prefix and Added REPNE and REP/REPE Prefix --- os/kernel/src/v8086/v8086.c | 18 ++++++++++++++++++ os/kernel/src/v8086/v8086.h | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 10646b94..d4b7c280 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -600,6 +600,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset = 0; machine->internal_state.operand_32_bit = 0; machine->internal_state.segment_reg_select = DEFAULT; + machine->internal_state.rep_prefix = NONE; //Maybe opcode, an be also prefix uint8_t opcode; @@ -631,6 +632,23 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.operand_32_bit = 1; goto decode; //continue parsing opcode; } + //REPNE Prefix + else if(opcode == 0xF2) + { + machine->internal_state.rep_prefix = REPNE; + goto decode; //continue parsing opcode; + } + //REP/REPE Prefix + else if(opcode == 0xF3) + { + machine->internal_state.rep_prefix = REP_REPE; + goto decode; //continue parsing opcode; + } + //LOCK Prefix + else if(opcode == 0xF0) + { + goto decode; //ommit prefix, contniue parsinf opcode; + } //Aritmetic operations //ADD else if(opcode <= 5) diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index a70ec826..a2aaaead 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -7,6 +7,10 @@ typedef enum _segment_register_select { ES, CS, SS, DS, FS, GS, DEFAULT } segment_register_select; +typedef enum _repeat_prefix { + NONE, REPNE, REP_REPE +} repeat_prefix; + struct DWORDREGS { uint32_t edi; uint32_t esi; @@ -73,6 +77,7 @@ struct SREGS { typedef struct _is{ uint32_t operand_32_bit; segment_register_select segment_reg_select; + repeat_prefix rep_prefix; uint16_t IPOffset; } _internal_state; From 3b06e970e2cff24b55202b823725e6ad4dcf85da Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 00:29:50 +0200 Subject: [PATCH 031/165] Added MOVSB MOVSW MOVSD --- os/kernel/src/v8086/v8086.c | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index d4b7c280..5ece924c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -13,6 +13,7 @@ #define AUX_CARRY_FLAG_BIT 4 #define ZERO_FLAG_BIT 6 #define SIGN_FLAG_BIT 7 +#define DIRECTION_FLAG_BIT 10 #define OVERFLOW_FLAG_BIT 11 enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; @@ -1134,5 +1135,58 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG } + //STRING GROUP + //MOVSB + else if(opcode==0xA4) + { + uint16_t* source_segment; + uint16_t* dest_segment = select_segment_register(machine, ES); + uint8_t* source; + uint8_t* dest; + if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; + + do{ + source = get_byte_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); + dest = get_byte_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); + *dest = *source; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -1 : 1; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -1 : 1; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } + //MOVSW or MOVSD + else if(opcode == 0xA5) + { + uint16_t* source_segment; + uint16_t* dest_segment = select_segment_register(machine, ES); + if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; + + if(machine->internal_state.operand_32_bit) + do{ + uint32_t* source = get_dword_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); + uint32_t* dest = get_dword_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); + *dest = *source; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -4 : 4; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -4 : 4; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + else + do{ + uint16_t* source = get_word_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); + uint16_t* dest = get_word_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); + *dest = *source; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -2 : 2; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -2 : 2; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + + } + recalculate_ip: machine->IP += machine->internal_state.IPOffset; + return 0; } \ No newline at end of file From 6e8d18713e97ab4d506917a9097c7daab679af6d Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 01:24:22 +0200 Subject: [PATCH 032/165] ADDED CMPSB, CMPSW, CMPSD --- os/kernel/src/v8086/v8086.c | 54 ++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 5ece924c..4d837741 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -538,7 +538,7 @@ int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uin dest_before = *((uint32_t*)dest); source_before = *((uint32_t*)source); } else return -1; - result = dest_before - (source_before + carry); + result = dest_before - source_before; bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG uint8_t parrity = result & 1; @@ -1186,6 +1186,58 @@ int16_t parse_and_execute_instruction(v8086* machine) } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } + //CMPSB or CMPSW or CMPSD + else if(opcode >= 0xA6 && opcode <= 0xA7) + { + uint16_t* source_segment; + uint16_t* dest_segment = select_segment_register(machine, ES); + void* source; + void* dest; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + uint64_t result; + uint8_t width = 8; + if(opcode == 0xA7) + if(machine->internal_state.operand_32_bit) width=32; + else width = 16; + + if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; + + do{ + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + dest = get_varaible_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return -1; + + result = dest_before - source_before; + bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + + machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; + else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; + } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 160d1f3f89ad6b806ab6e09e543d305e1f9cbeae Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 01:51:16 +0200 Subject: [PATCH 033/165] Added STOSB STOSW STOSD LOADB LOADW LOADD --- os/kernel/src/v8086/v8086.c | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 4d837741..23e5debe 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1238,6 +1238,61 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); } + //STOSB STOSW STOSD + else if(opcode >= 0xAA && opcode <= 0xAB) + { + uint16_t* segment = select_segment_register(machine, ES); + void* source; + void* dest; + uint8_t width = 8; + if(opcode == 0xA7) + if(machine->internal_state.operand_32_bit) width=32; + else width = 16; + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; + + do{ + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); + source = get_variable_length_register(machine, AL, width); + + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return -1; + + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } + //LOADB LOADW LOADD + else if(opcode >= 0xAC && opcode <= 0xAD) + { + uint16_t* segment; + void* source; + void* dest; + uint8_t width = 8; + if(opcode == 0xA7) + if(machine->internal_state.operand_32_bit) width=32; + else width = 16; + + if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); + else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; + + do{ + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); + dest = get_variable_length_register(machine, AL, width); + + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return -1; + + machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From e56e70950622b50aaa5eb5fd87fc64106ec81382 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 02:03:08 +0200 Subject: [PATCH 034/165] Added SCASB SCASW SCADD --- os/kernel/src/v8086/v8086.c | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 23e5debe..ef4ff63e 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1293,6 +1293,53 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } + //SCASB or SCASW or SCADD + else if(opcode >= 0xAE && opcode <= 0xAF) + { + uint16_t* source_segment = select_segment_register(machine, ES); + void* source; + void* dest; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + uint64_t result; + uint8_t width = 8; + if(opcode == 0xA7) + if(machine->internal_state.operand_32_bit) width=32; + else width = 16; + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; + + do{ + dest = get_variable_length_register(machine, AX, width); + source = get_varaible_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return -1; + + result = dest_before - source_before; + bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1; + for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + + machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; + else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; + } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 7fd50e941d259549ee3934b20c2df4b215625a7d Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 15:09:39 +0200 Subject: [PATCH 035/165] Added Ascii Adjustments --- os/kernel/src/v8086/v8086.c | 119 ++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index ef4ff63e..68604369 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1340,6 +1340,125 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); } + //ASCII ADJUSTMENT + //AAA + else if(opcode == 0x37) + { + if(((machine->regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.x.ax += 0x106; + bit_set(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.h.al &= 0x0f; + } + //AAS + else if(opcode == 0x3F) + { + if(((machine->regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.h.al -= 0x6; + machine->regs.h.ah -= 1; + bit_set(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.h.al &= 0x0f; + } + //DAA + else if(opcode == 0x27) + { + uint8_t old_AL = machine->regs.h.al; + uint16_t old_cf = bit_get(machine->regs.w.flags, 1<regs.w.flags, 1<regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.h.al + 6; + machine->regs.h.al = temp_ax & 0xFF; + bit_write(machine->regs.w.flags, 1< 0xFF)) ? 1 : 0); + bit_set(machine->regs.w.flags, 1<regs.w.flags, 1< 0x99) || old_cf) + { + machine->regs.h.al += 0x60; + bit_set(machine->regs.w.flags, 1<regs.w.flags, 1<regs.h.al & 1; + for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + } + //DAS + else if(opcode == 0x2f) + { + uint8_t old_AL = machine->regs.h.al; + uint16_t old_cf = bit_get(machine->regs.w.flags, 1<regs.w.flags, 1<regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.h.al - 6; + machine->regs.h.al = temp_ax & 0xFF; + bit_write(machine->regs.w.flags, 1< 0xFF)) ? 1 : 0); + bit_set(machine->regs.w.flags, 1<regs.w.flags, 1< 0x99) || old_cf) + { + machine->regs.h.al -= 0x60; + bit_set(machine->regs.w.flags, 1<regs.h.al & 1; + for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + } + //AAM + else if(opcode == 0xd4) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t tempAL = machine->regs.h.al; + machine->regs.h.ah = tempAL / immediate; + machine->regs.h.al = tempAL % immediate; + + uint8_t parrity = machine->regs.h.al & 1; + for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + } + //AAD + else if(opcode == 0xd5) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t tempAL = machine->regs.h.al; + uint8_t tempAH = machine->regs.h.ah; + + machine->regs.h.al = (tempAL + (tempAH * immediate)) & 0xFF; + machine->regs.h.ah = 0; + + uint8_t parrity = machine->regs.h.al & 1; + for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; + bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 2997f32c04c186f48162aefb8bd66749b176acb3 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 16:32:51 +0200 Subject: [PATCH 036/165] Refactor od get_memory_from_mode function --- os/kernel/src/v8086/v8086.c | 102 +++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 31 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 68604369..5bb700ac 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -265,7 +265,7 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select } } -void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) +int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset) { uint16_t* segment_register = NULL; if(machine->internal_state.segment_reg_select != DEFAULT) @@ -289,56 +289,71 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) break; } } - + + *segment = *segment_register; switch(mod_rm >> 6) //Parsing mod than parsing rm { case 0: switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si), width); + *offset = machine->regs.x.bx + machine->regs.x.si; + return 0; case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di), width); + *offset = machine->regs.x.bx + machine->regs.x.di; + return 0; case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si), width); + *offset = machine->regs.x.bp + machine->regs.x.si; + return 0; case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di), width); + *offset = machine->regs.x.bp + machine->regs.x.di; + return 0; case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si), width); + *offset = machine->regs.x.si; + return 0; case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di), width); + *offset = machine->regs.x.di; + return 0; case 6:{ - void* ptr = get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset)))), width); + *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset))); machine->internal_state.IPOffset += 1; - return ptr; + return 0; } case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx), width); + *offset = machine->regs.x.bx; default: - return NULL; + return -1; } case 1:{ int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si + disp), width); + *offset = machine->regs.x.bx + machine->regs.x.si + disp; + return 0; case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di + disp), width); + *offset = machine->regs.x.bx + machine->regs.x.di + disp; + return 0; case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si + disp), width); + *offset = machine->regs.x.bp + machine->regs.x.si + disp; + return 0; case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di + disp), width); + *offset = machine->regs.x.bp + machine->regs.x.di + disp; + return 0; case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si + disp), width); + *offset = machine->regs.x.si + disp; + return 0; case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di + disp), width); + *offset = machine->regs.x.di + disp; + return 0; case 6: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + disp), width); + *offset = machine->regs.x.bp + disp; + return 0; case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + disp), width); + *offset = machine->regs.x.bx + disp; + return 0; default: - return NULL; + return -1; } } case 2:{ @@ -346,25 +361,50 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) machine->internal_state.IPOffset += 2; switch(mod_rm & 7){ case 0: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.si + disp), width); + *offset = machine->regs.x.bx + machine->regs.x.si + disp; + return 0; case 1: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + machine->regs.x.di + disp), width); + *offset = machine->regs.x.bx + machine->regs.x.di + disp; + return 0; case 2: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.si + disp), width); + *offset = machine->regs.x.bp + machine->regs.x.si + disp; + return 0; case 3: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + machine->regs.x.di + disp), width); + *offset = machine->regs.x.bp + machine->regs.x.di + disp; + return 0; case 4: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.si + disp), width); + *offset = machine->regs.x.si + disp; + return 0; case 5: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.di + disp), width); + *offset = machine->regs.x.di + disp; + return 0; case 6: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bp + disp), width); + *offset = machine->regs.x.bp + disp; + return 0; case 7: - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment_register, machine->regs.x.bx + disp), width); + *offset = machine->regs.x.bx + disp; + return 0; default: - return NULL; + return -1; } } + return -1; + } + +} + +void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) +{ + uint16_t segment; + uint16_t offset; + + switch(mod_rm >> 6) //Parsing mod than parsing rm + { + case 0: + case 1: + case 2: + calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); case 3: switch(width){ case 8: @@ -1452,7 +1492,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.h.al = (tempAL + (tempAH * immediate)) & 0xFF; machine->regs.h.ah = 0; - + uint8_t parrity = machine->regs.h.al & 1; for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; bit_write(machine->regs.d.eflags, 1< Date: Thu, 7 May 2020 21:33:18 +0200 Subject: [PATCH 037/165] Added LEA LES and LDS --- os/kernel/src/v8086/v8086.c | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 5bb700ac..1ffd10fd 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1499,6 +1499,58 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG } + //LOAD Operations + //LEA + else if(opcode == 0x8d) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + uint16_t segment; + uint16_t offset; + + if((mod_rm >> 6) > 3) return -1; + + int16_t r = calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + if(r) return r; + + if(machine->internal_state.operand_32_bit) + { + uint32_t* reg = get_dword_register(machine, (mod_rm>>3)&7); + *reg = offset; + } + else + { + uint16_t* reg = get_word_register(machine, (mod_rm>>3)&7); + *reg = offset; + } + } + //LDS or LES + else if(opcode >= 0xc4 && opcode <= 0xc5) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + uint16_t* segment_register; + if(opcode == 0xc4) segment_register = select_segment_register(machine, ES); + else segment_register = select_segment_register(machine, DS); + + uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); + + if(machine->internal_state.operand_32_bit) + { + uint16_t* dest = get_dword_register(machine, (mod_rm >> 3) & 7); + *dest = *((uint32_t*) source); + *segment_register = *(source+2); + } + else + { + uint16_t* dest = get_word_register(machine, (mod_rm >> 3) & 7); + *dest = *source; + *segment_register = *(source+1); + } + + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 22d42d94f4cf8379cdd0dbd5d729a831365a6759 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 21:44:46 +0200 Subject: [PATCH 038/165] PUSHF and POPF --- os/kernel/src/v8086/v8086.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 1ffd10fd..f755ddb3 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -806,6 +806,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //PUSH SS else if(opcode == 0x16) push_word(machine, machine->sregs.ss); + //PUSH FLAGS + else if(opcode == 0x9c) + push_word(machine, machine->regs.w.flags); //POP Operations //POP General purpose registers else if(opcode >= 0x50 && opcode <= 0x57) @@ -827,6 +830,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //POP SS else if(opcode == 0x17) machine->sregs.ss = pop_word(machine); + //POP FLAGS + else if(opcode == 0x9d) + machine->regs.w.flags = pop_word(machine); //XCHG group //XCHG GRP with AX or EAX else if(opcode >= 90 && opcode <= 97) From 4043107bbcf8611656c1919b7177d66eba1b623b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 21:57:52 +0200 Subject: [PATCH 039/165] Added CBW/CWDE and CWD/CDQ --- os/kernel/src/v8086/v8086.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f755ddb3..3ba835c4 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1557,6 +1557,27 @@ int16_t parse_and_execute_instruction(v8086* machine) } } + //CONVERSIONS + //CBW or CWDE + else if(opcode == 0x98) + { + if(machine->internal_state.operand_32_bit) + (int32_t)(machine->regs.d.eax) = (int16_t)(machine->regs.w.ax); + else + (int16_t)(machine->regs.w.ax) = (int8_t)(machine->regs.h.al); + } + //CWD or CDQ + else if(opcode == 0x99) + { + if(machine->internal_state.operand_32_bit){} + int64_t t = machine->regs.d.eax; + machine->regs.d.edx = (t >> 32); + } + else{ + int32_t t = machine->regs.w.ax; + machine->regs.w.dx = (t >> 16); + } + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 3693ef81df962cd24fa5c5e47d475591e44385c3 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 22:14:35 +0200 Subject: [PATCH 040/165] Added SAHF and LAHF --- os/kernel/src/v8086/v8086.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 3ba835c4..04cab7e3 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1569,7 +1569,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //CWD or CDQ else if(opcode == 0x99) { - if(machine->internal_state.operand_32_bit){} + if(machine->internal_state.operand_32_bit){ int64_t t = machine->regs.d.eax; machine->regs.d.edx = (t >> 32); } @@ -1578,6 +1578,15 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.w.dx = (t >> 16); } } + //Store and load flags + //SAHF + else if(opcode == 0x9e) + for(int i = 0; i < 8; i++) + if(i != 1 && i != 3 && i != 5) + bit_write(machine->regs.w.flags, 1<regs.h.ah, 1<regs.h.ah = machine->regs.w.flags & 0xFF; recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From f04ef46b7771eb3f5b1eee24b609b262033b1ca7 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 22:24:44 +0200 Subject: [PATCH 041/165] Some corrections in comments and added XLAT/XLATB --- os/kernel/src/v8086/v8086.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 04cab7e3..cc8c3b6b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1386,7 +1386,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); } - //ASCII ADJUSTMENT + //ASCII ADJUSTMENT group //AAA else if(opcode == 0x37) { @@ -1505,7 +1505,7 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_write(machine-> regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG } - //LOAD Operations + //LOAD Operations group //LEA else if(opcode == 0x8d) { @@ -1557,7 +1557,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } } - //CONVERSIONS + //CONVERSIONS group //CBW or CWDE else if(opcode == 0x98) { @@ -1578,7 +1578,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.w.dx = (t >> 16); } } - //Store and load flags + //Store and load flags group //SAHF else if(opcode == 0x9e) for(int i = 0; i < 8; i++) @@ -1587,6 +1587,18 @@ int16_t parse_and_execute_instruction(v8086* machine) //LAHF else if(opcode == 0x9f) machine->regs.h.ah = machine->regs.w.flags & 0xFF; + //MISC group + //XLAT/XLATB + else if(opcode == 0xd7) + { + uint8_t tempAL = machine->regs.h.al; + uint16_t* segment; + if(machine->internal_state.segment_reg_select != DEFAULT) + segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + else + segment = select_segment_register(machine, DS); + machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From 549cf45ecf7d2bcf730d52f920e69a522adffb73 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 22:37:21 +0200 Subject: [PATCH 042/165] Added Flag Setting and Clearing --- os/kernel/src/v8086/v8086.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index cc8c3b6b..278d80f8 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -13,6 +13,7 @@ #define AUX_CARRY_FLAG_BIT 4 #define ZERO_FLAG_BIT 6 #define SIGN_FLAG_BIT 7 +#define INTERRUPT_FLAG_BIT 9 #define DIRECTION_FLAG_BIT 10 #define OVERFLOW_FLAG_BIT 11 @@ -1587,6 +1588,28 @@ int16_t parse_and_execute_instruction(v8086* machine) //LAHF else if(opcode == 0x9f) machine->regs.h.ah = machine->regs.w.flags & 0xFF; + //FLAG Setting and clearing Group + //CMC + else if(opcode == 0xf5) + bit_flip(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1< Date: Thu, 7 May 2020 23:22:15 +0200 Subject: [PATCH 043/165] Another jumps --- os/kernel/src/v8086/v8086.c | 135 ++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 278d80f8..387ce79c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -897,68 +897,101 @@ int16_t parse_and_execute_instruction(v8086* machine) } } - //SHORT JUMPS - else if(opcode >= 0x70 && opcode <= 0x7f) + //Jumps Group + //SHORT JUMPS on conditions + else if((opcode >= 0x70 && opcode <= 0x7f) || (opcode == 0xe3)) { int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint32_t tempIP = machine->IP; uint8_t jump = 0; - switch(opcode & 0x0f) + if(opcode != 0xe3) + switch(opcode & 0x0f) + { + case 0: //JO + if(bit_get(machine->regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<internal_state.operand_32_bit) + if(!machine->regs.d.ecx) jump = 1; + else + if(!machine->regs.w.cx) jump = 1; } if(jump) tempIP += offset; if(tempIP > 0xFFFF) return -1; machine->IP = tempIP; } + //Short relative JMP + else if(opcode == 0xeb) + { + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + machine->IP += offset; + } + //Near realtive JMP + else if(opcode == 0xe9) + { + int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + machine->IP += offset; + } + //Far JMP + else if(opcode == 0xea) + { + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->sregs.cs = newCS; + machine->IP = newIP; + machine->internal_state.IPOffset = 0; + } //MOV Group //MOV r8, imm8 else if(opcode >= 0xb0 && opcode <= 0xb7) From dd6feaf88e35e71f030b2be15ecd49e44ee81d0b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 7 May 2020 23:43:22 +0200 Subject: [PATCH 044/165] Added LOOPs --- os/kernel/src/v8086/v8086.c | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 387ce79c..56ded830 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -992,6 +992,45 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->IP = newIP; machine->internal_state.IPOffset = 0; } + //LOOP Group + //LOOP LOOPE LOOPNE + else if(opcode >= 0xe0 && opcode <= 0xe2) + { + uint8_t jump = 0; + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(machine->internal_state.operand_32_bit) machine->regs.d.ecx--; + else machine->regs.w.cx--; + + switch (opcode) + { + case 0xe0: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx && !bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + } + else + if(machine->regs.w.cx && !bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + break; + case 0xe1: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx && bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + } + else + if(machine->regs.w.cx && bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + break; + case 0xe2: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx) jump = 1; + } + else + if(machine->regs.w.cx) jump = 1; + break; + } + + if(jump) + machine->IP += offset; + } //MOV Group //MOV r8, imm8 else if(opcode >= 0xb0 && opcode <= 0xb7) From fbfa9d279570b073ceebbb17f46cb70e2ce54922 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 00:09:14 +0200 Subject: [PATCH 045/165] Added IO Operations --- os/kernel/src/v8086/v8086.c | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 56ded830..01b00ac4 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1,6 +1,7 @@ #include "v8086.h" #include "../memory/heap/heap.h" #include +#include "../assembly/io.h" #define bit_get(p,m) ((p) & (m)) #define bit_set(p,m) ((p) |= (m)) @@ -1682,6 +1683,63 @@ int16_t parse_and_execute_instruction(v8086* machine) //STD else if(opcode == 0xfd) bit_set(machine->regs.w.flags, 1<Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + machine->regs.h.al = io_in_byte(immediate); + } + //IN AX/EAX, i8 + else if(opcode == 0xe5) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(machine->internal_state.operand_32_bit) + machine->regs.d.eax = io_in_long(immediate); + else + machine->regs.w.ax = io_in_word(immediate); + } + //IN AL, DX + else if(opcode == 0xec) + machine->regs.h.al = io_in_byte(machine->regs.x.dx); + //IN AX/EAX, DX + else if(opcode == 0xed) + { + if(machine->internal_state.operand_32_bit) + machine->regs.d.eax = io_in_long(machine->regs.x.dx); + else + machine->regs.w.ax = io_in_word(machine->regs.x.dx); + } + //OUT i8, AL + else if(opcode == 0xe6) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + io_out_byte(immediate, machine->regs.h.al); + } + //OUT i8, AX/EAX + else if(opcode == 0xe7) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(machine->internal_state.operand_32_bit) + io_out_long(immediate, machine->regs.d.eax); + else + io_out_long(immediate, machine->regs.w.ax); + } + //OUT DX, AL + else if(opcode == 0xee) + io_out_byte(machine->regs.w.dx, machine->regs.h.al); + //OUT DX, AX/EAX + else if(opcode == 0xef) + { + if(machine->internal_state.operand_32_bit) + io_out_long(machine->regs.w.dx, machine->regs.d.eax); + else + io_out_long(machine->regs.w.dx, machine->regs.w.ax); + } //MISC group //XLAT/XLATB else if(opcode == 0xd7) From 1c764684a6951a767a569fee921efcf6ceab92bf Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 00:48:25 +0200 Subject: [PATCH 046/165] Added Calls and Rets --- os/kernel/src/v8086/v8086.c | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 01b00ac4..c99d96d7 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1740,6 +1740,63 @@ int16_t parse_and_execute_instruction(v8086* machine) else io_out_long(machine->regs.w.dx, machine->regs.w.ax); } + //CALLs and RETs group + //NEAR relative CALL + else if(opcode == 0xe8) + { + int16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + + machine->IP += machine->internal_state.IPOffset; + push_word(machine, machine->IP); + machine->IP += immediate; + machine->internal_state.IPOffset = 0; + } + //FAR CALL + else if(opcode == 0x9a) + { + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP + machine->internal_state.IPOffset); + machine->IP = newIP; + machine->sregs.cs = newCS; + machine->internal_state.IPOffset = 0; + } + //Near RET + else if(opcode == 0xc3) + { + machine->IP = pop_word(machine); + machine->internal_state.IPOffset = 0; + } + //Near RET, imm16 + else if(opcode == 0xc2) + { + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + machine->IP = pop_word(machine); + machine->regs.w.sp += immediate; + machine->internal_state.IPOffset = 0; + } + //Far RET + else if(opcode == 0xcb) + { + machine->IP = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->internal_state.IPOffset = 0; + } + //Far RET, imm16 + else if(opcode == 0xca) + { + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + machine->IP = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->regs.w.sp += immediate; + machine->internal_state.IPOffset = 0; + } //MISC group //XLAT/XLATB else if(opcode == 0xd7) From 9704d92c820600b04eca210332fb9a015f4bea63 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 01:12:15 +0200 Subject: [PATCH 047/165] Added INT INT3 INTO IRET --- os/kernel/src/v8086/v8086.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index c99d96d7..ac75a4d9 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1797,6 +1797,41 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.w.sp += immediate; machine->internal_state.IPOffset = 0; } + //Interrupts group + //INT, imm and INT 3 and INTO + else if(opcode >= 0xcc && opcode <= 0xce) + { + uint8_t interrupt_number = 3; + if(opcode == 0xcd) //INT, imm + { + interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } + else if(opcode == 0xce) //INTO + { + if(!bit_get(machine->regs.w.flags, 1 << OVERFLOW_FLAG_BIT)) goto recalculate_ip; + interrupt_number = 4; + } + + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4)); + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4 + 2)); + + push_word(machine, machine->regs.w.flags); + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP); + + machine->IP = newIP; + machine->sregs.cs = newCS; + + machine->internal_state.IPOffset = 0; + } + //IRET + else if(opcode == 0xcf) + { + machine->IP = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->regs.w.flags = pop_word(machine); + } //MISC group //XLAT/XLATB else if(opcode == 0xd7) From 7a76f4980fb8bf2b43d6e9150a7c3d2cad13b9a7 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 01:15:50 +0200 Subject: [PATCH 048/165] Correction error in IRET --- os/kernel/src/v8086/v8086.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index ac75a4d9..398f6290 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1831,6 +1831,8 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->IP = pop_word(machine); machine->sregs.cs = pop_word(machine); machine->regs.w.flags = pop_word(machine); + + machine->internal_state.IPOffset = 0; } //MISC group //XLAT/XLATB From cbe5476ade82d311a45ddb0f2151d89ee9b44cdd Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 14:19:43 +0200 Subject: [PATCH 049/165] Added Group 1 --- os/kernel/src/v8086/v8086.c | 76 ++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 398f6290..f69589ea 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -634,9 +634,49 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc machine->internal_state.IPOffset += ((width / 8) - 1); break; } - perform_adding(machine, dest, source, width, carry); + operation(machine, dest, source, width, carry); return 0; } +int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) +{ + void* dest = NULL; + uint8_t width; + uint32_t immediate; + int32_t signed_immediate; + switch(recalculated_opcode) + { + case 0: //OPERATION rm8, imm8 + case 2: //OPERATION rm8, imm8 + width = 8; + dest = get_memory_from_mode(machine, mod_rm, width); + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + break; + case 1: //OPERATION rm16, imm16 or rm32, imm32 + if(machine->internal_state.operand_32_bit) { + width = 32; + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + } + else + { + width = 16; + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } + dest = get_memory_from_mode(machine, mod_rm, width); + break; + case 3: //OPERATION rm16, imm8, or rm32, imm8 + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + dest = get_memory_from_mode(machine, mod_rm, width); + break; + } + if(recalculated_opcode == 3) operation(machine, dest, &signed_immediate, width, carry); + else operation(machine, dest, &immediate, width, carry); +} int16_t parse_and_execute_instruction(v8086* machine) { @@ -784,6 +824,40 @@ int16_t parse_and_execute_instruction(v8086* machine) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); } + //GROUP 1 + else if(opcode >= 0x80 && opcode <= 0x83) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t recalculated_opcode = opcode - 0x80; + switch((mod_rm >> 3) & 7) + { + case 0: //ADD + perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_adding); + break; + case 1: //OR + perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_or); + break; + case 2: //ADC + perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, bit_get(machine->regs.w.flags, 1<regs.w.flags, 1<= 0x50 && opcode <= 0x57) From 5920b1fcf2893e50f860d8e6fb022ce06b75461c Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 8 May 2020 15:15:50 +0200 Subject: [PATCH 050/165] Fix many warnings and errors --- os/kernel/src/v8086/v8086.c | 47 ++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f69589ea..a55b7d90 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -116,7 +116,7 @@ static inline uint16_t pop_word(v8086* machine) return v; } -static inline uint32_t pop_word(v8086* machine) +static inline uint32_t pop_dword(v8086* machine) { uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); machine->regs.w.sp += 4; @@ -286,6 +286,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 case 6: if((mod_rm >> 6) == 0) segment_register = select_segment_register(machine, DS); else segment_register = select_segment_register(machine, SS); + break; default: segment_register = select_segment_register(machine, SS); break; @@ -323,6 +324,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 } case 7: *offset = machine->regs.x.bx; + return 0; default: return -1; } @@ -392,7 +394,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 } return -1; } - + return -1; } void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) @@ -509,6 +511,7 @@ int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint if(width == 8) *((uint8_t*)dest) = result & 0xFF; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return 0; } int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) @@ -536,6 +539,7 @@ int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uin if(width == 8) *((uint8_t*)dest) = result & 0xFF; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return 0; } int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) @@ -563,6 +567,7 @@ int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uin if(width == 8) *((uint8_t*)dest) = result & 0xFF; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return 0; } int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) @@ -676,6 +681,7 @@ int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t } if(recalculated_opcode == 3) operation(machine, dest, &signed_immediate, width, carry); else operation(machine, dest, &immediate, width, carry); + return 0; } int16_t parse_and_execute_instruction(v8086* machine) @@ -815,7 +821,7 @@ int16_t parse_and_execute_instruction(v8086* machine) perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); } //XOR - else if(opcode >- 0x30 && opcode <= 0x35) + else if(opcode >= 0x30 && opcode <= 0x35) { perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_xor); } @@ -927,8 +933,8 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width == 32) { uint16_t temp; - uint16_t* regA = get_dword_register(machine, EAX); - uint16_t* regB = get_dword_register(machine, opcode & 7); + uint32_t* regA = get_dword_register(machine, EAX); + uint32_t* regB = get_dword_register(machine, opcode & 7); temp = *regA; *regA = *regB; *regB = temp; @@ -972,6 +978,9 @@ int16_t parse_and_execute_instruction(v8086* machine) } } + //ROLS and RORS Group + else if(opcode >= 0xd0 && opcode <= 0xd3) + {} //Jumps Group //SHORT JUMPS on conditions else if((opcode >= 0x70 && opcode <= 0x7f) || (opcode == 0xe3)) @@ -1035,7 +1044,9 @@ int16_t parse_and_execute_instruction(v8086* machine) else { if(machine->internal_state.operand_32_bit) + { if(!machine->regs.d.ecx) jump = 1; + } else if(!machine->regs.w.cx) jump = 1; } @@ -1391,9 +1402,10 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t source_before; uint64_t result; uint8_t width = 8; - if(opcode == 0xA7) + if(opcode == 0xA7){ if(machine->internal_state.operand_32_bit) width=32; else width = 16; + } if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); @@ -1403,7 +1415,7 @@ int16_t parse_and_execute_instruction(v8086* machine) do{ source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); - dest = get_varaible_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); @@ -1430,7 +1442,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); } //STOSB STOSW STOSD else if(opcode >= 0xAA && opcode <= 0xAB) @@ -1440,8 +1452,10 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest; uint8_t width = 8; if(opcode == 0xA7) + { if(machine->internal_state.operand_32_bit) width=32; else width = 16; + } //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; @@ -1466,8 +1480,10 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest; uint8_t width = 8; if(opcode == 0xA7) + { if(machine->internal_state.operand_32_bit) width=32; else width = 16; + } if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); @@ -1498,15 +1514,17 @@ int16_t parse_and_execute_instruction(v8086* machine) uint64_t result; uint8_t width = 8; if(opcode == 0xA7) + { if(machine->internal_state.operand_32_bit) width=32; else width = 16; + } //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; do{ dest = get_variable_length_register(machine, AX, width); - source = get_varaible_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); @@ -1532,7 +1550,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - } while(machine->internal_state.rep_prefix != DEFAULT && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); } //ASCII ADJUSTMENT group //AAA @@ -1693,7 +1711,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) { - uint16_t* dest = get_dword_register(machine, (mod_rm >> 3) & 7); + uint32_t* dest = get_dword_register(machine, (mod_rm >> 3) & 7); *dest = *((uint32_t*) source); *segment_register = *(source+2); } @@ -1710,9 +1728,9 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0x98) { if(machine->internal_state.operand_32_bit) - (int32_t)(machine->regs.d.eax) = (int16_t)(machine->regs.w.ax); + machine->regs.d.eax = ((int32_t)(machine->regs.w.ax)); else - (int16_t)(machine->regs.w.ax) = (int8_t)(machine->regs.h.al); + machine->regs.w.ax = ((int16_t)(machine->regs.h.al)); } //CWD or CDQ else if(opcode == 0x99) @@ -1728,10 +1746,11 @@ int16_t parse_and_execute_instruction(v8086* machine) } //Store and load flags group //SAHF - else if(opcode == 0x9e) + else if(opcode == 0x9e){ for(int i = 0; i < 8; i++) if(i != 1 && i != 3 && i != 5) bit_write(machine->regs.w.flags, 1<regs.h.ah, 1<regs.h.ah = machine->regs.w.flags & 0xFF; From 5c897ef12f7bf3d7f60fdda259435386970266b7 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 9 May 2020 03:22:26 +0200 Subject: [PATCH 051/165] Added Group 2 --- os/kernel/src/v8086/v8086.c | 159 +++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index a55b7d90..6ba16b67 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -684,6 +684,126 @@ int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t return 0; } +int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) +{ + uint16_t temp_flags = 0; + if(arg == 0) return 0; + if(width == 8) + __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); + else if(width == 16) + __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); + else if(width == 32) + __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + else return -1; + if(arg == 1) bit_write(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<internal_state.IPOffset = 0; @@ -980,7 +1100,44 @@ int16_t parse_and_execute_instruction(v8086* machine) } //ROLS and RORS Group else if(opcode >= 0xd0 && opcode <= 0xd3) - {} + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t arg = opcode <=0xd1 ? 1 : machine->regs.h.cl; + uint8_t width = 8; + if(opcode % 2){ + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + } + void* dest = get_memory_from_mode(machine, mod_rm, width); + + switch((mod_rm >> 3) & 7) + { + case 0: + perform_rol(machine, dest, arg, width); + break; + case 1: + perform_ror(machine, dest, arg, width); + break; + case 2: + perform_rcl(machine, dest, arg, width); + break; + case 3: + perform_rcr(machine, dest, arg, width); + break; + case 4: + perform_shl(machine, dest, arg, width); + break; + case 5: + perform_shr(machine, dest, arg, width); + break; + case 6: + return -1; + case 7: + perform_sar(machine, dest, arg, width); + break; + } + } //Jumps Group //SHORT JUMPS on conditions else if((opcode >= 0x70 && opcode <= 0x7f) || (opcode == 0xe3)) From 3d602fa0823f438d294fd4d2b3e86ec29ba52e94 Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 16 May 2020 03:24:18 +0200 Subject: [PATCH 052/165] Added Group 3a and 3b and 4. Started work with group 5 --- os/kernel/src/v8086/v8086.c | 911 +++++++++++++++++++++++------------- 1 file changed, 598 insertions(+), 313 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 6ba16b67..11f5597b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -9,14 +9,14 @@ #define bit_flip(p,m) ((p) ^= (m)) #define bit_write(p,m,v) (v ? bit_set(p,m) : bit_clear(p,m)) -#define CARRY_FLAG_BIT 0 -#define PARITY_FLAG_BIT 2 -#define AUX_CARRY_FLAG_BIT 4 -#define ZERO_FLAG_BIT 6 -#define SIGN_FLAG_BIT 7 -#define INTERRUPT_FLAG_BIT 9 -#define DIRECTION_FLAG_BIT 10 -#define OVERFLOW_FLAG_BIT 11 +#define CARRY_FLAG_BIT 0u +#define PARITY_FLAG_BIT 2u +#define AUX_CARRY_FLAG_BIT 4u +#define ZERO_FLAG_BIT 6u +#define SIGN_FLAG_BIT 7u +#define INTERRUPT_FLAG_BIT 9u +#define DIRECTION_FLAG_BIT 10u +#define OVERFLOW_FLAG_BIT 11u enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; @@ -59,7 +59,7 @@ static inline void* get_variable_length_pointer(uint8_t* memory, uint16_t offset } } -static inline uint8_t read_byte_from_pointer(uint8_t* memory, uint16_t offset) +static inline uint8_t read_byte_from_pointer(const uint8_t* memory, uint16_t offset) { return *(memory + offset); } @@ -179,6 +179,8 @@ uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) return &(machine->regs.h.dl); case DH: return &(machine->regs.h.dh); + default: + return NULL; } return NULL; } @@ -203,6 +205,8 @@ uint16_t* get_word_register(v8086* machine, uint8_t reg_field) return &(machine->regs.x.si); case DI: return &(machine->regs.x.di); + default: + return NULL; } return NULL; } @@ -227,6 +231,8 @@ uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) return &(machine->regs.d.esi); case EDI: return &(machine->regs.d.edi); + default: + return NULL; } return NULL; } @@ -274,7 +280,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); else { - switch (mod_rm & 7) + switch (mod_rm & 7u) { case 0: case 1: @@ -284,7 +290,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 segment_register = select_segment_register(machine, DS); break; case 6: - if((mod_rm >> 6) == 0) segment_register = select_segment_register(machine, DS); + if((mod_rm >> 6u) == 0) segment_register = select_segment_register(machine, DS); else segment_register = select_segment_register(machine, SS); break; default: @@ -295,10 +301,10 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 *segment = *segment_register; - switch(mod_rm >> 6) //Parsing mod than parsing rm + switch(mod_rm >> 6u) //Parsing mod than parsing rm { case 0: - switch(mod_rm & 7){ + switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si; return 0; @@ -331,7 +337,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 case 1:{ int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - switch(mod_rm & 7){ + switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; return 0; @@ -363,7 +369,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 case 2:{ uint16_t disp = (uint16_t) read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - switch(mod_rm & 7){ + switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; return 0; @@ -402,7 +408,7 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) uint16_t segment; uint16_t offset; - switch(mod_rm >> 6) //Parsing mod than parsing rm + switch(mod_rm >> 6u) //Parsing mod than parsing rm { case 0: case 1: @@ -412,11 +418,11 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) case 3: switch(width){ case 8: - return get_byte_register(machine, mod_rm & 7); + return get_byte_register(machine, mod_rm & 7u); case 16: - return get_word_register(machine, mod_rm & 7); + return get_word_register(machine, mod_rm & 7u); case 32: - return get_dword_register(machine, mod_rm & 7); + return get_dword_register(machine, mod_rm & 7u); default: return NULL; } @@ -440,16 +446,16 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, source_before = *((uint32_t*)source); } else return -1; result = dest_before + source_before + carry; - bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFF; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; else return -1; return 0; @@ -471,16 +477,16 @@ int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t wi source_before = *((uint32_t*)source); } else return -1; result = dest_before - (source_before + carry); - bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFF; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; else return -1; return 0; @@ -500,16 +506,16 @@ int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint result = *((uint32_t*)dest) | *((uint32_t*)source); } else return -1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFF; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; return 0; } @@ -528,16 +534,16 @@ int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uin result = *((uint32_t*)dest) & *((uint32_t*)source); } else return -1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFF; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; return 0; } @@ -556,16 +562,16 @@ int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uin result = *((uint32_t*)dest) ^ *((uint32_t*)source); } else return -1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFF; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; return 0; } @@ -586,14 +592,14 @@ int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uin source_before = *((uint32_t*)source); } else return -1; result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG return 0; } @@ -611,19 +617,19 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc switch(recalculated_opcode) { case 0: //OPERATION r/m8, r8 - source = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + source = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 - source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); break; case 2: //OPERATION r8, r/m8 - dest = get_byte_register(machine, (mod_rm_or_immediate >> 3) & 7); + dest = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); break; case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 - dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3) & 7, width); + dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); source = get_memory_from_mode(machine, mod_rm_or_immediate, width); break; case 4: //OPERATION AL, imm8 @@ -638,6 +644,8 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += ((width / 8) - 1); break; + default: + return -1; } operation(machine, dest, source, width, carry); return 0; @@ -678,6 +686,8 @@ int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t machine->internal_state.IPOffset += 1; dest = get_memory_from_mode(machine, mod_rm, width); break; + default: + return -1; } if(recalculated_opcode == 3) operation(machine, dest, &signed_immediate, width, carry); else operation(machine, dest, &immediate, width, carry); @@ -695,8 +705,8 @@ int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) else if(width == 32) __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); else return -1; - if(arg == 1) bit_write(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; imul %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; imul %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + } + else + { + if(width == 8) + { + __asm__ __volatile__( + "movb %%dl, %%al; mul %%cl; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; mul %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; mul %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + } + bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + } + else + { + if(width == 8) + { + __asm__ __volatile__( + "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + } + return 0; +} + +int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) +{ + uint32_t result; + + if(width == 8) + result = *((uint8_t*) source) & *((uint8_t*) dest); + else if(width == 16) + result = *((uint16_t*) source) & *((uint16_t*) dest); + else if(width == 32) + result = *((uint32_t*) source) & *((uint32_t*) dest); + else return -1; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + return 0; +} + +int16_t perform_inc(v8086* machine, void* dest, uint8_t width) +{ + uint64_t result = 0; + uint32_t dest_before; + + if (width == 8) dest_before = *((uint8_t*) dest); + else if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return -1; + + result = dest_before + 1; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return 0; +} + +int16_t perform_dec(v8086* machine, void* dest, uint8_t width) +{ + uint64_t result = 0; + uint32_t dest_before; + + if (width == 8) dest_before = *((uint8_t*) dest); + else if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return -1; + + result = dest_before - 1; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; return 0; } @@ -818,9 +1030,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //PREFIXES //Segment Prefix CS DS ES SS - if((opcode & 0x7) == 0x6 && ((opcode >> 5) & 0x7) == 0x1) //001XX110 pattern where XX is number of segment + if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment { - machine->internal_state.segment_reg_select = (opcode >> 3) & 0x3; + machine->internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; goto decode; //continue parsing opcode; } //Segment Prefix FS @@ -867,12 +1079,12 @@ int16_t parse_and_execute_instruction(v8086* machine) //ADC else if(opcode >= 0x10 && opcode <= 0x15) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1<> CARRY_FLAG_BIT, perform_adding); + perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_adding); } //SBB else if(opcode >= 0x18 && opcode <= 0x1d) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1<> CARRY_FLAG_BIT, perform_subtracting); + perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_subtracting); } //SUB else if(opcode >= 0x28 && opcode <= 0x2d) @@ -884,50 +1096,18 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint8_t width = 16; void* dest = NULL; - uint64_t result = 0; - uint32_t dest_before; if(machine->internal_state.operand_32_bit) width=32; - dest = get_variable_length_register(machine, opcode & 7, width); - if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); - else return -1; - - result = dest_before + 1; - - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + dest = get_variable_length_register(machine, opcode & 7u, width); + perform_inc(machine, dest, width); } //DEC general registers 16 or 32-bit else if(opcode >= 0x48 && opcode <= 0x4f) { uint8_t width = 16; void* dest = NULL; - uint64_t result = 0; - uint32_t dest_before; if(machine->internal_state.operand_32_bit) width=32; - dest = get_variable_length_register(machine, opcode & 7, width); - if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); - else return -1; - - result = dest_before - 1; - - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1<regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - if(width == 16) *((uint16_t*)dest) = result & 0xFFFF; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + dest = get_variable_length_register(machine, opcode & 7u, width); + perform_dec(machine, dest, width); } //LOGICAL operations //OR @@ -956,7 +1136,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t recalculated_opcode = opcode - 0x80; - switch((mod_rm >> 3) & 7) + switch((mod_rm >> 3u) & 7u) { case 0: //ADD perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_adding); @@ -965,10 +1145,10 @@ int16_t parse_and_execute_instruction(v8086* machine) perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_or); break; case 2: //ADC - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, bit_get(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <= 0xf6 && opcode <= 0xf7) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + if(opcode == 0xf7) + { + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + } + + void* dest = get_memory_from_mode(machine, mod_rm, width); + + switch((mod_rm >> 3u) & 7u) + { + case 0: //TEST + { + uint32_t immediate; + if(width == 8) + { + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 1; + } + else if(width == 16) + { + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 2; + } + else if(width == 32) + { + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 4; + } + perform_test(machine, &immediate, dest, width); + break; + } + case 2: //NOT + if(width == 8) + *((uint8_t*)dest) = ~(*((uint8_t*)dest)); + else if(width == 16) + *((uint16_t*)dest) = ~(*((uint16_t*)dest)); + else if(width == 32) + *((uint32_t*)dest) = ~(*((uint32_t*)dest)); + break; + case 3: //NEG + perform_neg(machine, dest, width); + break; + case 4: //MUL + perform_multiplication(machine, dest, 0, width); + break; + case 5: //IMUL + perform_multiplication(machine, dest, 1, width); + break; + case 6: //DIV + perform_division(machine, dest, 0, width); + break; + case 7: + perform_division(machine, dest, 1, width); + break; + default: + return -1; + } + } //PUSH Operations //PUSH General purpose registers else if(opcode >= 0x50 && opcode <= 0x57) @@ -991,7 +1235,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t width = 16; void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; - reg = get_variable_length_register(machine, opcode & 7, width); + reg = get_variable_length_register(machine, opcode & 7u, width); if(width==16) push_word(machine, *((uint16_t*)reg)); else if(width==32) push_dword(machine, *((uint32_t*)reg)); else return -1; @@ -1018,7 +1262,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t width = 16; void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; - reg = get_variable_length_register(machine, opcode & 7, width); + reg = get_variable_length_register(machine, opcode & 7u, width); if(width==16) *((uint16_t*)reg) = pop_word(machine); else if(width==32) *((uint32_t*)reg) = pop_dword(machine); else return -1; @@ -1045,7 +1289,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint16_t temp; uint16_t* regA = get_word_register(machine, AX); - uint16_t* regB = get_word_register(machine, opcode & 7); + uint16_t* regB = get_word_register(machine, opcode & 7u); temp = *regA; *regA = *regB; *regB = temp; @@ -1054,7 +1298,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint16_t temp; uint32_t* regA = get_dword_register(machine, EAX); - uint32_t* regB = get_dword_register(machine, opcode & 7); + uint32_t* regB = get_dword_register(machine, opcode & 7u); temp = *regA; *regA = *regB; *regB = temp; @@ -1068,7 +1312,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; if(opcode == 0x86) { - uint8_t* source = get_byte_register(machine, (mod_rm >> 3) & 7); + uint8_t* source = get_byte_register(machine, (mod_rm >> 3u) & 7u); uint8_t* dest = get_memory_from_mode(machine, mod_rm, 8); uint8_t temp; temp = *source; @@ -1079,7 +1323,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit) { - uint32_t* source = get_dword_register(machine, (mod_rm >> 3) & 7); + uint32_t* source = get_dword_register(machine, (mod_rm >> 3u) & 7u); uint32_t* dest = get_memory_from_mode(machine, mod_rm, 32); uint32_t temp; temp = *source; @@ -1088,7 +1332,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } else { - uint16_t* source = get_word_register(machine, (mod_rm >> 3) & 7); + uint16_t* source = get_word_register(machine, (mod_rm >> 3u) & 7u); uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); uint16_t temp; temp = *source; @@ -1098,7 +1342,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } } - //ROLS and RORS Group + //ROLS and RORS Group (Group 2) else if(opcode >= 0xd0 && opcode <= 0xd3) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); @@ -1111,7 +1355,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } void* dest = get_memory_from_mode(machine, mod_rm, width); - switch((mod_rm >> 3) & 7) + switch((mod_rm >> 3u) & 7u) { case 0: perform_rol(machine, dest, arg, width); @@ -1147,55 +1391,55 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t tempIP = machine->IP; uint8_t jump = 0; if(opcode != 0xe3) - switch(opcode & 0x0f) + switch(opcode & 0x0fu) { case 0: //JO - if(bit_get(machine->regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1<regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <internal_state.operand_32_bit){ - if(machine->regs.d.ecx && !bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + if(machine->regs.d.ecx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; } else - if(machine->regs.w.cx && !bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + if(machine->regs.w.cx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; break; case 0xe1: if(machine->internal_state.operand_32_bit){ - if(machine->regs.d.ecx && bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + if(machine->regs.d.ecx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; } else - if(machine->regs.w.cx && bit_get(machine->regs.w.flags, 1 << ZERO_FLAG_BIT)) jump = 1; + if(machine->regs.w.cx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; break; case 0xe2: if(machine->internal_state.operand_32_bit){ @@ -1269,6 +1513,8 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(machine->regs.w.cx) jump = 1; break; + default: + break; } if(jump) @@ -1278,7 +1524,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //MOV r8, imm8 else if(opcode >= 0xb0 && opcode <= 0xb7) { - uint8_t* reg = get_byte_register(machine, opcode & 0x7); + uint8_t* reg = get_byte_register(machine, opcode & 0x7u); uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; *reg = imm; @@ -1288,14 +1534,14 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit) { - uint32_t* reg = get_dword_register(machine, (opcode - 0xb8) & 0x7); + uint32_t* reg = get_dword_register(machine, (opcode - 0xb8u) & 0x7u); uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; *reg = imm; } else { - uint16_t* reg = get_word_register(machine, (opcode - 0xb8) & 0x7); + uint16_t* reg = get_word_register(machine, (opcode - 0xb8u) & 0x7u); uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; *reg = imm; @@ -1324,6 +1570,8 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.d.eax); else write_word_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.x.ax); break; + default: + break; } } //MOV r8/r16/r32, rm8/rm16/rm32 or MOV rm8/rm16/rm32, r8/r16/r32 @@ -1338,27 +1586,29 @@ int16_t parse_and_execute_instruction(v8086* machine) switch (opcode) { case 0x88: - source = get_byte_register(machine, (mod_rm >> 3) & 7); + source = get_byte_register(machine, (mod_rm >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm, 8); *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x89: - source = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); dest = get_memory_from_mode(machine, mod_rm, width); if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); else *((uint32_t*)dest) = *((uint32_t*) source); break; case 0x8a: - dest = get_byte_register(machine, (mod_rm >> 3) & 7); + dest = get_byte_register(machine, (mod_rm >> 3u) & 7u); source = get_memory_from_mode(machine, mod_rm, 8); *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x8b: - dest = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + dest = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); source = get_memory_from_mode(machine, mod_rm, width); if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); else *((uint32_t*)dest) = *((uint32_t*) source); break; + default: + break; } } //MOV Segment to/from r/m @@ -1370,12 +1620,12 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t* dest = NULL; if(opcode == 0x8c) { - source = select_segment_register(machine, (mod_rm >> 3) & 7); + source = select_segment_register(machine, (mod_rm >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm, 16); } else { - dest = select_segment_register(machine, (mod_rm >> 3) & 7); + dest = select_segment_register(machine, (mod_rm >> 3u) & 7); source = get_memory_from_mode(machine, mod_rm, 16); } *dest = *source; @@ -1418,16 +1668,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //Mod/RM uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - uint8_t* reg = get_byte_register(machine, (mod_rm >> 3) & 7); + uint8_t* reg = get_byte_register(machine, (mod_rm >> 3u) & 7u); uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); - uint8_t result = *reg & *memory; - bit_clear(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG + perform_test(machine, reg, memory, 8); } else if(opcode == 0x85) { @@ -1436,20 +1679,9 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; - uint32_t result; - void* source = get_variable_length_register(machine, (mod_rm >> 3) & 7, width); + void* source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); void* dest = get_memory_from_mode(machine, mod_rm, width); - - if(width == 16) - result = *((uint16_t*) source) & *((uint16_t*) dest); - else if(width == 32) - result = *((uint32_t*) source) & *((uint32_t*) dest); - - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + perform_test(machine, source, dest, width); } else if(opcode == 0xa8) { @@ -1458,13 +1690,13 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; uint8_t* reg = get_byte_register(machine, AL); uint8_t result = *reg & immediate; - bit_clear(machine->regs.d.eflags, 1<regs.d.eflags, 1<> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> 7); //SIGN FLAG + bit_clear(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> 7u); //SIGN FLAG } else if(opcode == 0xa9) { @@ -1491,11 +1723,11 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width == 32) result = *((uint32_t*) reg) & immediate; - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG } //STRING GROUP //MOVSB @@ -1515,8 +1747,8 @@ int16_t parse_and_execute_instruction(v8086* machine) source = get_byte_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); dest = get_byte_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -1 : 1; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -1 : 1; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -1 : 1; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -1 : 1; } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } //MOVSW or MOVSD @@ -1535,16 +1767,16 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t* source = get_dword_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); uint32_t* dest = get_dword_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -4 : 4; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -4 : 4; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -4 : 4; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -4 : 4; } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); else do{ uint16_t* source = get_word_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); uint16_t* dest = get_word_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -2 : 2; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -2 : 2; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -2 : 2; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -2 : 2; } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } @@ -1585,17 +1817,17 @@ int16_t parse_and_execute_instruction(v8086* machine) } else return -1; result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG - - machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; @@ -1626,7 +1858,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); else return -1; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } //LOADB LOADW LOADD @@ -1657,7 +1889,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); else return -1; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); } //SCASB or SCASW or SCADD @@ -1694,16 +1926,16 @@ int16_t parse_and_execute_instruction(v8086* machine) } else return -1; result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1<> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1<> 4) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1; - for(int i = 1; i < 8; i++) parrity ^= (result >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.d.eflags, 1<> (width - 1)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1<> (width - 1)) != (dest_before >> (width - 1)))); //OVERFLOW FLAG + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - machine->regs.w.di += bit_get(machine->regs.w.flags, 1 << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; @@ -1713,88 +1945,88 @@ int16_t parse_and_execute_instruction(v8086* machine) //AAA else if(opcode == 0x37) { - if(((machine->regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.x.ax += 0x106; - bit_set(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al &= 0x0f; + machine->regs.h.al &= 0x0fu; } //AAS else if(opcode == 0x3F) { - if(((machine->regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al -= 0x6; machine->regs.h.ah -= 1; - bit_set(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al &= 0x0f; + machine->regs.h.al &= 0x0fu; } //DAA else if(opcode == 0x27) { uint8_t old_AL = machine->regs.h.al; - uint16_t old_cf = bit_get(machine->regs.w.flags, 1<regs.w.flags, 1<regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al + 6; - machine->regs.h.al = temp_ax & 0xFF; - bit_write(machine->regs.w.flags, 1< 0xFF)) ? 1 : 0); - bit_set(machine->regs.w.flags, 1<regs.h.al = temp_ax & 0xFFu; + bit_write(machine->regs.w.flags, 1u < 0xFF)) ? 1 : 0); + bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u < 0x99) || old_cf) { machine->regs.h.al += 0x60; - bit_set(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.h.al & 1; - for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + else bit_clear(machine->regs.w.flags, 1u <regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG } //DAS else if(opcode == 0x2f) { uint8_t old_AL = machine->regs.h.al; - uint16_t old_cf = bit_get(machine->regs.w.flags, 1<regs.w.flags, 1<regs.h.al & 0x0f) > 9) || bit_get(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 0x0f) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al - 6; - machine->regs.h.al = temp_ax & 0xFF; - bit_write(machine->regs.w.flags, 1< 0xFF)) ? 1 : 0); - bit_set(machine->regs.w.flags, 1<regs.h.al = temp_ax & 0xFFu; + bit_write(machine->regs.w.flags, 1u < 0xFF)) ? 1 : 0); + bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u < 0x99) || old_cf) { machine->regs.h.al -= 0x60; - bit_set(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.h.al & 1; - for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + uint8_t parrity = machine->regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG } //AAM else if(opcode == 0xd4) @@ -1805,11 +2037,11 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->regs.h.ah = tempAL / immediate; machine->regs.h.al = tempAL % immediate; - uint8_t parrity = machine->regs.h.al & 1; - for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + uint8_t parrity = machine->regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG } //AAD else if(opcode == 0xd5) @@ -1819,14 +2051,14 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t tempAL = machine->regs.h.al; uint8_t tempAH = machine->regs.h.ah; - machine->regs.h.al = (tempAL + (tempAH * immediate)) & 0xFF; + machine->regs.h.al = (tempAL + (tempAH * immediate)) & 0xFFu; machine->regs.h.ah = 0; - uint8_t parrity = machine->regs.h.al & 1; - for(int i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1; - bit_write(machine->regs.d.eflags, 1< regs.d.eflags, 1<regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1<regs.h.al >> (7)); //SIGN FLAG + uint8_t parrity = machine->regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG } //LOAD Operations group //LEA @@ -1838,19 +2070,19 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t segment; uint16_t offset; - if((mod_rm >> 6) > 3) return -1; + if((mod_rm >> 6u) > 3) return -1; int16_t r = calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); if(r) return r; if(machine->internal_state.operand_32_bit) { - uint32_t* reg = get_dword_register(machine, (mod_rm>>3)&7); + uint32_t* reg = get_dword_register(machine, (mod_rm>>3u)&7u); *reg = offset; } else { - uint16_t* reg = get_word_register(machine, (mod_rm>>3)&7); + uint16_t* reg = get_word_register(machine, (mod_rm>>3u)&7u); *reg = offset; } } @@ -1868,13 +2100,13 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) { - uint32_t* dest = get_dword_register(machine, (mod_rm >> 3) & 7); + uint32_t* dest = get_dword_register(machine, (mod_rm >> 3u) & 7u); *dest = *((uint32_t*) source); *segment_register = *(source+2); } else { - uint16_t* dest = get_word_register(machine, (mod_rm >> 3) & 7); + uint16_t* dest = get_word_register(machine, (mod_rm >> 3u) & 7u); *dest = *source; *segment_register = *(source+1); } @@ -1894,45 +2126,45 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit){ int64_t t = machine->regs.d.eax; - machine->regs.d.edx = (t >> 32); + machine->regs.d.edx = (t >> 32u); } else{ int32_t t = machine->regs.w.ax; - machine->regs.w.dx = (t >> 16); + machine->regs.w.dx = (t >> 16u); } } //Store and load flags group //SAHF else if(opcode == 0x9e){ - for(int i = 0; i < 8; i++) + for(uint8_t i = 0; i < 8; i++) if(i != 1 && i != 3 && i != 5) - bit_write(machine->regs.w.flags, 1<regs.h.ah, 1<regs.w.flags, 1u <regs.h.ah, 1u <regs.h.ah = machine->regs.w.flags & 0xFF; + machine->regs.h.ah = machine->regs.w.flags & 0xFFu; //FLAG Setting and clearing Group //CMC else if(opcode == 0xf5) - bit_flip(machine->regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1<regs.w.flags, 1u <regs.w.flags, 1 << OVERFLOW_FLAG_BIT)) goto recalculate_ip; + if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) goto recalculate_ip; interrupt_number = 4; } @@ -2096,6 +2328,59 @@ int16_t parse_and_execute_instruction(v8086* machine) segment = select_segment_register(machine, DS); machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); } + //GROUP 4 + else if(opcode == 0xfe) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + + switch((mod_rm >> 3u) & 7u) + { + case 0: //INC rm8 + perform_inc(machine, dest, width); + break; + case 1: //DEC rm8 + perform_dec(machine, dest, width); + break; + default: + return -1; + } + } + //GROUP 5 + else if(opcode == 0xff) + { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + + switch((mod_rm >> 3u) & 7u) + { + case 0: //INC rm8 + perform_inc(machine, dest, width); + break; + case 1: //DEC rm8 + perform_dec(machine, dest, width); + break; + case 2: //Near absolute indirect call + machine->IP += machine->internal_state.IPOffset; + push_word(machine, machine->IP); + if(width == 16) + machine->IP += *((uint16_t*) dest); + else return -1; + machine->internal_state.IPOffset = 0; + break; + case 3: + + default: + return -1; + } + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From b6f4dff6b5530e5c4b45ebf0eacfef5bbb6eb5b7 Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 16 May 2020 23:19:58 +0200 Subject: [PATCH 053/165] Added Group 5 and 1A - finished bingo. Now the hell of testing --- os/kernel/src/v8086/v8086.c | 42 +++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 11f5597b..c665d020 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -2375,12 +2375,50 @@ int16_t parse_and_execute_instruction(v8086* machine) else return -1; machine->internal_state.IPOffset = 0; break; - case 3: - + case 3: // Far absolute indirect call + machine->IP += machine->internal_state.IPOffset; + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP); + machine->IP = *((uint16_t*) dest); + machine->sregs.cs = *(((uint16_t*)dest)+1); + machine->internal_state.IPOffset = 0; + break; + case 4: //Near absolute indirect jmp + if(width == 16) + machine->IP += *((uint16_t*) dest); + else return -1; + machine->internal_state.IPOffset = 0; + break; + case 5: //Far absolute indirect jmp + machine->IP = *((uint16_t*) dest); + machine->sregs.cs = *(((uint16_t*)dest)+1); + machine->internal_state.IPOffset = 0; + break; + case 6: + if(width == 16) + push_word(machine, *((uint16_t*)dest)); + else if(width == 32) + push_dword(machine, *((uint32_t*)dest)); + else return -1; default: return -1; } } + //GROUP 1A + else if(opcode == 0x8f) + { + //ITS only POP rm16/32 + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(width == 16) + *((uint16_t*)dest) = pop_word(machine); + else if(width == 32) + *((uint32_t*)dest) = pop_dword(machine); + } recalculate_ip: machine->IP += machine->internal_state.IPOffset; return 0; From ddca8505562a5fcacfc0fcb92f9185945ee2e3fe Mon Sep 17 00:00:00 2001 From: SzateX Date: Sun, 17 May 2020 01:03:35 +0200 Subject: [PATCH 054/165] Making code more safe, not shy if error happens. Duck... Where is my duck? --- os/kernel/src/v8086/v8086.c | 430 ++++++++++++++++++++---------------- os/kernel/src/v8086/v8086.h | 16 ++ 2 files changed, 261 insertions(+), 185 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index c665d020..19fdeef4 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -22,7 +22,7 @@ enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; -int16_t parse_instruction(v8086* machine); +int16_t parse_and_execute_instruction(v8086* machine); static inline uint16_t get_absolute_address(uint16_t segment, uint16_t offset) { @@ -140,22 +140,22 @@ int16_t v8086_call_function(v8086* machine) { while(!(machine->IP == 0xFFFF && machine->sregs.cs == 0xFFFF)) { - int x = -1; - if(x) return x; + int16_t status = parse_and_execute_instruction(machine); + if(status != OK) return status; } - return 0; + return OK; } int16_t v8086_call_int(v8086* machine, int16_t num) { - if ((num < 0) || (num > 0xFF)) return -1; + if ((num < 0) || (num > 0xFF)) return BAD_INT_NUMBER; machine -> IP = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4)); machine -> sregs.cs = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); push_word(machine, machine->regs.w.flags); push_word(machine, 0xFFFF); push_word(machine, 0xFFFF); - int x = v8086_call_function(machine); - if(x) return -2; + int16_t x = v8086_call_function(machine); + if(x != OK) return x; return num; } @@ -299,6 +299,8 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 } } + if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; + *segment = *segment_register; switch(mod_rm >> 6u) //Parsing mod than parsing rm @@ -307,32 +309,32 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si; - return 0; + return OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di; - return 0; + return OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si; - return 0; + return OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di; - return 0; + return OK; case 4: *offset = machine->regs.x.si; - return 0; + return OK; case 5: *offset = machine->regs.x.di; - return 0; + return OK; case 6:{ *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset))); machine->internal_state.IPOffset += 1; - return 0; + return OK; } case 7: *offset = machine->regs.x.bx; - return 0; + return OK; default: - return -1; + return BAD_RM; } case 1:{ int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); @@ -340,30 +342,30 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return 0; + return OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return 0; + return OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return 0; + return OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return 0; + return OK; case 4: *offset = machine->regs.x.si + disp; - return 0; + return OK; case 5: *offset = machine->regs.x.di + disp; - return 0; + return OK; case 6: *offset = machine->regs.x.bp + disp; - return 0; + return OK; case 7: *offset = machine->regs.x.bx + disp; - return 0; + return OK; default: - return -1; + return BAD_RM; } } case 2:{ @@ -372,35 +374,36 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return 0; + return OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return 0; + return OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return 0; + return OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return 0; + return OK; case 4: *offset = machine->regs.x.si + disp; - return 0; + return OK; case 5: *offset = machine->regs.x.di + disp; - return 0; + return OK; case 6: *offset = machine->regs.x.bp + disp; - return 0; + return OK; case 7: *offset = machine->regs.x.bx + disp; - return 0; + return OK; default: - return -1; + return BAD_RM; } } - return -1; + default: + return BAD_MOD; } - return -1; + return UNKNOWN_ERROR; } void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) @@ -444,7 +447,7 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, } else if(width == 32){ dest_before = *((uint32_t*)dest); source_before = *((uint32_t*)source); - } else return -1; + } else return BAD_WIDTH; result = dest_before + source_before + carry; bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG uint8_t parrity = result & 1u; @@ -457,8 +460,8 @@ int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, if(width == 8) *((uint8_t*)dest) = result & 0xFFu; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - else return -1; - return 0; + else return BAD_WIDTH; + return OK; } int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) @@ -475,7 +478,7 @@ int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t wi } else if(width == 32){ dest_before = *((uint32_t*)dest); source_before = *((uint32_t*)source); - } else return -1; + } else return BAD_WIDTH; result = dest_before - (source_before + carry); bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG @@ -488,24 +491,20 @@ int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t wi if(width == 8) *((uint8_t*)dest) = result & 0xFFu; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - else return -1; - return 0; + else return BAD_WIDTH; + return OK; } int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) { uint32_t result = 0; if(width == 8) - { result = *((uint8_t*)dest) | *((uint8_t*)source); - } else if(width == 16) - { + else if(width == 16) result = *((uint16_t*)dest) | *((uint16_t*)source); - } else if(width == 32) - { + else if(width == 32) result = *((uint32_t*)dest) | *((uint32_t*)source); - } - else return -1; + else return BAD_WIDTH; bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG @@ -600,7 +591,7 @@ int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uin bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - return 0; + return OK; } int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) @@ -619,25 +610,35 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc case 0: //OPERATION r/m8, r8 source = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; break; case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; break; case 2: //OPERATION r8, r/m8 dest = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; break; case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); source = get_memory_from_mode(machine, mod_rm_or_immediate, width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; break; case 4: //OPERATION AL, imm8 dest = get_byte_register(machine, AL); source = &(mod_rm_or_immediate); + if(dest == NULL) return UNDEFINED_REGISTER; break; case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 dest = get_variable_length_register(machine, AX, width); + if(dest == NULL) return UNDEFINED_REGISTER; if(width == 32) source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); else @@ -645,12 +646,13 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc machine->internal_state.IPOffset += ((width / 8) - 1); break; default: - return -1; + return UNDEFINED_RECALCULATED_OPCODE; } - operation(machine, dest, source, width, carry); - return 0; + int16_t status = operation(machine, dest, source, width, carry); + if(status) return status; + return OK; } -int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) +int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { void* dest = NULL; uint8_t width; @@ -687,33 +689,36 @@ int16_t perform_artihmetic_or_logical_instruction_group(v8086* machine, uint8_t dest = get_memory_from_mode(machine, mod_rm, width); break; default: - return -1; - } - if(recalculated_opcode == 3) operation(machine, dest, &signed_immediate, width, carry); - else operation(machine, dest, &immediate, width, carry); - return 0; + return UNDEFINED_RECALCULATED_OPCODE; + } + if(dest == NULL) return UNABLE_GET_MEMORY; + int16_t status; + if(recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); + else status = operation(machine, dest, &immediate, width, carry); + if(status) return status; + return OK; } int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) { uint16_t temp_flags = 0; - if(arg == 0) return 0; + if(arg == 0) return OK; if(width == 8) __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); else if(width == 16) __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); else if(width == 32) __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); - else return -1; + else return BAD_WIDTH; if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) ); } + else return BAD_WIDTH; } else { @@ -884,10 +890,11 @@ int16_t perform_multiplication(v8086* machine, void* source, uint8_t signed_mul, : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) ); } + else return BAD_WIDTH; } bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) ); } + else return BAD_WIDTH; } else { @@ -940,8 +948,9 @@ int16_t perform_division(v8086* machine, void* source, uint8_t signed_div, uint8 : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) ); } + else return BAD_WIDTH; } - return 0; + return OK; } int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) @@ -954,14 +963,14 @@ int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) result = *((uint16_t*) source) & *((uint16_t*) dest); else if(width == 32) result = *((uint32_t*) source) & *((uint32_t*) dest); - else return -1; + else return BAD_WIDTH; uint8_t parrity = result & 1u; for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - return 0; + return OK; } int16_t perform_inc(v8086* machine, void* dest, uint8_t width) @@ -972,7 +981,7 @@ int16_t perform_inc(v8086* machine, void* dest, uint8_t width) if (width == 8) dest_before = *((uint8_t*) dest); else if(width == 16) dest_before = *((uint16_t*)dest); else if(width == 32) dest_before = *((uint32_t*)dest); - else return -1; + else return BAD_WIDTH; result = dest_before + 1; @@ -987,7 +996,7 @@ int16_t perform_inc(v8086* machine, void* dest, uint8_t width) if(width == 8) *((uint8_t*)dest) = result & 0xFFu; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return 0; + return OK; } int16_t perform_dec(v8086* machine, void* dest, uint8_t width) @@ -998,7 +1007,7 @@ int16_t perform_dec(v8086* machine, void* dest, uint8_t width) if (width == 8) dest_before = *((uint8_t*) dest); else if(width == 16) dest_before = *((uint16_t*)dest); else if(width == 32) dest_before = *((uint32_t*)dest); - else return -1; + else return BAD_WIDTH; result = dest_before - 1; @@ -1013,7 +1022,7 @@ int16_t perform_dec(v8086* machine, void* dest, uint8_t width) if(width == 8) *((uint8_t*)dest) = result & 0xFFu; else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return 0; + return OK; } int16_t parse_and_execute_instruction(v8086* machine) @@ -1023,6 +1032,8 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.segment_reg_select = DEFAULT; machine->internal_state.rep_prefix = NONE; + int16_t status = OK; + //Maybe opcode, an be also prefix uint8_t opcode; decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); @@ -1074,22 +1085,22 @@ int16_t parse_and_execute_instruction(v8086* machine) //ADD else if(opcode <= 5) { - perform_artihmetic_or_logical_instruction(machine, opcode, 0, perform_adding); + status = perform_artihmetic_or_logical_instruction(machine, opcode, 0, perform_adding); } //ADC else if(opcode >= 0x10 && opcode <= 0x15) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_adding); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_adding); } //SBB else if(opcode >= 0x18 && opcode <= 0x1d) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_subtracting); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_subtracting); } //SUB else if(opcode >= 0x28 && opcode <= 0x2d) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); } //INC general registers 16 or 32-bit else if(opcode >= 0x40 && opcode <= 0x47) @@ -1098,7 +1109,8 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest = NULL; if(machine->internal_state.operand_32_bit) width=32; dest = get_variable_length_register(machine, opcode & 7u, width); - perform_inc(machine, dest, width); + if(dest == NULL) return UNDEFINED_REGISTER; + status = perform_inc(machine, dest, width); } //DEC general registers 16 or 32-bit else if(opcode >= 0x48 && opcode <= 0x4f) @@ -1107,28 +1119,29 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest = NULL; if(machine->internal_state.operand_32_bit) width=32; dest = get_variable_length_register(machine, opcode & 7u, width); - perform_dec(machine, dest, width); + if(dest == NULL) return UNDEFINED_REGISTER; + status = perform_dec(machine, dest, width); } //LOGICAL operations //OR else if(opcode >= 0x08 && opcode <= 0x0d) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, 0, perform_or); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, 0, perform_or); } //AND else if(opcode >= 0x20 && opcode <= 0x25) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); } //XOR else if(opcode >= 0x30 && opcode <= 0x35) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_xor); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_xor); } //CMP else if(opcode >= 0x38 && opcode <= 0x3d) { - perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); + status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); } //GROUP 1 else if(opcode >= 0x80 && opcode <= 0x83) @@ -1139,28 +1152,34 @@ int16_t parse_and_execute_instruction(v8086* machine) switch((mod_rm >> 3u) & 7u) { case 0: //ADD - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_adding); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, + perform_adding); break; case 1: //OR - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_or); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_or); break; case 2: //ADC - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, bit_get(machine->regs.w.flags, 1u <regs.w.flags, 1u << CARRY_FLAG_BIT) != + 0, perform_adding); break; case 3: //SBB - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, bit_get(machine->regs.w.flags, 1u <regs.w.flags, 1u << CARRY_FLAG_BIT) != + 0, perform_subtracting); break; case 4: //AND - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_and); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_and); break; case 5: //SUB - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_subtracting); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, + perform_subtracting); break; case 6: //XOR - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_xor); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_xor); break; case 7: //CMP - perform_artihmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_cmp); + status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_cmp); break; } } @@ -1178,6 +1197,8 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest = get_memory_from_mode(machine, mod_rm, width); + if(dest == NULL) return UNABLE_GET_MEMORY; + switch((mod_rm >> 3u) & 7u) { case 0: //TEST @@ -1198,7 +1219,7 @@ int16_t parse_and_execute_instruction(v8086* machine) immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine -> internal_state.IPOffset += 4; } - perform_test(machine, &immediate, dest, width); + status = perform_test(machine, &immediate, dest, width); break; } case 2: //NOT @@ -1210,22 +1231,22 @@ int16_t parse_and_execute_instruction(v8086* machine) *((uint32_t*)dest) = ~(*((uint32_t*)dest)); break; case 3: //NEG - perform_neg(machine, dest, width); + status = perform_neg(machine, dest, width); break; case 4: //MUL - perform_multiplication(machine, dest, 0, width); + status = perform_multiplication(machine, dest, 0, width); break; case 5: //IMUL - perform_multiplication(machine, dest, 1, width); + status = perform_multiplication(machine, dest, 1, width); break; case 6: //DIV - perform_division(machine, dest, 0, width); + status = perform_division(machine, dest, 0, width); break; case 7: - perform_division(machine, dest, 1, width); + status = perform_division(machine, dest, 1, width); break; default: - return -1; + return BAD_REG; } } //PUSH Operations @@ -1236,9 +1257,10 @@ int16_t parse_and_execute_instruction(v8086* machine) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; reg = get_variable_length_register(machine, opcode & 7u, width); + if(reg == NULL) return UNDEFINED_REGISTER; if(width==16) push_word(machine, *((uint16_t*)reg)); else if(width==32) push_dword(machine, *((uint32_t*)reg)); - else return -1; + else return BAD_WIDTH; } //PUSH CS else if(opcode == 0x0e) @@ -1263,9 +1285,10 @@ int16_t parse_and_execute_instruction(v8086* machine) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 16; reg = get_variable_length_register(machine, opcode & 7u, width); + if(reg == NULL) return UNDEFINED_REGISTER; if(width==16) *((uint16_t*)reg) = pop_word(machine); else if(width==32) *((uint32_t*)reg) = pop_dword(machine); - else return -1; + else return BAD_WIDTH; } //POP DS else if(opcode == 0x1f) @@ -1290,15 +1313,17 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t temp; uint16_t* regA = get_word_register(machine, AX); uint16_t* regB = get_word_register(machine, opcode & 7u); + if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; temp = *regA; *regA = *regB; *regB = temp; } else if(width == 32) { - uint16_t temp; + uint32_t temp; uint32_t* regA = get_dword_register(machine, EAX); uint32_t* regB = get_dword_register(machine, opcode & 7u); + if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; temp = *regA; *regA = *regB; *regB = temp; @@ -1314,6 +1339,8 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint8_t* source = get_byte_register(machine, (mod_rm >> 3u) & 7u); uint8_t* dest = get_memory_from_mode(machine, mod_rm, 8); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; uint8_t temp; temp = *source; *source = *dest; @@ -1325,6 +1352,8 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint32_t* source = get_dword_register(machine, (mod_rm >> 3u) & 7u); uint32_t* dest = get_memory_from_mode(machine, mod_rm, 32); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; uint32_t temp; temp = *source; *source = *dest; @@ -1334,12 +1363,13 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint16_t* source = get_word_register(machine, (mod_rm >> 3u) & 7u); uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; uint16_t temp; temp = *source; *source = *dest; *dest = temp; } - } } //ROLS and RORS Group (Group 2) @@ -1354,31 +1384,31 @@ int16_t parse_and_execute_instruction(v8086* machine) else width = 16; } void* dest = get_memory_from_mode(machine, mod_rm, width); - + if(dest == NULL) return UNABLE_GET_MEMORY; switch((mod_rm >> 3u) & 7u) { case 0: - perform_rol(machine, dest, arg, width); + status = perform_rol(machine, dest, arg, width); break; case 1: - perform_ror(machine, dest, arg, width); + status = perform_ror(machine, dest, arg, width); break; case 2: - perform_rcl(machine, dest, arg, width); + status = perform_rcl(machine, dest, arg, width); break; case 3: - perform_rcr(machine, dest, arg, width); + status = perform_rcr(machine, dest, arg, width); break; case 4: - perform_shl(machine, dest, arg, width); + status = perform_shl(machine, dest, arg, width); break; case 5: - perform_shr(machine, dest, arg, width); + status = perform_shr(machine, dest, arg, width); break; case 6: - return -1; + return UNDEFINED_OPCODE; case 7: - perform_sar(machine, dest, arg, width); + status = perform_sar(machine, dest, arg, width); break; } } @@ -1514,7 +1544,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->regs.w.cx) jump = 1; break; default: - break; + return UNKNOWN_ERROR; } if(jump) @@ -1526,6 +1556,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint8_t* reg = get_byte_register(machine, opcode & 0x7u); uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + if(reg == NULL) return UNDEFINED_REGISTER; machine->internal_state.IPOffset += 1; *reg = imm; } @@ -1535,6 +1566,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) { uint32_t* reg = get_dword_register(machine, (opcode - 0xb8u) & 0x7u); + if(reg == NULL) return UNDEFINED_REGISTER; uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; *reg = imm; @@ -1542,6 +1574,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else { uint16_t* reg = get_word_register(machine, (opcode - 0xb8u) & 0x7u); + if(reg == NULL) return UNDEFINED_REGISTER; uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; *reg = imm; @@ -1552,26 +1585,26 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - uint16_t segment = *select_segment_register(machine, DS) ? machine->internal_state.segment_reg_select == DEFAULT : *select_segment_register(machine, machine->internal_state.segment_reg_select); - + uint16_t* segment = machine->internal_state.segment_reg_select == DEFAULT ? select_segment_register(machine, DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; switch (opcode) { case 0xa0: - machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(segment, offset)); + machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); break; case 0xa1: - if(machine->internal_state.operand_32_bit) machine->regs.d.eax = read_dword_from_pointer(machine->Memory, get_absolute_address(segment, offset)); - else machine->regs.x.ax = read_word_from_pointer(machine->Memory, get_absolute_address(segment, offset)); + if(machine->internal_state.operand_32_bit) machine->regs.d.eax = read_dword_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); + else machine->regs.x.ax = read_word_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); break; case 0xa2: - write_byte_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.h.al); + write_byte_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.h.al); break; case 0xa3: - if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.d.eax); - else write_word_to_pointer(machine->Memory, get_absolute_address(segment, offset), machine->regs.x.ax); + if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.d.eax); + else write_word_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.x.ax); break; default: - break; + return UNKNOWN_ERROR; } } //MOV r8/r16/r32, rm8/rm16/rm32 or MOV rm8/rm16/rm32, r8/r16/r32 @@ -1588,27 +1621,35 @@ int16_t parse_and_execute_instruction(v8086* machine) case 0x88: source = get_byte_register(machine, (mod_rm >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm, 8); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x89: source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); dest = get_memory_from_mode(machine, mod_rm, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); else *((uint32_t*)dest) = *((uint32_t*) source); break; case 0x8a: dest = get_byte_register(machine, (mod_rm >> 3u) & 7u); source = get_memory_from_mode(machine, mod_rm, 8); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x8b: dest = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); source = get_memory_from_mode(machine, mod_rm, width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); else *((uint32_t*)dest) = *((uint32_t*) source); break; default: - break; + return UNKNOWN_ERROR; } } //MOV Segment to/from r/m @@ -1622,11 +1663,15 @@ int16_t parse_and_execute_instruction(v8086* machine) { source = select_segment_register(machine, (mod_rm >> 3u) & 7u); dest = get_memory_from_mode(machine, mod_rm, 16); + if(source == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; } else { dest = select_segment_register(machine, (mod_rm >> 3u) & 7); source = get_memory_from_mode(machine, mod_rm, 16); + if(dest == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; } *dest = *source; } @@ -1640,6 +1685,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); + if(mem == NULL) return UNABLE_GET_MEMORY; *mem = immediate; } else @@ -1649,6 +1695,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); + if(mem == NULL) return UNABLE_GET_MEMORY; *mem = immediate; } else @@ -1656,11 +1703,10 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); + if(mem == NULL) return UNABLE_GET_MEMORY; *mem = immediate; } - } - } //TEST GROUP else if(opcode == 0x84) @@ -1670,7 +1716,9 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; uint8_t* reg = get_byte_register(machine, (mod_rm >> 3u) & 7u); uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); - perform_test(machine, reg, memory, 8); + if(reg == NULL) return UNDEFINED_REGISTER; + if(memory == NULL) return UNABLE_GET_MEMORY; + status = perform_test(machine, reg, memory, 8); } else if(opcode == 0x85) { @@ -1681,7 +1729,9 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) width = 32; void* source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); void* dest = get_memory_from_mode(machine, mod_rm, width); - perform_test(machine, source, dest, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + status = perform_test(machine, source, dest, width); } else if(opcode == 0xa8) { @@ -1689,6 +1739,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* reg = get_byte_register(machine, AL); + if(reg == NULL) return UNDEFINED_REGISTER; uint8_t result = *reg & immediate; bit_clear(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; } + else return BAD_WIDTH; void* reg = get_variable_length_register(machine, AX, width); + if(reg == NULL) return UNDEFINED_REGISTER; if(width == 16) result = *((uint16_t*) reg) & immediate; @@ -1739,7 +1792,8 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t* dest; if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; @@ -1758,7 +1812,8 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t* dest_segment = select_segment_register(machine, ES); if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; @@ -1798,7 +1853,8 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; @@ -1845,14 +1901,15 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) width=32; else width = 16; } - + + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; do{ dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); source = get_variable_length_register(machine, AL, width); - + if(source == NULL) return UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); @@ -1876,14 +1933,14 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; do{ source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); dest = get_variable_length_register(machine, AL, width); - + if(dest == NULL) return UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); @@ -1907,13 +1964,14 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) width=32; else width = 16; } - + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; do{ dest = get_variable_length_register(machine, AX, width); source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); + if(dest == NULL) return UNDEFINED_REGISTER; if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); @@ -2095,8 +2153,9 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t* segment_register; if(opcode == 0xc4) segment_register = select_segment_register(machine, ES); else segment_register = select_segment_register(machine, DS); - + if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); + if(source == NULL) return UNABLE_GET_MEMORY; if(machine->internal_state.operand_32_bit) { @@ -2326,6 +2385,7 @@ int16_t parse_and_execute_instruction(v8086* machine) segment = select_segment_register(machine, machine->internal_state.segment_reg_select); else segment = select_segment_register(machine, DS); + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); } //GROUP 4 @@ -2336,17 +2396,17 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t width = 8; void* dest = get_memory_from_mode(machine, mod_rm, width); - + if(dest == NULL) return UNABLE_GET_MEMORY; switch((mod_rm >> 3u) & 7u) { case 0: //INC rm8 - perform_inc(machine, dest, width); + status = perform_inc(machine, dest, width); break; case 1: //DEC rm8 - perform_dec(machine, dest, width); + status = perform_dec(machine, dest, width); break; default: - return -1; + return UNDEFINED_OPCODE; } } //GROUP 5 @@ -2358,21 +2418,21 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) width = 32; void* dest = get_memory_from_mode(machine, mod_rm, width); - + if(dest == NULL) return UNABLE_GET_MEMORY; switch((mod_rm >> 3u) & 7u) { case 0: //INC rm8 - perform_inc(machine, dest, width); + status = perform_inc(machine, dest, width); break; case 1: //DEC rm8 - perform_dec(machine, dest, width); + status = perform_dec(machine, dest, width); break; case 2: //Near absolute indirect call machine->IP += machine->internal_state.IPOffset; push_word(machine, machine->IP); if(width == 16) machine->IP += *((uint16_t*) dest); - else return -1; + else return BAD_WIDTH; machine->internal_state.IPOffset = 0; break; case 3: // Far absolute indirect call @@ -2386,7 +2446,7 @@ int16_t parse_and_execute_instruction(v8086* machine) case 4: //Near absolute indirect jmp if(width == 16) machine->IP += *((uint16_t*) dest); - else return -1; + else return BAD_WIDTH; machine->internal_state.IPOffset = 0; break; case 5: //Far absolute indirect jmp @@ -2395,13 +2455,12 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset = 0; break; case 6: - if(width == 16) - push_word(machine, *((uint16_t*)dest)); - else if(width == 32) - push_dword(machine, *((uint32_t*)dest)); - else return -1; + if(width == 16) push_word(machine, *((uint16_t*)dest)); + else if(width == 32) push_dword(machine, *((uint32_t*)dest)); + else return BAD_WIDTH; + break; default: - return -1; + return UNDEFINED_OPCODE; } } //GROUP 1A @@ -2419,7 +2478,8 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width == 32) *((uint32_t*)dest) = pop_dword(machine); } + else return UNDEFINED_OPCODE; recalculate_ip: machine->IP += machine->internal_state.IPOffset; - return 0; + return status; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index a2aaaead..daf1b29c 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -11,6 +11,22 @@ typedef enum _repeat_prefix { NONE, REPNE, REP_REPE } repeat_prefix; +typedef enum _machine_status { + OK = 0, + UNDEFINED_OPCODE = -1, + UNDEFINED_REGISTER = -2, + UNDEFINED_SEGMENT_REGISTER = -3, + UNABLE_GET_MEMORY = -4, + BAD_MOD_RM = -5, + BAD_RM = -6, + BAD_MOD = -7, + BAD_REG = -8, + BAD_WIDTH = -9, + UNDEFINED_RECALCULATED_OPCODE = -10, + BAD_INT_NUMBER = -11, + UNKNOWN_ERROR = -69 +} machine_status; + struct DWORDREGS { uint32_t edi; uint32_t esi; From 2d24a30bba3ed65ebfa792eb30075f690037ca12 Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 23 May 2020 03:37:45 +0200 Subject: [PATCH 055/165] Starting Refactor + Starting work with 32-bit addressing --- os/kernel/src/kernel.c | 23 +- os/kernel/src/v8086/memory_operations.h | 69 +++ os/kernel/src/v8086/mod_rm_parsing.c | 425 ++++++++++++++++++ os/kernel/src/v8086/mod_rm_parsing.h | 16 + os/kernel/src/v8086/stack.h | 28 ++ os/kernel/src/v8086/v8086.c | 550 ++++-------------------- os/kernel/src/v8086/v8086.h | 34 +- 7 files changed, 679 insertions(+), 466 deletions(-) create mode 100644 os/kernel/src/v8086/memory_operations.h create mode 100644 os/kernel/src/v8086/mod_rm_parsing.c create mode 100644 os/kernel/src/v8086/mod_rm_parsing.h create mode 100644 os/kernel/src/v8086/stack.h diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 5bfd22f7..37c84271 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -34,7 +34,6 @@ #include #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" - #include "v8086/v8086.h" typedef struct _linesStruct @@ -396,6 +395,9 @@ int kmain() switch_active_terminal(0); v8086* v8086 = v8086_create_machine(); + v8086->regs.h.ah = 0x00; + v8086->regs.h.al = 0x13; + int16_t status = v8086_call_int(v8086, 0x10); // terminal_manager_print_string(p, "CIASTKO"); // p = process_manager_create_process("A:/ENV/SHELL.ELF", "", 1000, false); // attach_process_to_terminal(ts[0].terminal_id, process_manager_get_process(p)); @@ -407,7 +409,24 @@ int kmain() //terminal_manager_print_string(ts[2].active_process->id, "CZEKOLADA!"); //process_manager_run(); //destroy_active_terminal(); - + char str[100] = ""; + vga_printstring("IP: "); + uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); + uint16_t CS = *(uint16_t*)(v8086->Memory + 0x10 * 4 + 2); + itoa(IP, str, 10); + vga_printstring(str); + vga_newline(); + vga_printstring("CS: "); + itoa(CS, str, 10); + vga_printstring(str); + vga_newline(); + for(uint32_t i = CS * 16 + IP; i < (CS * 16 + IP + 16); i++) + { + uint8_t mem = v8086->Memory[i]; + itoa(mem, str, 16); + vga_printstring(str); + vga_printstring(" "); + } while (1); // { // sleep(5000); diff --git a/os/kernel/src/v8086/memory_operations.h b/os/kernel/src/v8086/memory_operations.h new file mode 100644 index 00000000..04584001 --- /dev/null +++ b/os/kernel/src/v8086/memory_operations.h @@ -0,0 +1,69 @@ +#ifndef V8086_MEMORY_OPERATIONS_H +#define V8086_MEMORY_OPERATIONS_H + +static inline uint32_t get_absolute_address(uint32_t segment, uint32_t offset) +{ + return segment * 0x10 + offset; +} + +static inline uint8_t* get_byte_pointer(uint8_t* memory, uint32_t absolute_address) +{ + return memory + absolute_address; +} + +static inline uint16_t* get_word_pointer(uint8_t* memory, uint32_t absolute_address) +{ + return (uint16_t*)(memory + absolute_address); +} + +static inline uint32_t* get_dword_pointer(uint8_t* memory, uint32_t absolute_address) +{ + return (uint32_t*)(memory + absolute_address); +} + +static inline void* get_variable_length_pointer(uint8_t* memory, uint32_t absolute_address, uint8_t width) +{ + switch(width) + { + case 8: + return get_byte_pointer(memory, absolute_address); + case 16: + return get_word_pointer(memory, absolute_address); + case 32: + return get_dword_pointer(memory, absolute_address); + default: + return NULL; + } +} + +static inline uint8_t read_byte_from_pointer(const uint8_t* memory, uint32_t absolute_address) +{ + return *(memory + absolute_address); +} + +static inline uint16_t read_word_from_pointer(uint8_t* memory, uint32_t absolute_address) +{ + return *get_word_pointer(memory, absolute_address); +} + +static inline uint32_t read_dword_from_pointer(uint8_t* memory, uint32_t absolute_address) +{ + return *get_dword_pointer(memory, absolute_address); +} + +static inline void write_byte_to_pointer(uint8_t* memory, uint32_t absolute_address, uint8_t value) +{ + *(get_byte_pointer(memory, absolute_address)) = value; +} + +static inline void write_word_to_pointer(uint8_t* memory, uint32_t absolute_address, uint16_t value) +{ + *(get_word_pointer(memory, absolute_address)) = value; +} + +static inline void write_dword_to_pointer(uint8_t* memory, uint32_t absolute_address, uint32_t value) +{ + *(get_dword_pointer(memory, absolute_address)) = value; +} + +#endif //V8086_MEMORY_OPERATIONS_H diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c new file mode 100644 index 00000000..d3c30fa4 --- /dev/null +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -0,0 +1,425 @@ +#include "mod_rm_parsing.h" +#include +#include "memory_operations.h" + +uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) +{ + switch(reg_field) + { + case AL: + return &(machine->regs.h.al); + case AH: + return &(machine->regs.h.ah); + case BL: + return &(machine->regs.h.bl); + case BH: + return &(machine->regs.h.bh); + case CL: + return &(machine->regs.h.cl); + case CH: + return &(machine->regs.h.ch); + case DL: + return &(machine->regs.h.dl); + case DH: + return &(machine->regs.h.dh); + default: + return NULL; + } + return NULL; +} + +uint16_t* get_word_register(v8086* machine, uint8_t reg_field) +{ + switch(reg_field) + { + case AX: + return &(machine->regs.x.ax); + case CX: + return &(machine->regs.x.cx); + case DX: + return &(machine->regs.x.dx); + case BX: + return &(machine->regs.x.bx); + case SP: + return &(machine->regs.x.sp); + case BP: + return &(machine->regs.x.bp); + case SI: + return &(machine->regs.x.si); + case DI: + return &(machine->regs.x.di); + default: + return NULL; + } + return NULL; +} + +uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) +{ + switch(reg_field) + { + case EAX: + return &(machine->regs.d.eax); + case ECX: + return &(machine->regs.d.ecx); + case EDX: + return &(machine->regs.d.edx); + case EBX: + return &(machine->regs.d.ebx); + case ESP: + return &(machine->regs.d.esp); + case EBP: + return &(machine->regs.d.ebp); + case ESI: + return &(machine->regs.d.esi); + case EDI: + return &(machine->regs.d.edi); + default: + return NULL; + } + return NULL; +} + +void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width) +{ + switch (width) + { + case 8: + return get_byte_register(machine, reg_field); + case 16: + return get_word_register(machine, reg_field); + case 32: + return get_dword_register(machine, reg_field); + default: + return NULL; + } +} + +uint16_t* select_segment_register(v8086* machine, segment_register_select select) +{ + switch(select) + { + case CS: + return &(machine->sregs.cs); + case DS: + return &(machine->sregs.ds); + case SS: + return &(machine->sregs.ss); + case ES: + return &(machine->sregs.es); + case FS: + return &(machine->sregs.fs); + case GS: + return &(machine->sregs.gs); + default: + return NULL; + } +} + +int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset) +{ + uint16_t* segment_register = NULL; + if(machine->internal_state.segment_reg_select != DEFAULT) + segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); + else + { + switch (mod_rm & 7u) + { + case 0: + case 1: + case 4: + case 5: + case 7: + segment_register = select_segment_register(machine, DS); + break; + case 6: + if((mod_rm >> 6u) == 0) segment_register = select_segment_register(machine, DS); + else segment_register = select_segment_register(machine, SS); + break; + default: + segment_register = select_segment_register(machine, SS); + break; + } + } + + if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; + + *segment = *segment_register; + + switch(mod_rm >> 6u) //Parsing mod than parsing rm + { + case 0: + switch(mod_rm & 7u){ + case 0: + *offset = machine->regs.x.bx + machine->regs.x.si; + return OK; + case 1: + *offset = machine->regs.x.bx + machine->regs.x.di; + return OK; + case 2: + *offset = machine->regs.x.bp + machine->regs.x.si; + return OK; + case 3: + *offset = machine->regs.x.bp + machine->regs.x.di; + return OK; + case 4: + *offset = machine->regs.x.si; + return OK; + case 5: + *offset = machine->regs.x.di; + return OK; + case 6:{ + *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + (machine->internal_state.IPOffset))); + machine->internal_state.IPOffset += 1; + return OK; + } + case 7: + *offset = machine->regs.x.bx; + return OK; + default: + return BAD_RM; + } + case 1:{ + int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + switch(mod_rm & 7u){ + case 0: + *offset = machine->regs.x.bx + machine->regs.x.si + disp; + return OK; + case 1: + *offset = machine->regs.x.bx + machine->regs.x.di + disp; + return OK; + case 2: + *offset = machine->regs.x.bp + machine->regs.x.si + disp; + return OK; + case 3: + *offset = machine->regs.x.bp + machine->regs.x.di + disp; + return OK; + case 4: + *offset = machine->regs.x.si + disp; + return OK; + case 5: + *offset = machine->regs.x.di + disp; + return OK; + case 6: + *offset = machine->regs.x.bp + disp; + return OK; + case 7: + *offset = machine->regs.x.bx + disp; + return OK; + default: + return BAD_RM; + } + } + case 2:{ + uint16_t disp = (uint16_t) read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + switch(mod_rm & 7u){ + case 0: + *offset = machine->regs.x.bx + machine->regs.x.si + disp; + return OK; + case 1: + *offset = machine->regs.x.bx + machine->regs.x.di + disp; + return OK; + case 2: + *offset = machine->regs.x.bp + machine->regs.x.si + disp; + return OK; + case 3: + *offset = machine->regs.x.bp + machine->regs.x.di + disp; + return OK; + case 4: + *offset = machine->regs.x.si + disp; + return OK; + case 5: + *offset = machine->regs.x.di + disp; + return OK; + case 6: + *offset = machine->regs.x.bp + disp; + return OK; + case 7: + *offset = machine->regs.x.bx + disp; + return OK; + default: + return BAD_RM; + } + } + default: + return BAD_MOD; + } + return UNKNOWN_ERROR; +} + +int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t* segment, uint32_t *offset) +{ + uint8_t sib = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t scale = sib >> 6u; + uint8_t index = (sib >> 3u) & 7u; + uint8_t base = sib & 7u; + + switch (index) { + case 0: + *offset = machine->regs.d.eax; + break; + case 1: + *offset = machine->regs.d.ecx; + break; + case 2: + *offset = machine->regs.d.edx; + break; + case 3: + *offset = machine->regs.d.ebx; + break; + case 4: + *offset = 0; + break; + case 5: + *offset = machine->regs.d.ebp; + segment = select_segment_register(machine, SS); + break; + case 6: + *offset = machine->regs.d.esi; + break; + case 7: + *offset = machine->regs.d.edi; + break; + default: + return BAD_INDEX; + } + *offset <<= scale; + + switch (base){ + case 0: + *offset += machine->regs.d.eax; + break; + case 1: + *offset += machine->regs.d.ecx; + break; + case 2: + *offset += machine->regs.d.edx; + break; + case 3: + *offset += machine->regs.d.ebx; + break; + case 4: + *offset += machine->regs.d.esp; + break; + case 5: + if (mod == 0) + { + uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + *offset += disp; + } + else if (mod == 1) + { + uint8_t disp = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + *offset += disp; + *offset += machine->regs.d.ebp; + segment = select_segment_register(machine, SS); + } + else if(mod == 2) + { + uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + *offset += disp; + *offset += machine->regs.d.ebp; + segment = select_segment_register(machine, SS); + } + else{ + return BAD_BASE; + } + break; + case 6: + *offset += machine->regs.d.esi; + break; + case 7: + *offset += machine->regs.d.edi; + break; + default: + return BAD_BASE; + } + return OK; +} + +int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, uint16_t *segment, uint32_t *offset) { + uint16_t* segment_register = NULL; + uint8_t mod = mod_rm >> 6u; //Parsing mod than parsing rm + uint8_t rm = mod_rm & 7u; + + switch(mod) + { + case 0: + switch(rm) + { + case 0: + *offset = machine->regs.d.eax; + break; + case 1: + *offset = machine->regs.d.ecx; + break; + case 2: + *offset = machine->regs.d.edx; + break; + case 3: + *offset = machine->regs.d.ebx; + break; + case 4: // SIB + read_and_parse_sib(machine, mod, segment_register, offset); + break; + case 5:{ + uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + *offset = disp; + break; + } + case 6: + *offset = machine->regs.d.esi; + break; + case 7: + *offset = machine->regs.d.edi; + break; + default: + return BAD_RM; + } + break; + } + return 0; +} + +void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) +{ + uint16_t segment; + uint16_t offset; + + switch(mod_rm >> 6u) //Parsing mod than parsing rm + { + case 0: + case 1: + case 2: + calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); + case 3: + switch(width){ + case 8: + return get_byte_register(machine, mod_rm & 7u); + case 16: + return get_word_register(machine, mod_rm & 7u); + case 32: + return get_dword_register(machine, mod_rm & 7u); + default: + return NULL; + } + } + return NULL; +} + diff --git a/os/kernel/src/v8086/mod_rm_parsing.h b/os/kernel/src/v8086/mod_rm_parsing.h new file mode 100644 index 00000000..0f3cf90b --- /dev/null +++ b/os/kernel/src/v8086/mod_rm_parsing.h @@ -0,0 +1,16 @@ +#ifndef V8086_MOD_RM_PARSING_H +#define V8086_MOD_RM_PARSING_H + +#include "v8086.h" + +uint8_t* get_byte_register(v8086* machine, uint8_t reg_field); +uint16_t* get_word_register(v8086* machine, uint8_t reg_field); +uint32_t* get_dword_register(v8086* machine, uint8_t reg_field); +void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width); + +uint16_t* select_segment_register(v8086* machine, segment_register_select select); +int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset); +int16_t calculate_segment_offset_from_mode_32(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset); +void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width); + +#endif //V8086_MOD_RM_PARSING_H diff --git a/os/kernel/src/v8086/stack.h b/os/kernel/src/v8086/stack.h new file mode 100644 index 00000000..245f7182 --- /dev/null +++ b/os/kernel/src/v8086/stack.h @@ -0,0 +1,28 @@ +#ifndef V8086_STACK_H +#define V8086_STACK_H + +static inline void push_word(v8086* machine, uint16_t value) +{ + write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); +} + +static inline void push_dword(v8086* machine, uint32_t value) +{ + write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 4), value); +} + +static inline uint16_t pop_word(v8086* machine) +{ + uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + machine->regs.w.sp += 2; + return v; +} + +static inline uint32_t pop_dword(v8086* machine) +{ + uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + machine->regs.w.sp += 4; + return v; +} + +#endif //V8086_STACK_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 19fdeef4..34c9c9e1 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -2,6 +2,9 @@ #include "../memory/heap/heap.h" #include #include "../assembly/io.h" +#include "./memory_operations.h" +#include "./stack.h" +#include "./mod_rm_parsing.h" #define bit_get(p,m) ((p) & (m)) #define bit_set(p,m) ((p) |= (m)) @@ -18,111 +21,8 @@ #define DIRECTION_FLAG_BIT 10u #define OVERFLOW_FLAG_BIT 11u -enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; -enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; -enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; - int16_t parse_and_execute_instruction(v8086* machine); -static inline uint16_t get_absolute_address(uint16_t segment, uint16_t offset) -{ - return segment * 16 + offset; -} - -static inline uint8_t* get_byte_pointer(uint8_t* memory, uint16_t offset) -{ - return memory + offset; -} - -static inline uint16_t* get_word_pointer(uint8_t* memory, uint16_t offset) -{ - return (uint16_t*)(memory + offset); -} - -static inline uint32_t* get_dword_pointer(uint8_t* memory, uint16_t offset) -{ - return (uint32_t*)(memory + offset); -} - -static inline void* get_variable_length_pointer(uint8_t* memory, uint16_t offset, uint8_t width) -{ - switch(width) - { - case 8: - return get_byte_pointer(memory, offset); - case 16: - return get_word_pointer(memory, offset); - case 32: - return get_dword_pointer(memory, offset); - default: - return NULL; - } -} - -static inline uint8_t read_byte_from_pointer(const uint8_t* memory, uint16_t offset) -{ - return *(memory + offset); -} - -static inline uint16_t read_word_from_pointer(uint8_t* memory, uint16_t offset) -{ - return *get_word_pointer(memory, offset); -} - -static inline uint32_t read_dword_from_pointer(uint8_t* memory, uint16_t offset) -{ - return *get_dword_pointer(memory, offset); -} - -static inline void write_byte_to_pointer(uint8_t* memory, uint16_t offset, uint8_t value) -{ - *(get_byte_pointer(memory, offset)) = value; -} - -static inline void write_word_to_pointer(uint8_t* memory, uint16_t offset, uint16_t value) -{ - *(get_word_pointer(memory, offset)) = value; -} - -static inline void write_dword_to_pointer(uint8_t* memory, uint16_t offset, uint32_t value) -{ - *(get_dword_pointer(memory, offset)) = value; -} - -static inline uint16_t read_word_from_double_pointer(uint8_t* memory, uint16_t offset) -{ - return *(get_word_pointer(memory, read_word_from_pointer(memory, offset))); -} - -static inline void write_word_from_double_pointer(uint8_t* memory, uint16_t offset, uint16_t value) -{ - *(get_word_pointer(memory, read_word_from_pointer(memory, offset))) = value; -} - -static inline void push_word(v8086* machine, uint16_t value) -{ - write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); -} - -static inline void push_dword(v8086* machine, uint32_t value) -{ - write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 4), value); -} - -static inline uint16_t pop_word(v8086* machine) -{ - uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); - machine->regs.w.sp += 2; - return v; -} - -static inline uint32_t pop_dword(v8086* machine) -{ - uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); - machine->regs.w.sp += 4; - return v; -} - v8086* v8086_create_machine() { v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); @@ -130,7 +30,7 @@ v8086* v8086_create_machine() memset(machine, 0, sizeof(v8086)); machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; - machine->IP = 0xfff0; + machine->IP.w.ip = 0xfff0; memcpy(machine->Memory, (void*)0xc0000000, 0x100000); return machine; @@ -138,7 +38,7 @@ v8086* v8086_create_machine() int16_t v8086_call_function(v8086* machine) { - while(!(machine->IP == 0xFFFF && machine->sregs.cs == 0xFFFF)) + while(!(machine->IP.w.ip == 0xFFFF && machine->sregs.cs == 0xFFFF)) { int16_t status = parse_and_execute_instruction(machine); if(status != OK) return status; @@ -149,8 +49,8 @@ int16_t v8086_call_function(v8086* machine) int16_t v8086_call_int(v8086* machine, int16_t num) { if ((num < 0) || (num > 0xFF)) return BAD_INT_NUMBER; - machine -> IP = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4)); - machine -> sregs.cs = read_word_from_double_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + machine -> IP.w.ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); + machine -> sregs.cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); push_word(machine, machine->regs.w.flags); push_word(machine, 0xFFFF); push_word(machine, 0xFFFF); @@ -159,280 +59,6 @@ int16_t v8086_call_int(v8086* machine, int16_t num) return num; } -uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case AL: - return &(machine->regs.h.al); - case AH: - return &(machine->regs.h.ah); - case BL: - return &(machine->regs.h.bl); - case BH: - return &(machine->regs.h.bh); - case CL: - return &(machine->regs.h.cl); - case CH: - return &(machine->regs.h.ch); - case DL: - return &(machine->regs.h.dl); - case DH: - return &(machine->regs.h.dh); - default: - return NULL; - } - return NULL; -} - -uint16_t* get_word_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case AX: - return &(machine->regs.x.ax); - case CX: - return &(machine->regs.x.cx); - case DX: - return &(machine->regs.x.dx); - case BX: - return &(machine->regs.x.bx); - case SP: - return &(machine->regs.x.sp); - case BP: - return &(machine->regs.x.bp); - case SI: - return &(machine->regs.x.si); - case DI: - return &(machine->regs.x.di); - default: - return NULL; - } - return NULL; -} - -uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case EAX: - return &(machine->regs.d.eax); - case ECX: - return &(machine->regs.d.ecx); - case EDX: - return &(machine->regs.d.edx); - case EBX: - return &(machine->regs.d.ebx); - case ESP: - return &(machine->regs.d.esp); - case EBP: - return &(machine->regs.d.ebp); - case ESI: - return &(machine->regs.d.esi); - case EDI: - return &(machine->regs.d.edi); - default: - return NULL; - } - return NULL; -} - -void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width) -{ - switch (width) - { - case 8: - return get_byte_register(machine, reg_field); - case 16: - return get_word_register(machine, reg_field); - case 32: - return get_dword_register(machine, reg_field); - default: - return NULL; - } -} - -uint16_t* select_segment_register(v8086* machine, segment_register_select select) -{ - switch(select) - { - case CS: - return &(machine->sregs.cs); - case DS: - return &(machine->sregs.ds); - case SS: - return &(machine->sregs.ss); - case ES: - return &(machine->sregs.es); - case FS: - return &(machine->sregs.fs); - case GS: - return &(machine->sregs.gs); - default: - return NULL; - } -} - -int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset) -{ - uint16_t* segment_register = NULL; - if(machine->internal_state.segment_reg_select != DEFAULT) - segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); - else - { - switch (mod_rm & 7u) - { - case 0: - case 1: - case 4: - case 5: - case 7: - segment_register = select_segment_register(machine, DS); - break; - case 6: - if((mod_rm >> 6u) == 0) segment_register = select_segment_register(machine, DS); - else segment_register = select_segment_register(machine, SS); - break; - default: - segment_register = select_segment_register(machine, SS); - break; - } - } - - if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; - - *segment = *segment_register; - - switch(mod_rm >> 6u) //Parsing mod than parsing rm - { - case 0: - switch(mod_rm & 7u){ - case 0: - *offset = machine->regs.x.bx + machine->regs.x.si; - return OK; - case 1: - *offset = machine->regs.x.bx + machine->regs.x.di; - return OK; - case 2: - *offset = machine->regs.x.bp + machine->regs.x.si; - return OK; - case 3: - *offset = machine->regs.x.bp + machine->regs.x.di; - return OK; - case 4: - *offset = machine->regs.x.si; - return OK; - case 5: - *offset = machine->regs.x.di; - return OK; - case 6:{ - *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + (machine->internal_state.IPOffset))); - machine->internal_state.IPOffset += 1; - return OK; - } - case 7: - *offset = machine->regs.x.bx; - return OK; - default: - return BAD_RM; - } - case 1:{ - int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - switch(mod_rm & 7u){ - case 0: - *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return OK; - case 1: - *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return OK; - case 2: - *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return OK; - case 3: - *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return OK; - case 4: - *offset = machine->regs.x.si + disp; - return OK; - case 5: - *offset = machine->regs.x.di + disp; - return OK; - case 6: - *offset = machine->regs.x.bp + disp; - return OK; - case 7: - *offset = machine->regs.x.bx + disp; - return OK; - default: - return BAD_RM; - } - } - case 2:{ - uint16_t disp = (uint16_t) read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - switch(mod_rm & 7u){ - case 0: - *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return OK; - case 1: - *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return OK; - case 2: - *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return OK; - case 3: - *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return OK; - case 4: - *offset = machine->regs.x.si + disp; - return OK; - case 5: - *offset = machine->regs.x.di + disp; - return OK; - case 6: - *offset = machine->regs.x.bp + disp; - return OK; - case 7: - *offset = machine->regs.x.bx + disp; - return OK; - default: - return BAD_RM; - } - } - default: - return BAD_MOD; - } - return UNKNOWN_ERROR; -} - -void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) -{ - uint16_t segment; - uint16_t offset; - - switch(mod_rm >> 6u) //Parsing mod than parsing rm - { - case 0: - case 1: - case 2: - calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); - case 3: - switch(width){ - case 8: - return get_byte_register(machine, mod_rm & 7u); - case 16: - return get_word_register(machine, mod_rm & 7u); - case 32: - return get_dword_register(machine, mod_rm & 7u); - default: - return NULL; - } - } - return NULL; -} - int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) { uint64_t result = 0; @@ -597,7 +223,7 @@ int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uin int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) { //Maybe Mod/RM, Can be Immediate - uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 16; @@ -640,9 +266,9 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc dest = get_variable_length_register(machine, AX, width); if(dest == NULL) return UNDEFINED_REGISTER; if(width == 32) - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); else - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP - 1 + machine->internal_state.IPOffset)); + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += ((width / 8) - 1); break; default: @@ -664,19 +290,19 @@ int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t case 2: //OPERATION rm8, imm8 width = 8; dest = get_memory_from_mode(machine, mod_rm, width); - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; break; case 1: //OPERATION rm16, imm16 or rm32, imm32 if(machine->internal_state.operand_32_bit) { width = 32; - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; } else { width = 16; - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; } dest = get_memory_from_mode(machine, mod_rm, width); @@ -684,7 +310,7 @@ int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t case 3: //OPERATION rm16, imm8, or rm32, imm8 if(machine->internal_state.operand_32_bit) width = 32; else width = 16; - signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; dest = get_memory_from_mode(machine, mod_rm, width); break; @@ -1036,7 +662,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //Maybe opcode, an be also prefix uint8_t opcode; - decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); + uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; //PREFIXES @@ -1146,7 +774,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //GROUP 1 else if(opcode >= 0x80 && opcode <= 0x83) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t recalculated_opcode = opcode - 0x80; switch((mod_rm >> 3u) & 7u) @@ -1186,7 +814,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //GROUP 3 else if(opcode >= 0xf6 && opcode <= 0xf7) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 8; if(opcode == 0xf7) @@ -1206,17 +834,17 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t immediate; if(width == 8) { - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine -> internal_state.IPOffset += 1; } else if(width == 16) { - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine -> internal_state.IPOffset += 2; } else if(width == 32) { - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine -> internal_state.IPOffset += 4; } status = perform_test(machine, &immediate, dest, width); @@ -1333,7 +961,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //XCHG r8, rm8 or XCHG r16, rm16 or XCHG r32, rm32 else if(opcode >= 0x86 && opcode <= 0x87) { - int8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if(opcode == 0x86) { @@ -1375,7 +1003,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //ROLS and RORS Group (Group 2) else if(opcode >= 0xd0 && opcode <= 0xd3) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t arg = opcode <=0xd1 ? 1 : machine->regs.h.cl; uint8_t width = 8; @@ -1416,9 +1044,9 @@ int16_t parse_and_execute_instruction(v8086* machine) //SHORT JUMPS on conditions else if((opcode >= 0x70 && opcode <= 0x7f) || (opcode == 0xe3)) { - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - uint32_t tempIP = machine->IP; + uint32_t tempIP = machine->IP.w.ip; uint8_t jump = 0; if(opcode != 0xe3) switch(opcode & 0x0fu) @@ -1483,30 +1111,30 @@ int16_t parse_and_execute_instruction(v8086* machine) } if(jump) tempIP += offset; if(tempIP > 0xFFFF) return -1; - machine->IP = tempIP; + machine->IP.w.ip = tempIP; } //Short relative JMP else if(opcode == 0xeb) { - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - machine->IP += offset; + machine->IP.w.ip += offset; } //Near realtive JMP else if(opcode == 0xe9) { - int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - machine->IP += offset; + machine->IP.w.ip += offset; } //Far JMP else if(opcode == 0xea) { - int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->sregs.cs = newCS; - machine->IP = newIP; + machine->IP.w.ip = newIP; machine->internal_state.IPOffset = 0; } //LOOP Group @@ -1514,7 +1142,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode >= 0xe0 && opcode <= 0xe2) { uint8_t jump = 0; - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if(machine->internal_state.operand_32_bit) machine->regs.d.ecx--; @@ -1548,14 +1176,14 @@ int16_t parse_and_execute_instruction(v8086* machine) } if(jump) - machine->IP += offset; + machine->IP.w.ip += offset; } //MOV Group //MOV r8, imm8 else if(opcode >= 0xb0 && opcode <= 0xb7) { uint8_t* reg = get_byte_register(machine, opcode & 0x7u); - uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); if(reg == NULL) return UNDEFINED_REGISTER; machine->internal_state.IPOffset += 1; *reg = imm; @@ -1567,7 +1195,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint32_t* reg = get_dword_register(machine, (opcode - 0xb8u) & 0x7u); if(reg == NULL) return UNDEFINED_REGISTER; - uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; *reg = imm; } @@ -1575,7 +1203,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { uint16_t* reg = get_word_register(machine, (opcode - 0xb8u) & 0x7u); if(reg == NULL) return UNDEFINED_REGISTER; - uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; *reg = imm; } @@ -1583,7 +1211,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //MOV AL/AX/EAX, moffs8/moffs16/moffs32 or MOV moffs8/moffs16/moffs32, AL/AX/EAX else if(opcode >= 0xa0 && opcode <= 0xa3) { - uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; uint16_t* segment = machine->internal_state.segment_reg_select == DEFAULT ? select_segment_register(machine, DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; @@ -1611,7 +1239,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode >= 0x88 && opcode <= 0x8b) { //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; void* source = NULL; void* dest = NULL; @@ -1655,7 +1283,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //MOV Segment to/from r/m else if(opcode == 0x8c || opcode == 0x8e) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint16_t* source = NULL; uint16_t* dest = NULL; @@ -1678,11 +1306,11 @@ int16_t parse_and_execute_instruction(v8086* machine) //MOV rm, imm else if(opcode >= 0xc6 && opcode <= 0xc7) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if(opcode == 0xc6) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); if(mem == NULL) return UNABLE_GET_MEMORY; @@ -1692,7 +1320,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit) { - uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); if(mem == NULL) return UNABLE_GET_MEMORY; @@ -1700,7 +1328,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } else { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); if(mem == NULL) return UNABLE_GET_MEMORY; @@ -1712,7 +1340,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0x84) { //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* reg = get_byte_register(machine, (mod_rm >> 3u) & 7u); uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); @@ -1723,7 +1351,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0x85) { //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; @@ -1736,7 +1364,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0xa8) { //Mod/RM - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* reg = get_byte_register(machine, AL); if(reg == NULL) return UNDEFINED_REGISTER; @@ -1758,12 +1386,12 @@ int16_t parse_and_execute_instruction(v8086* machine) uint32_t result; if(width == 16) { - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; } else if(width == 32) { - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; } else return BAD_WIDTH; @@ -2089,7 +1717,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //AAM else if(opcode == 0xd4) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t tempAL = machine->regs.h.al; machine->regs.h.ah = tempAL / immediate; @@ -2104,7 +1732,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //AAD else if(opcode == 0xd5) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t tempAL = machine->regs.h.al; uint8_t tempAH = machine->regs.h.ah; @@ -2122,7 +1750,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //LEA else if(opcode == 0x8d) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint16_t segment; @@ -2147,7 +1775,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //LDS or LES else if(opcode >= 0xc4 && opcode <= 0xc5) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint16_t* segment_register; @@ -2228,14 +1856,14 @@ int16_t parse_and_execute_instruction(v8086* machine) //IN AL, i8 else if(opcode == 0xe4) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; machine->regs.h.al = io_in_byte(immediate); } //IN AX/EAX, i8 else if(opcode == 0xe5) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if(machine->internal_state.operand_32_bit) machine->regs.d.eax = io_in_long(immediate); @@ -2256,14 +1884,14 @@ int16_t parse_and_execute_instruction(v8086* machine) //OUT i8, AL else if(opcode == 0xe6) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; io_out_byte(immediate, machine->regs.h.al); } //OUT i8, AX/EAX else if(opcode == 0xe7) { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if(machine->internal_state.operand_32_bit) io_out_long(immediate, machine->regs.d.eax); @@ -2285,55 +1913,55 @@ int16_t parse_and_execute_instruction(v8086* machine) //NEAR relative CALL else if(opcode == 0xe8) { - int16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - machine->IP += machine->internal_state.IPOffset; - push_word(machine, machine->IP); - machine->IP += immediate; + machine->IP.w.ip += machine->internal_state.IPOffset; + push_word(machine, machine->IP.w.ip); + machine->IP.w.ip += immediate; machine->internal_state.IPOffset = 0; } //FAR CALL else if(opcode == 0x9a) { - int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP + machine->internal_state.IPOffset); - machine->IP = newIP; + push_word(machine, machine->IP.w.ip + machine->internal_state.IPOffset); + machine->IP.w.ip = newIP; machine->sregs.cs = newCS; machine->internal_state.IPOffset = 0; } //Near RET else if(opcode == 0xc3) { - machine->IP = pop_word(machine); + machine->IP.w.ip = pop_word(machine); machine->internal_state.IPOffset = 0; } //Near RET, imm16 else if(opcode == 0xc2) { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - machine->IP = pop_word(machine); + machine->IP.w.ip = pop_word(machine); machine->regs.w.sp += immediate; machine->internal_state.IPOffset = 0; } //Far RET else if(opcode == 0xcb) { - machine->IP = pop_word(machine); + machine->IP.w.ip = pop_word(machine); machine->sregs.cs = pop_word(machine); machine->internal_state.IPOffset = 0; } //Far RET, imm16 else if(opcode == 0xca) { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - machine->IP = pop_word(machine); + machine->IP.w.ip = pop_word(machine); machine->sregs.cs = pop_word(machine); machine->regs.w.sp += immediate; machine->internal_state.IPOffset = 0; @@ -2345,7 +1973,7 @@ int16_t parse_and_execute_instruction(v8086* machine) uint8_t interrupt_number = 3; if(opcode == 0xcd) //INT, imm { - interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; } else if(opcode == 0xce) //INTO @@ -2359,9 +1987,9 @@ int16_t parse_and_execute_instruction(v8086* machine) push_word(machine, machine->regs.w.flags); push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP); + push_word(machine, machine->IP.w.ip); - machine->IP = newIP; + machine->IP.w.ip = newIP; machine->sregs.cs = newCS; machine->internal_state.IPOffset = 0; @@ -2369,7 +1997,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //IRET else if(opcode == 0xcf) { - machine->IP = pop_word(machine); + machine->IP.w.ip = pop_word(machine); machine->sregs.cs = pop_word(machine); machine->regs.w.flags = pop_word(machine); @@ -2391,7 +2019,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //GROUP 4 else if(opcode == 0xfe) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 8; @@ -2412,7 +2040,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //GROUP 5 else if(opcode == 0xff) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; @@ -2428,29 +2056,29 @@ int16_t parse_and_execute_instruction(v8086* machine) status = perform_dec(machine, dest, width); break; case 2: //Near absolute indirect call - machine->IP += machine->internal_state.IPOffset; - push_word(machine, machine->IP); + machine->IP.w.ip += machine->internal_state.IPOffset; + push_word(machine, machine->IP.w.ip); if(width == 16) - machine->IP += *((uint16_t*) dest); + machine->IP.w.ip += *((uint16_t*) dest); else return BAD_WIDTH; machine->internal_state.IPOffset = 0; break; case 3: // Far absolute indirect call - machine->IP += machine->internal_state.IPOffset; + machine->IP.w.ip += machine->internal_state.IPOffset; push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP); - machine->IP = *((uint16_t*) dest); + push_word(machine, machine->IP.w.ip); + machine->IP.w.ip = *((uint16_t*) dest); machine->sregs.cs = *(((uint16_t*)dest)+1); machine->internal_state.IPOffset = 0; break; case 4: //Near absolute indirect jmp if(width == 16) - machine->IP += *((uint16_t*) dest); + machine->IP.w.ip += *((uint16_t*) dest); else return BAD_WIDTH; machine->internal_state.IPOffset = 0; break; case 5: //Far absolute indirect jmp - machine->IP = *((uint16_t*) dest); + machine->IP.w.ip = *((uint16_t*) dest); machine->sregs.cs = *(((uint16_t*)dest)+1); machine->internal_state.IPOffset = 0; break; @@ -2467,7 +2095,7 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0x8f) { //ITS only POP rm16/32 - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; @@ -2479,7 +2107,7 @@ int16_t parse_and_execute_instruction(v8086* machine) *((uint32_t*)dest) = pop_dword(machine); } else return UNDEFINED_OPCODE; - recalculate_ip: machine->IP += machine->internal_state.IPOffset; + recalculate_ip: machine->IP.w.ip += machine->internal_state.IPOffset; return status; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index daf1b29c..b3a77bee 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -11,6 +11,14 @@ typedef enum _repeat_prefix { NONE, REPNE, REP_REPE } repeat_prefix; +enum instruction_set_compatibility{ + IS8086, IS386 +}; + +enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; +enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; +enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; + typedef enum _machine_status { OK = 0, UNDEFINED_OPCODE = -1, @@ -22,8 +30,10 @@ typedef enum _machine_status { BAD_MOD = -7, BAD_REG = -8, BAD_WIDTH = -9, - UNDEFINED_RECALCULATED_OPCODE = -10, - BAD_INT_NUMBER = -11, + BAD_INDEX = -10, + BAD_BASE = -11 + UNDEFINED_RECALCULATED_OPCODE = -12, + BAD_INT_NUMBER = -13, UNKNOWN_ERROR = -69 } machine_status; @@ -90,8 +100,24 @@ struct SREGS { uint16_t ss; }; +struct DWORDIP{ + uint32_t eip; +}; + +struct WORDIP { + uint16_t ip; + uint16_t _upper_ip; +}; + +union IP { + struct DWORDIP d; + struct WORDIP w; + struct WORDIP x; +}; + typedef struct _is{ uint32_t operand_32_bit; + uint32_t address_32_bit; segment_register_select segment_reg_select; repeat_prefix rep_prefix; uint16_t IPOffset; @@ -101,9 +127,11 @@ typedef struct _v8086 { union REGS regs; struct SREGS sregs; - uint16_t IP; + union IP IP; _internal_state internal_state; uint8_t Memory[0x100000]; + enum instruction_set_compatibility is_compatibility; + int16_t (*operations[256]) (struct _v8086*, uint8_t); } v8086; From 05dd0b88b8a29e517337af15c81a9f112e6662ed Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 25 May 2020 02:37:33 +0200 Subject: [PATCH 056/165] Temporarly finished worked with implementing 32-bit addressing. More refactor - making files cleaner, easier to maintain, fixing code (if needed). --- os/kernel/src/v8086/memory_operations.h | 2 + os/kernel/src/v8086/mod_rm_parsing.c | 116 ++- os/kernel/src/v8086/mod_rm_parsing.h | 2 +- .../v8086/operations/arithmetic_operations.c | 613 ++++++++++++ .../v8086/operations/arithmetic_operations.h | 28 + .../operations/ascii_adjustments_operations.c | 81 ++ .../operations/ascii_adjustments_operations.h | 8 + .../src/v8086/operations/internal_funcs.c | 1 + .../src/v8086/operations/internal_funcs.h | 11 + os/kernel/src/v8086/operations/opcodes.c | 121 +++ os/kernel/src/v8086/operations/opcodes.h | 34 + os/kernel/src/v8086/stack.h | 3 + os/kernel/src/v8086/v8086.c | 896 ++---------------- os/kernel/src/v8086/v8086.h | 17 +- 14 files changed, 1073 insertions(+), 860 deletions(-) create mode 100644 os/kernel/src/v8086/operations/arithmetic_operations.c create mode 100644 os/kernel/src/v8086/operations/arithmetic_operations.h create mode 100644 os/kernel/src/v8086/operations/ascii_adjustments_operations.c create mode 100644 os/kernel/src/v8086/operations/ascii_adjustments_operations.h create mode 100644 os/kernel/src/v8086/operations/internal_funcs.c create mode 100644 os/kernel/src/v8086/operations/internal_funcs.h create mode 100644 os/kernel/src/v8086/operations/opcodes.c create mode 100644 os/kernel/src/v8086/operations/opcodes.h diff --git a/os/kernel/src/v8086/memory_operations.h b/os/kernel/src/v8086/memory_operations.h index 04584001..b08cdabf 100644 --- a/os/kernel/src/v8086/memory_operations.h +++ b/os/kernel/src/v8086/memory_operations.h @@ -1,6 +1,8 @@ #ifndef V8086_MEMORY_OPERATIONS_H #define V8086_MEMORY_OPERATIONS_H +#include + static inline uint32_t get_absolute_address(uint32_t segment, uint32_t offset) { return segment * 0x10 + offset; diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index d3c30fa4..daecb4b8 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -116,7 +116,7 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select } } -int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset) +int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset) { uint16_t* segment_register = NULL; if(machine->internal_state.segment_reg_select != DEFAULT) @@ -249,12 +249,12 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 return UNKNOWN_ERROR; } -int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t* segment, uint32_t *offset) +int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, uint32_t *offset) { uint8_t sib = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t scale = sib >> 6u; - uint8_t index = (sib >> 3u) & 7u; + uint8_t index = (uint8_t)(sib >> 3u) & 7u; uint8_t base = sib & 7u; switch (index) { @@ -275,7 +275,6 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t* segment, uint3 break; case 5: *offset = machine->regs.d.ebp; - segment = select_segment_register(machine, SS); break; case 6: *offset = machine->regs.d.esi; @@ -313,29 +312,11 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t* segment, uint3 machine->internal_state.IPOffset += 4; *offset += disp; } - else if (mod == 1) + else { - uint8_t disp = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, - machine->IP.w.ip + - machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - *offset += disp; - *offset += machine->regs.d.ebp; - segment = select_segment_register(machine, SS); - } - else if(mod == 2) - { - uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, - machine->IP.w.ip + - machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 4; - *offset += disp; *offset += machine->regs.d.ebp; segment = select_segment_register(machine, SS); } - else{ - return BAD_BASE; - } break; case 6: *offset += machine->regs.d.esi; @@ -392,21 +373,106 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui return BAD_RM; } break; + case 1: + { + int8_t disp = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + switch (rm) { + case 0: + *offset = machine->regs.d.eax + disp; + break; + case 1: + *offset = machine->regs.d.ecx + disp; + break; + case 2: + *offset = machine->regs.d.edx + disp; + break; + case 3: + *offset = machine->regs.d.ebx + disp; + break; + case 4: // SIB + read_and_parse_sib(machine, mod, segment_register, offset); + *offset += disp; + break; + case 5:{ + *offset = machine->regs.d.ebp + disp; + segment_register = select_segment_register(machine, SS); + break; + } + case 6: + *offset = machine->regs.d.esi + disp; + break; + case 7: + *offset = machine->regs.d.edi + disp; + break; + default: + return BAD_RM; + } + break; + } + case 2: { + uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + switch (rm) { + case 0: + *offset = machine->regs.d.eax + disp; + break; + case 1: + *offset = machine->regs.d.ecx + disp; + break; + case 2: + *offset = machine->regs.d.edx + disp; + break; + case 3: + *offset = machine->regs.d.ebx + disp; + break; + case 4: // SIB + read_and_parse_sib(machine, mod, segment_register, offset); + *offset += disp; + break; + case 5:{ + *offset = machine->regs.d.ebp + disp; + segment_register = select_segment_register(machine, SS); + break; + } + case 6: + *offset = machine->regs.d.esi + disp; + break; + case 7: + *offset = machine->regs.d.edi + disp; + break; + default: + return BAD_RM; + } + break; + } + default: + return BAD_MOD; } + + if(machine->internal_state.segment_reg_select != DEFAULT) + segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); + else if(segment_register == NULL) + segment_register = select_segment_register(machine, DS); + + *segment = *segment_register; return 0; } void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) { uint16_t segment; - uint16_t offset; + uint32_t offset; switch(mod_rm >> 6u) //Parsing mod than parsing rm { case 0: case 1: case 2: - calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + if(machine->internal_state.address_32_bit) + calculate_segment_offset_from_mode_32(machine, mod_rm, &segment, &offset); + else + calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); case 3: switch(width){ diff --git a/os/kernel/src/v8086/mod_rm_parsing.h b/os/kernel/src/v8086/mod_rm_parsing.h index 0f3cf90b..f89b0cd9 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.h +++ b/os/kernel/src/v8086/mod_rm_parsing.h @@ -9,7 +9,7 @@ uint32_t* get_dword_register(v8086* machine, uint8_t reg_field); void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width); uint16_t* select_segment_register(v8086* machine, segment_register_select select); -int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint16_t* offset); +int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset); int16_t calculate_segment_offset_from_mode_32(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset); void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width); diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c new file mode 100644 index 00000000..8eb3244a --- /dev/null +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -0,0 +1,613 @@ +#include +#include +#include +#include +#include +#include +#include "arithmetic_operations.h" +#include "internal_funcs.h" + +int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return BAD_WIDTH; + result = dest_before + source_before + carry; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + else return BAD_WIDTH; + return OK; +} + +int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return BAD_WIDTH; + result = dest_before - (source_before + carry); + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + else return BAD_WIDTH; + return OK; +} + +int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + result = *((uint8_t*)dest) | *((uint8_t*)source); + else if(width == 16) + result = *((uint16_t*)dest) | *((uint16_t*)source); + else if(width == 32) + result = *((uint32_t*)dest) | *((uint32_t*)source); + else return BAD_WIDTH; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return OK; +} + +int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + result = *((uint8_t*)dest) & *((uint8_t*)source); + else if(width == 16) + result = *((uint16_t*)dest) & *((uint16_t*)source); + else if(width == 32) + result = *((uint32_t*)dest) & *((uint32_t*)source); + else return BAD_WIDTH; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return OK; +} + +int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint32_t result = 0; + if(width == 8) + result = *((uint8_t*)dest) ^ *((uint8_t*)source); + else if(width == 16) + result = *((uint16_t*)dest) ^ *((uint16_t*)source); + else if(width == 32) + result = *((uint32_t*)dest) ^ *((uint32_t*)source); + else return BAD_WIDTH; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return OK; +} + +int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) +{ + uint64_t result = 0; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return BAD_WIDTH; + result = dest_before - source_before; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + return OK; +} + +int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) +{ + uint16_t temp_flags = 0; + if(arg == 0) return OK; + if(width == 8) + __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); + else if(width == 16) + __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); + else if(width == 32) + __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + else return BAD_WIDTH; + if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; imul %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; imul %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + else return BAD_WIDTH; + } + else + { + if(width == 8) + { + __asm__ __volatile__( + "movb %%dl, %%al; mul %%cl; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; mul %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; mul %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + else return BAD_WIDTH; + } + bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + else return BAD_WIDTH; + } + else + { + if(width == 8) + { + __asm__ __volatile__( + "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + ); + } + else if(width == 16) + { + __asm__ __volatile__( + "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + ); + } + else if(width == 32) + { + __asm__ __volatile__( + "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + ); + } + else return BAD_WIDTH; + } + return OK; +} + +int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) +{ + uint32_t result; + + if(width == 8) + result = *((uint8_t*) source) & *((uint8_t*) dest); + else if(width == 16) + result = *((uint16_t*) source) & *((uint16_t*) dest); + else if(width == 32) + result = *((uint32_t*) source) & *((uint32_t*) dest); + else return BAD_WIDTH; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + return OK; +} + +int16_t perform_inc(v8086* machine, void* dest, uint8_t width) +{ + uint64_t result = 0; + uint32_t dest_before; + + if (width == 8) dest_before = *((uint8_t*) dest); + else if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return BAD_WIDTH; + + result = dest_before + 1; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return OK; +} + +int16_t perform_dec(v8086* machine, void* dest, uint8_t width) +{ + uint64_t result = 0; + uint32_t dest_before; + + if (width == 8) dest_before = *((uint8_t*) dest); + else if(width == 16) dest_before = *((uint16_t*)dest); + else if(width == 32) dest_before = *((uint32_t*)dest); + else return BAD_WIDTH; + + result = dest_before - 1; + + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if(width == 8) *((uint8_t*)dest) = result & 0xFFu; + else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; + else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + return OK; +} + +int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) +{ + //Maybe Mod/RM, Can be Immediate + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t reg = get_reg(mod_rm_or_immediate); + uint8_t width = 16; + void* source = NULL; + void* dest = NULL; + if(!(recalculated_opcode % 2)) width = 8; //Odd Opcode means 16 or 32 bit operands + else if(machine->internal_state.operand_32_bit) width = 32; + switch(recalculated_opcode) + { + case 0: //OPERATION r/m8, r8 + source = get_byte_register(machine, reg); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + break; + case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 + source = get_variable_length_register(machine, reg, width); + dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + break; + case 2: //OPERATION r8, r/m8 + dest = get_byte_register(machine, reg); + source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; + break; + case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 + dest = get_variable_length_register(machine, reg, width); + source = get_memory_from_mode(machine, mod_rm_or_immediate, width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(source == NULL) return UNABLE_GET_MEMORY; + break; + case 4: //OPERATION AL, imm8 + dest = get_byte_register(machine, AL); + source = &(mod_rm_or_immediate); + if(dest == NULL) return UNDEFINED_REGISTER; + break; + case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 + dest = get_variable_length_register(machine, AX, width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(width == 32) + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); + else + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += ((width / 8) - 1); + break; + default: + return UNDEFINED_RECALCULATED_OPCODE; + } + int16_t status = operation(machine, dest, source, width, carry); + if(status) return status; + return OK; +} +int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) +{ + void* dest = NULL; + uint8_t width; + uint32_t immediate; + int32_t signed_immediate; + switch(recalculated_opcode) + { + case 0: //OPERATION rm8, imm8 + case 2: //OPERATION rm8, imm8 + width = 8; + dest = get_memory_from_mode(machine, mod_rm, width); + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + break; + case 1: //OPERATION rm16, imm16 or rm32, imm32 + if(machine->internal_state.operand_32_bit) { + width = 32; + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + } + else + { + width = 16; + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } + dest = get_memory_from_mode(machine, mod_rm, width); + break; + case 3: //OPERATION rm16, imm8, or rm32, imm8 + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + dest = get_memory_from_mode(machine, mod_rm, width); + break; + default: + return UNDEFINED_RECALCULATED_OPCODE; + } + if(dest == NULL) return UNABLE_GET_MEMORY; + int16_t status; + if(recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); + else status = operation(machine, dest, &immediate, width, carry); + if(status) return status; + return OK; +} + +int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec) +{ + uint8_t width = 16; + void* dest = NULL; + if(machine->internal_state.operand_32_bit) width=32; + dest = get_variable_length_register(machine, opcode & 7u, width); + if(dest == NULL) return UNDEFINED_REGISTER; + + if(!dec) + return perform_inc(machine, dest, width); + return perform_dec(machine, dest, width); +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.h b/os/kernel/src/v8086/operations/arithmetic_operations.h new file mode 100644 index 00000000..699b4711 --- /dev/null +++ b/os/kernel/src/v8086/operations/arithmetic_operations.h @@ -0,0 +1,28 @@ +#ifndef V8086_ARITHMETIC_OPERATIONS_H +#define V8086_ARITHMETIC_OPERATIONS_H + +int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); +int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_rol(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_rcl(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_rcr(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_shl(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_shr(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width); +int16_t perform_neg(v8086* machine, void* source, uint8_t width); +int16_t perform_multiplication(v8086* machine, void* source, uint8_t signed_mul, uint8_t width); +int16_t perform_division(v8086* machine, void* source, uint8_t signed_div, uint8_t width); +int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width); +int16_t perform_inc(v8086* machine, void* dest, uint8_t width); +int16_t perform_dec(v8086* machine, void* dest, uint8_t width); + +int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)); +int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)); +int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec); + +#endif //V8086_ARITHMETIC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c new file mode 100644 index 00000000..0b41dfb5 --- /dev/null +++ b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include "ascii_adjustments_operations.h" + +int16_t adjust_after_add_sub(v8086* machine, bool sub) +{ + if(((machine->regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.x.ax += 0x106; + else + { + machine->regs.h.al -= 0x6; + machine->regs.h.ah -= 1; + } + bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al &= 0x0fu; + return OK; +} + +int16_t adjust_after_add_sub_packed(v8086* machine, bool sub) +{ + uint8_t old_AL = machine->regs.h.al; + uint16_t old_cf = bit_get(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al + (!sub ? 6 : -6); + machine->regs.h.al = temp_ax & 0xFFu; + bit_write(machine->regs.w.flags, 1u < 0xFF)) ? 1 : 0); + bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u < 0x99) || old_cf) + { + machine->regs.h.al += sub ? 0x60 : -0x60; + bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (uint8_t)(machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG + return OK; +} + +int16_t adjust_after_mul_div(v8086* machine, bool div) +{ + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t tempAL = machine->regs.h.al; + uint8_t tempAH = machine->regs.h.ah; + + if(!div) { + machine->regs.h.ah = tempAL / immediate; + machine->regs.h.al = tempAL % immediate; + } + else { + machine->regs.h.al = (uint8_t)(tempAL + (tempAH * immediate)) & 0xFFu; + machine->regs.h.ah = 0; + } + + uint8_t parrity = machine->regs.h.al & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (uint8_t)(machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG + + return OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/ascii_adjustments_operations.h b/os/kernel/src/v8086/operations/ascii_adjustments_operations.h new file mode 100644 index 00000000..92656b83 --- /dev/null +++ b/os/kernel/src/v8086/operations/ascii_adjustments_operations.h @@ -0,0 +1,8 @@ +#ifndef MICROS_ASCII_ADJUSTMENTS_OPERATIONS_H +#define MICROS_ASCII_ADJUSTMENTS_OPERATIONS_H + +int16_t adjust_after_add_sub(v8086* machine, bool sub); +int16_t adjust_after_add_sub_packed(v8086* machine, bool sub); +int16_t adjust_after_mul_div(v8086* machine, bool div); + +#endif //MICROS_ASCII_ADJUSTMENTS_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/internal_funcs.c b/os/kernel/src/v8086/operations/internal_funcs.c new file mode 100644 index 00000000..ce348a91 --- /dev/null +++ b/os/kernel/src/v8086/operations/internal_funcs.c @@ -0,0 +1 @@ +#include "internal_funcs.h" diff --git a/os/kernel/src/v8086/operations/internal_funcs.h b/os/kernel/src/v8086/operations/internal_funcs.h new file mode 100644 index 00000000..03916f72 --- /dev/null +++ b/os/kernel/src/v8086/operations/internal_funcs.h @@ -0,0 +1,11 @@ +#ifndef V8086_INTERNAL_FUNCS_H +#define V8086_INTERNAL_FUNCS_H + +#include + +static inline uint8_t get_reg(uint8_t mod_rm) +{ + return (uint8_t)(mod_rm >> 3u) & 7u; +} + +#endif //V8086_INTERNAL_FUNCS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c new file mode 100644 index 00000000..33840298 --- /dev/null +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include "opcodes.h" +#include "arithmetic_operations.h" +#include "ascii_adjustments_operations.h" + +#define NO_CARRY 0 +#define CARRY_FLAG_AS_NUMBER bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT + +OPCODE_PROTO(add) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode, NO_CARRY, perform_adding); +} + +OPCODE_PROTO(push_es) +{ + push_word(machine, machine->sregs.es); + return OK; +} + +OPCODE_PROTO(pop_es) +{ + machine->sregs.es = pop_word(machine); + return OK; +} + +OPCODE_PROTO(or) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, NO_CARRY, perform_or); +} + +OPCODE_PROTO(push_cs) +{ + push_word(machine, machine->sregs.cs); + return OK; +} + +OPCODE_PROTO(adc) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, CARRY_FLAG_AS_NUMBER, perform_adding); +} + +OPCODE_PROTO(push_ss) +{ + push_word(machine, machine->sregs.ss); + return OK; +} + +OPCODE_PROTO(pop_ss) +{ + machine->sregs.ss = pop_word(machine); + return OK; +} + +OPCODE_PROTO(sbb) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, CARRY_FLAG_AS_NUMBER, perform_subtracting); +} + +OPCODE_PROTO(push_ds) +{ + push_word(machine, machine->sregs.ds); + return OK; +} + +OPCODE_PROTO(pop_ds) +{ + machine->sregs.ds = pop_word(machine); + return OK; +} + +OPCODE_PROTO(and) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); +} + +OPCODE_PROTO(daa) +{ + return adjust_after_add_sub_packed(machine, false); +} + +OPCODE_PROTO(sub) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, NO_CARRY, perform_subtracting); +} + +OPCODE_PROTO(das) +{ + return adjust_after_add_sub_packed(machine, true); +} + +OPCODE_PROTO(xor) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, NO_CARRY, perform_xor); +} + +OPCODE_PROTO(aaa) +{ + return adjust_after_add_sub(machine, false); +} + +OPCODE_PROTO(cmp) +{ + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, NO_CARRY, perform_cmp); +} + +OPCODE_PROTO(aas) +{ + return adjust_after_add_sub(machine, true); +} + +OPCODE_PROTO(inc) +{ + return perform_inc_dec(machine, opcode, false); +} + +OPCODE_PROTO(dec) +{ + return perform_inc_dec(machine, opcode, true); +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h new file mode 100644 index 00000000..a15fde04 --- /dev/null +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -0,0 +1,34 @@ +#ifndef MICROS_OPCODES_H +#define MICROS_OPCODES_H + +#include "../v8086.h" + +#define OPCODE_PROTO_NAME(name) v8086_opcode_##name +#define OPCODE_PROTO(name) int16_t OPCODE_PROTO_NAME(name)(v8086* machine, uint8_t opcode) +#define ASSIGN_NULL(i) machine->operations[i] = NULL; +#define ASSIGN_OPCODE(i, name) machine->operations[i] = OPCODE_PROTO_NAME(name) +#define GROUP_OF_OPCODES(from, to, name) for(uint8_t i = from; i <= to; i++) ASSIGN_OPCODE(i, name) + +OPCODE_PROTO(add); +OPCODE_PROTO(push_es); +OPCODE_PROTO(pop_es); +OPCODE_PROTO(or); +OPCODE_PROTO(push_cs); +OPCODE_PROTO(adc); +OPCODE_PROTO(push_ss); +OPCODE_PROTO(pop_ss); +OPCODE_PROTO(sbb); +OPCODE_PROTO(push_ds); +OPCODE_PROTO(pop_ds); +OPCODE_PROTO(and); +OPCODE_PROTO(daa); +OPCODE_PROTO(sub); +OPCODE_PROTO(das); +OPCODE_PROTO(xor); +OPCODE_PROTO(aaa); +OPCODE_PROTO(cmp); +OPCODE_PROTO(aas); +OPCODE_PROTO(inc); +OPCODE_PROTO(dec); + +#endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/stack.h b/os/kernel/src/v8086/stack.h index 245f7182..16e1325b 100644 --- a/os/kernel/src/v8086/stack.h +++ b/os/kernel/src/v8086/stack.h @@ -1,6 +1,9 @@ #ifndef V8086_STACK_H #define V8086_STACK_H +#include "v8086.h" +#include "memory_operations.h" + static inline void push_word(v8086* machine, uint16_t value) { write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 34c9c9e1..e2676e69 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -5,23 +5,47 @@ #include "./memory_operations.h" #include "./stack.h" #include "./mod_rm_parsing.h" +#include "./operations/internal_funcs.h" +#include "./operations/arithmetic_operations.h" +#include "./operations/opcodes.h" -#define bit_get(p,m) ((p) & (m)) -#define bit_set(p,m) ((p) |= (m)) -#define bit_clear(p,m) ((p) &= ~(m)) -#define bit_flip(p,m) ((p) ^= (m)) -#define bit_write(p,m,v) (v ? bit_set(p,m) : bit_clear(p,m)) +int16_t parse_and_execute_instruction(v8086* machine); -#define CARRY_FLAG_BIT 0u -#define PARITY_FLAG_BIT 2u -#define AUX_CARRY_FLAG_BIT 4u -#define ZERO_FLAG_BIT 6u -#define SIGN_FLAG_BIT 7u -#define INTERRUPT_FLAG_BIT 9u -#define DIRECTION_FLAG_BIT 10u -#define OVERFLOW_FLAG_BIT 11u +void v8086_set_8086_instruction_set(v8086* machine) +{ + GROUP_OF_OPCODES(0x00u, 0x05u, add); + ASSIGN_OPCODE(0x06, push_es); + ASSIGN_OPCODE(0x07, pop_es); + GROUP_OF_OPCODES(0x08u, 0x0du, or); + ASSIGN_OPCODE(0x0eu, push_cs); + //THERE IS NO 2-BYTES OPCODES + ASSIGN_NULL(0x0fu); + GROUP_OF_OPCODES(0x10u, 0x15u, adc); + ASSIGN_OPCODE(0x16u, push_ss); + ASSIGN_OPCODE(0x17u, pop_ss); + GROUP_OF_OPCODES(0x18u, 0x1du, sbb); + ASSIGN_OPCODE(0x1eu, push_ds); + ASSIGN_OPCODE(0x1fu, pop_ds); + GROUP_OF_OPCODES(0x20u, 0x25u, and); + //RESERVED TO SEG=ES PREFIX + ASSIGN_NULL(0x26u); + ASSIGN_OPCODE(0x27u, daa); + GROUP_OF_OPCODES(0x28u, 0x2du, sub); + //RESERVED TO SEG=CS PREFIX + ASSIGN_NULL(0x2eu); + ASSIGN_OPCODE(0x2fu, das); + GROUP_OF_OPCODES(0x30u, 0x35u, xor); + //RESERVED TO SEG=SS PREFIX + ASSIGN_NULL(0x36u); + ASSIGN_OPCODE(0x37u, aaa); + GROUP_OF_OPCODES(0x38u, 0x3du, cmp); + //RESERVED TO SEG=DS PREFIX + ASSIGN_NULL(0x3eu); + ASSIGN_OPCODE(0x3fu, aas); + GROUP_OF_OPCODES(0x40u, 0x47u, inc); + GROUP_OF_OPCODES(0x48u, 0x4f, dec); -int16_t parse_and_execute_instruction(v8086* machine); +} v8086* v8086_create_machine() { @@ -32,7 +56,7 @@ v8086* v8086_create_machine() machine->sregs.cs = 0xf000; machine->IP.w.ip = 0xfff0; memcpy(machine->Memory, (void*)0xc0000000, 0x100000); - + v8086_set_8086_instruction_set(machine); return machine; } @@ -59,598 +83,6 @@ int16_t v8086_call_int(v8086* machine, int16_t num) return num; } -int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); - } else return BAD_WIDTH; - result = dest_before + source_before + carry; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - else return BAD_WIDTH; - return OK; -} - -int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); - } else return BAD_WIDTH; - result = dest_before - (source_before + carry); - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - else return BAD_WIDTH; - return OK; -} - -int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) | *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) | *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) | *((uint32_t*)source); - else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return OK; -} - -int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) & *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) & *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) & *((uint32_t*)source); - else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return OK; -} - -int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) ^ *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) ^ *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) ^ *((uint32_t*)source); - else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return OK; -} - -int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); - } else return BAD_WIDTH; - result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - return OK; -} - -int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) -{ - //Maybe Mod/RM, Can be Immediate - uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - uint8_t width = 16; - void* source = NULL; - void* dest = NULL; - if(!(recalculated_opcode % 2)) width = 8; //Odd Opcode means 16 or 32 bit operands - else if(machine->internal_state.operand_32_bit) width = 32; - switch(recalculated_opcode) - { - case 0: //OPERATION r/m8, r8 - source = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - break; - case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 - source = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); - dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - break; - case 2: //OPERATION r8, r/m8 - dest = get_byte_register(machine, (mod_rm_or_immediate >> 3u) & 7u); - source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; - break; - case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 - dest = get_variable_length_register(machine, (mod_rm_or_immediate >> 3u) & 7u, width); - source = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; - break; - case 4: //OPERATION AL, imm8 - dest = get_byte_register(machine, AL); - source = &(mod_rm_or_immediate); - if(dest == NULL) return UNDEFINED_REGISTER; - break; - case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 - dest = get_variable_length_register(machine, AX, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(width == 32) - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); - else - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += ((width / 8) - 1); - break; - default: - return UNDEFINED_RECALCULATED_OPCODE; - } - int16_t status = operation(machine, dest, source, width, carry); - if(status) return status; - return OK; -} -int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) -{ - void* dest = NULL; - uint8_t width; - uint32_t immediate; - int32_t signed_immediate; - switch(recalculated_opcode) - { - case 0: //OPERATION rm8, imm8 - case 2: //OPERATION rm8, imm8 - width = 8; - dest = get_memory_from_mode(machine, mod_rm, width); - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - break; - case 1: //OPERATION rm16, imm16 or rm32, imm32 - if(machine->internal_state.operand_32_bit) { - width = 32; - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 4; - } - else - { - width = 16; - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - } - dest = get_memory_from_mode(machine, mod_rm, width); - break; - case 3: //OPERATION rm16, imm8, or rm32, imm8 - if(machine->internal_state.operand_32_bit) width = 32; - else width = 16; - signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - dest = get_memory_from_mode(machine, mod_rm, width); - break; - default: - return UNDEFINED_RECALCULATED_OPCODE; - } - if(dest == NULL) return UNABLE_GET_MEMORY; - int16_t status; - if(recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); - else status = operation(machine, dest, &immediate, width, carry); - if(status) return status; - return OK; -} - -int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ - uint16_t temp_flags = 0; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); - else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) - ); - } - else if(width == 16) - { - __asm__ __volatile__( - "movw %%dx, %%ax; imul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) - ); - } - else if(width == 32) - { - __asm__ __volatile__( - "movl %%edx, %%eax; imul %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) - ); - } - else return BAD_WIDTH; - } - else - { - if(width == 8) - { - __asm__ __volatile__( - "movb %%dl, %%al; mul %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) - ); - } - else if(width == 16) - { - __asm__ __volatile__( - "movw %%dx, %%ax; mul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) - ); - } - else if(width == 32) - { - __asm__ __volatile__( - "movl %%edx, %%eax; mul %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) - ); - } - else return BAD_WIDTH; - } - bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) - ); - } - else if(width == 16) - { - __asm__ __volatile__( - "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) - ); - } - else if(width == 32) - { - __asm__ __volatile__( - "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) - ); - } - else return BAD_WIDTH; - } - else - { - if(width == 8) - { - __asm__ __volatile__( - "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) - ); - } - else if(width == 16) - { - __asm__ __volatile__( - "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) - ); - } - else if(width == 32) - { - __asm__ __volatile__( - "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) - ); - } - else return BAD_WIDTH; - } - return OK; -} - -int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) -{ - uint32_t result; - - if(width == 8) - result = *((uint8_t*) source) & *((uint8_t*) dest); - else if(width == 16) - result = *((uint16_t*) source) & *((uint16_t*) dest); - else if(width == 32) - result = *((uint32_t*) source) & *((uint32_t*) dest); - else return BAD_WIDTH; - - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - return OK; -} - -int16_t perform_inc(v8086* machine, void* dest, uint8_t width) -{ - uint64_t result = 0; - uint32_t dest_before; - - if (width == 8) dest_before = *((uint8_t*) dest); - else if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); - else return BAD_WIDTH; - - result = dest_before + 1; - - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return OK; -} - -int16_t perform_dec(v8086* machine, void* dest, uint8_t width) -{ - uint64_t result = 0; - uint32_t dest_before; - - if (width == 8) dest_before = *((uint8_t*) dest); - else if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); - else return BAD_WIDTH; - - result = dest_before - 1; - - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; - return OK; -} - int16_t parse_and_execute_instruction(v8086* machine) { machine->internal_state.IPOffset = 0; @@ -709,75 +141,13 @@ int16_t parse_and_execute_instruction(v8086* machine) { goto decode; //ommit prefix, contniue parsinf opcode; } - //Aritmetic operations - //ADD - else if(opcode <= 5) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode, 0, perform_adding); - } - //ADC - else if(opcode >= 0x10 && opcode <= 0x15) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x10, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_adding); - } - //SBB - else if(opcode >= 0x18 && opcode <= 0x1d) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x18, bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT, perform_subtracting); - } - //SUB - else if(opcode >= 0x28 && opcode <= 0x2d) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x28, 0, perform_subtracting); - } - //INC general registers 16 or 32-bit - else if(opcode >= 0x40 && opcode <= 0x47) - { - uint8_t width = 16; - void* dest = NULL; - if(machine->internal_state.operand_32_bit) width=32; - dest = get_variable_length_register(machine, opcode & 7u, width); - if(dest == NULL) return UNDEFINED_REGISTER; - status = perform_inc(machine, dest, width); - } - //DEC general registers 16 or 32-bit - else if(opcode >= 0x48 && opcode <= 0x4f) - { - uint8_t width = 16; - void* dest = NULL; - if(machine->internal_state.operand_32_bit) width=32; - dest = get_variable_length_register(machine, opcode & 7u, width); - if(dest == NULL) return UNDEFINED_REGISTER; - status = perform_dec(machine, dest, width); - } - //LOGICAL operations - //OR - else if(opcode >= 0x08 && opcode <= 0x0d) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x08, 0, perform_or); - } - //AND - else if(opcode >= 0x20 && opcode <= 0x25) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x20, 0, perform_and); - } - //XOR - else if(opcode >= 0x30 && opcode <= 0x35) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_xor); - } - //CMP - else if(opcode >= 0x38 && opcode <= 0x3d) - { - status = perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, 0, perform_cmp); - } //GROUP 1 else if(opcode >= 0x80 && opcode <= 0x83) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t recalculated_opcode = opcode - 0x80; - switch((mod_rm >> 3u) & 7u) + switch(get_reg(mod_rm)) { case 0: //ADD status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, @@ -827,7 +197,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(dest == NULL) return UNABLE_GET_MEMORY; - switch((mod_rm >> 3u) & 7u) + switch(get_reg(mod_rm)) { case 0: //TEST { @@ -890,18 +260,6 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width==32) push_dword(machine, *((uint32_t*)reg)); else return BAD_WIDTH; } - //PUSH CS - else if(opcode == 0x0e) - push_word(machine, machine->sregs.cs); - //PUSH DS - else if(opcode == 0x1e) - push_word(machine, machine->sregs.ds); - //PUSH ES - else if(opcode == 0x06) - push_word(machine, machine->sregs.es); - //PUSH SS - else if(opcode == 0x16) - push_word(machine, machine->sregs.ss); //PUSH FLAGS else if(opcode == 0x9c) push_word(machine, machine->regs.w.flags); @@ -918,15 +276,6 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(width==32) *((uint32_t*)reg) = pop_dword(machine); else return BAD_WIDTH; } - //POP DS - else if(opcode == 0x1f) - machine->sregs.ds = pop_word(machine); - //POP ES - else if(opcode == 0x07) - machine->sregs.es = pop_word(machine); - //POP SS - else if(opcode == 0x17) - machine->sregs.ss = pop_word(machine); //POP FLAGS else if(opcode == 0x9d) machine->regs.w.flags = pop_word(machine); @@ -965,7 +314,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; if(opcode == 0x86) { - uint8_t* source = get_byte_register(machine, (mod_rm >> 3u) & 7u); + uint8_t* source = get_byte_register(machine, get_reg(mod_rm)); uint8_t* dest = get_memory_from_mode(machine, mod_rm, 8); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; @@ -978,7 +327,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit) { - uint32_t* source = get_dword_register(machine, (mod_rm >> 3u) & 7u); + uint32_t* source = get_dword_register(machine, get_reg(mod_rm)); uint32_t* dest = get_memory_from_mode(machine, mod_rm, 32); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; @@ -989,7 +338,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } else { - uint16_t* source = get_word_register(machine, (mod_rm >> 3u) & 7u); + uint16_t* source = get_word_register(machine, get_reg(mod_rm)); uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; @@ -1013,7 +362,7 @@ int16_t parse_and_execute_instruction(v8086* machine) } void* dest = get_memory_from_mode(machine, mod_rm, width); if(dest == NULL) return UNABLE_GET_MEMORY; - switch((mod_rm >> 3u) & 7u) + switch(get_reg(mod_rm)) { case 0: status = perform_rol(machine, dest, arg, width); @@ -1247,14 +596,14 @@ int16_t parse_and_execute_instruction(v8086* machine) switch (opcode) { case 0x88: - source = get_byte_register(machine, (mod_rm >> 3u) & 7u); + source = get_byte_register(machine, get_reg(mod_rm)); dest = get_memory_from_mode(machine, mod_rm, 8); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x89: - source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); + source = get_variable_length_register(machine, get_reg(mod_rm), width); dest = get_memory_from_mode(machine, mod_rm, width); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; @@ -1262,14 +611,14 @@ int16_t parse_and_execute_instruction(v8086* machine) else *((uint32_t*)dest) = *((uint32_t*) source); break; case 0x8a: - dest = get_byte_register(machine, (mod_rm >> 3u) & 7u); + dest = get_byte_register(machine, get_reg(mod_rm)); source = get_memory_from_mode(machine, mod_rm, 8); if(dest == NULL) return UNDEFINED_REGISTER; if(source == NULL) return UNABLE_GET_MEMORY; *((uint8_t*)dest) = *((uint8_t*) source); break; case 0x8b: - dest = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); + dest = get_variable_length_register(machine, get_reg(mod_rm), width); source = get_memory_from_mode(machine, mod_rm, width); if(dest == NULL) return UNDEFINED_REGISTER; if(source == NULL) return UNABLE_GET_MEMORY; @@ -1289,14 +638,14 @@ int16_t parse_and_execute_instruction(v8086* machine) uint16_t* dest = NULL; if(opcode == 0x8c) { - source = select_segment_register(machine, (mod_rm >> 3u) & 7u); + source = select_segment_register(machine, get_reg(mod_rm)); dest = get_memory_from_mode(machine, mod_rm, 16); if(source == NULL) return UNDEFINED_SEGMENT_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; } else { - dest = select_segment_register(machine, (mod_rm >> 3u) & 7); + dest = select_segment_register(machine, get_reg(mod_rm)); source = get_memory_from_mode(machine, mod_rm, 16); if(dest == NULL) return UNDEFINED_SEGMENT_REGISTER; if(source == NULL) return UNABLE_GET_MEMORY; @@ -1342,7 +691,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //Mod/RM uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - uint8_t* reg = get_byte_register(machine, (mod_rm >> 3u) & 7u); + uint8_t* reg = get_byte_register(machine, get_reg(mod_rm)); uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); if(reg == NULL) return UNDEFINED_REGISTER; if(memory == NULL) return UNABLE_GET_MEMORY; @@ -1355,7 +704,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; - void* source = get_variable_length_register(machine, (mod_rm >> 3u) & 7u, width); + void* source = get_variable_length_register(machine, get_reg(mod_rm), width); void* dest = get_memory_from_mode(machine, mod_rm, width); if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; @@ -1372,7 +721,7 @@ int16_t parse_and_execute_instruction(v8086* machine) bit_clear(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (uint8_t)(result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> 7u); //SIGN FLAG @@ -1627,125 +976,6 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); } - //ASCII ADJUSTMENT group - //AAA - else if(opcode == 0x37) - { - if(((machine->regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.x.ax += 0x106; - bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al &= 0x0fu; - } - //AAS - else if(opcode == 0x3F) - { - if(((machine->regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al -= 0x6; - machine->regs.h.ah -= 1; - bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al &= 0x0fu; - } - //DAA - else if(opcode == 0x27) - { - uint8_t old_AL = machine->regs.h.al; - uint16_t old_cf = bit_get(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 0x0fu) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al + 6; - machine->regs.h.al = temp_ax & 0xFFu; - bit_write(machine->regs.w.flags, 1u < 0xFF)) ? 1 : 0); - bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u < 0x99) || old_cf) - { - machine->regs.h.al += 0x60; - bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - } - //DAS - else if(opcode == 0x2f) - { - uint8_t old_AL = machine->regs.h.al; - uint16_t old_cf = bit_get(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al & 0x0f) > 9u) || bit_get(machine->regs.w.flags, 1u <regs.h.al - 6; - machine->regs.h.al = temp_ax & 0xFFu; - bit_write(machine->regs.w.flags, 1u < 0xFF)) ? 1 : 0); - bit_set(machine->regs.w.flags, 1u <regs.w.flags, 1u < 0x99) || old_cf) - { - machine->regs.h.al -= 0x60; - bit_set(machine->regs.w.flags, 1u <regs.h.al & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - } - //AAM - else if(opcode == 0xd4) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t tempAL = machine->regs.h.al; - machine->regs.h.ah = tempAL / immediate; - machine->regs.h.al = tempAL % immediate; - - uint8_t parrity = machine->regs.h.al & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - } - //AAD - else if(opcode == 0xd5) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t tempAL = machine->regs.h.al; - uint8_t tempAH = machine->regs.h.ah; - - machine->regs.h.al = (tempAL + (tempAH * immediate)) & 0xFFu; - machine->regs.h.ah = 0; - - uint8_t parrity = machine->regs.h.al & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - } //LOAD Operations group //LEA else if(opcode == 0x8d) @@ -1754,7 +984,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; uint16_t segment; - uint16_t offset; + uint32_t offset; if((mod_rm >> 6u) > 3) return -1; @@ -1763,12 +993,12 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) { - uint32_t* reg = get_dword_register(machine, (mod_rm>>3u)&7u); + uint32_t* reg = get_dword_register(machine, get_reg(mod_rm)); *reg = offset; } else { - uint16_t* reg = get_word_register(machine, (mod_rm>>3u)&7u); + uint16_t* reg = get_word_register(machine, get_reg(mod_rm)); *reg = offset; } } @@ -1787,13 +1017,13 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->internal_state.operand_32_bit) { - uint32_t* dest = get_dword_register(machine, (mod_rm >> 3u) & 7u); + uint32_t* dest = get_dword_register(machine, get_reg(mod_rm)); *dest = *((uint32_t*) source); *segment_register = *(source+2); } else { - uint16_t* dest = get_word_register(machine, (mod_rm >> 3u) & 7u); + uint16_t* dest = get_word_register(machine, get_reg(mod_rm)); *dest = *source; *segment_register = *(source+1); } @@ -1813,11 +1043,11 @@ int16_t parse_and_execute_instruction(v8086* machine) { if(machine->internal_state.operand_32_bit){ int64_t t = machine->regs.d.eax; - machine->regs.d.edx = (t >> 32u); + machine->regs.d.edx = ((uint64_t)t >> 32u); } else{ int32_t t = machine->regs.w.ax; - machine->regs.w.dx = (t >> 16u); + machine->regs.w.dx = ((uint32_t)t >> 16u); } } //Store and load flags group @@ -2025,7 +1255,7 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest = get_memory_from_mode(machine, mod_rm, width); if(dest == NULL) return UNABLE_GET_MEMORY; - switch((mod_rm >> 3u) & 7u) + switch(get_reg(mod_rm)) { case 0: //INC rm8 status = perform_inc(machine, dest, width); @@ -2047,7 +1277,7 @@ int16_t parse_and_execute_instruction(v8086* machine) void* dest = get_memory_from_mode(machine, mod_rm, width); if(dest == NULL) return UNABLE_GET_MEMORY; - switch((mod_rm >> 3u) & 7u) + switch(get_reg(mod_rm)) { case 0: //INC rm8 status = perform_inc(machine, dest, width); diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index b3a77bee..1e4b7d40 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -3,6 +3,21 @@ #include +#define bit_get(p,m) ((p) & (m)) +#define bit_set(p,m) ((p) |= (m)) +#define bit_clear(p,m) ((p) &= ~(m)) +#define bit_flip(p,m) ((p) ^= (m)) +#define bit_write(p,m,v) (v ? bit_set(p,m) : bit_clear(p,m)) + +#define CARRY_FLAG_BIT 0u +#define PARITY_FLAG_BIT 2u +#define AUX_CARRY_FLAG_BIT 4u +#define ZERO_FLAG_BIT 6u +#define SIGN_FLAG_BIT 7u +#define INTERRUPT_FLAG_BIT 9u +#define DIRECTION_FLAG_BIT 10u +#define OVERFLOW_FLAG_BIT 11u + typedef enum _segment_register_select { ES, CS, SS, DS, FS, GS, DEFAULT } segment_register_select; @@ -31,7 +46,7 @@ typedef enum _machine_status { BAD_REG = -8, BAD_WIDTH = -9, BAD_INDEX = -10, - BAD_BASE = -11 + BAD_BASE = -11, UNDEFINED_RECALCULATED_OPCODE = -12, BAD_INT_NUMBER = -13, UNKNOWN_ERROR = -69 From 006554270f58cbcbc7e2d131b8c879347cf33a37 Mon Sep 17 00:00:00 2001 From: SzateX Date: Tue, 26 May 2020 02:42:02 +0200 Subject: [PATCH 057/165] Next part of refactor, bug fixes and adding 32-bit addressing to operations. Stopped on 0x8f opcode. --- .../v8086/operations/arithmetic_operations.c | 16 + .../v8086/operations/arithmetic_operations.h | 2 +- .../v8086/operations/exchange_operations.c | 57 +++ .../v8086/operations/exchange_operations.h | 9 + .../src/v8086/operations/jump_operations.c | 83 +++++ .../src/v8086/operations/jump_operations.h | 9 + .../src/v8086/operations/mov_operations.c | 97 +++++ .../src/v8086/operations/mov_operations.h | 10 + os/kernel/src/v8086/operations/opcodes.c | 82 +++++ os/kernel/src/v8086/operations/opcodes.h | 13 +- .../src/v8086/operations/stack_operations.c | 45 +++ .../src/v8086/operations/stack_operations.h | 10 + os/kernel/src/v8086/v8086.c | 345 +----------------- os/kernel/src/v8086/v8086.h | 1 + 14 files changed, 444 insertions(+), 335 deletions(-) create mode 100644 os/kernel/src/v8086/operations/exchange_operations.c create mode 100644 os/kernel/src/v8086/operations/exchange_operations.h create mode 100644 os/kernel/src/v8086/operations/jump_operations.c create mode 100644 os/kernel/src/v8086/operations/jump_operations.h create mode 100644 os/kernel/src/v8086/operations/mov_operations.c create mode 100644 os/kernel/src/v8086/operations/mov_operations.h create mode 100644 os/kernel/src/v8086/operations/stack_operations.c create mode 100644 os/kernel/src/v8086/operations/stack_operations.h diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 8eb3244a..3dd6519e 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -610,4 +610,20 @@ int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec) if(!dec) return perform_inc(machine, dest, width); return perform_dec(machine, dest, width); +} + +int16_t execute_test(v8086* machine, uint8_t opcode) +{ + //Mod/RM + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + if(opcode % 2) + width = machine->internal_state.operand_32_bit ? 32 : 16; + void* source = get_variable_length_register(machine, get_reg(mod_rm), width); + void* dest = get_memory_from_mode(machine, mod_rm, width); + + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + return perform_test(machine, source, dest, width); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.h b/os/kernel/src/v8086/operations/arithmetic_operations.h index 699b4711..7b46c21d 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.h +++ b/os/kernel/src/v8086/operations/arithmetic_operations.h @@ -24,5 +24,5 @@ int16_t perform_dec(v8086* machine, void* dest, uint8_t width); int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)); int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)); int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec); - +int16_t execute_test(v8086* machine, uint8_t opcode); #endif //V8086_ARITHMETIC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/exchange_operations.c b/os/kernel/src/v8086/operations/exchange_operations.c new file mode 100644 index 00000000..d865febb --- /dev/null +++ b/os/kernel/src/v8086/operations/exchange_operations.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "exchange_operations.h" +#include "internal_funcs.h" + +int16_t perform_exchange(void* source, void* dest, uint8_t width) +{ + uint32_t temp; + switch(width) + { + case 8: + temp = *((uint8_t*) source); + *((uint8_t*) source) = *((uint8_t*) dest); + *((uint8_t*) dest) = temp; + break; + case 16: + temp = *((uint16_t*) source); + *((uint16_t*) source) = *((uint16_t*) dest); + *((uint16_t*) dest) = temp; + break; + case 32: + temp = *((uint32_t*) source); + *((uint32_t*) source) = *((uint32_t*) dest); + *((uint32_t*) dest) = temp; + break; + default: + return BAD_WIDTH; + } + return OK; +} + +int16_t perform_exchange_rm(v8086* machine, uint8_t opcode) +{ + int8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + if(opcode % 2) + width = machine->internal_state.operand_32_bit ? 32 : 16; + + void* source = get_variable_length_register(machine, get_reg(mod_rm), width); + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + return perform_exchange(source, dest, width); +} + +int16_t perform_exchange_ax_register(v8086* machine, uint8_t opcode) +{ + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + void* regA = get_variable_length_register(machine, EAX, width); + void* regB = get_word_register(machine, opcode & 7u); + if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; + return perform_exchange(regA, regB, width); +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/exchange_operations.h b/os/kernel/src/v8086/operations/exchange_operations.h new file mode 100644 index 00000000..ffa417ef --- /dev/null +++ b/os/kernel/src/v8086/operations/exchange_operations.h @@ -0,0 +1,9 @@ +#ifndef MICROS_EXCHANGE_OPERATIONS_H +#define MICROS_EXCHANGE_OPERATIONS_H + +#include + +int16_t perform_exchange_rm(v8086* machine, uint8_t opcode); +int16_t perform_exchange_ax_register(v8086* machine, uint8_t opcode); + +#endif //MICROS_EXCHANGE_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c new file mode 100644 index 00000000..0477e825 --- /dev/null +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include "jump_operations.h" + +int16_t jump_short_relative(v8086* machine) +{ + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint32_t tempIP = machine->IP.w.ip; + tempIP += offset; + if((tempIP > 0xFFFF)) return RELATIVE_JMP_OVERFLOW; + machine->IP.w.ip = tempIP; + return OK; +} + +int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) +{ + uint8_t jump = 0; + if(opcode != 0xe3) + switch(opcode & 0x0fu) + { + case 0: //JO + if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <internal_state.operand_32_bit) + { + if(!machine->regs.d.ecx) jump = 1; + } + else + if(!machine->regs.w.cx) jump = 1; + } + if(jump) return jump_short_relative(machine); + return OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/jump_operations.h b/os/kernel/src/v8086/operations/jump_operations.h new file mode 100644 index 00000000..0325ebd2 --- /dev/null +++ b/os/kernel/src/v8086/operations/jump_operations.h @@ -0,0 +1,9 @@ +#ifndef MICROS_JUMP_OPERATIONS_H +#define MICROS_JUMP_OPERATIONS_H + +#include "../v8086.h" + +int16_t jump_short_relative(v8086* machine); +int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode); + +#endif //MICROS_JUMP_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c new file mode 100644 index 00000000..9dd942dd --- /dev/null +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include "mov_operations.h" +#include "internal_funcs.h" + +int16_t perform_mov(void* source, void* dest, uint8_t width) { + switch (width) { + case 8: + *((uint8_t *) dest) = *((uint8_t *) source); + break; + case 16: + *((uint16_t *) dest) = *((uint16_t *) source); + break; + case 32: + *((uint32_t *) dest) = *((uint32_t *) source); + break; + default: + return BAD_WIDTH; + } + return OK; +} + +int16_t perform_mov_rm(v8086* machine, uint8_t opcode) +{ + //Mod/RM + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + if(opcode % 2) + machine->internal_state.operand_32_bit ? 32 : 16; + void* source = get_variable_length_register(machine, get_reg(mod_rm), width); + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + switch (opcode) + { + case 0x88: + case 0x89: + return perform_mov(source, dest, width); + case 0x8a: + case 0x8b: + return perform_mov(dest, source, width); + default: + return UNKNOWN_ERROR; + } +} + +int16_t perform_mov_segment(v8086* machine, uint8_t opcode) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint16_t* source = select_segment_register(machine, get_reg(mod_rm)); + uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); + if(source == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest == NULL) return UNABLE_GET_MEMORY; + + if(opcode == 0x8c) + return perform_mov(source, dest, 16); + else if(opcode == 0x8e) + return perform_mov(dest, source, 16); + else return UNKNOWN_ERROR; +} + +int16_t perform_lea(v8086* machine) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + uint16_t segment; + uint32_t offset; + + if((mod_rm >> 6u) > 3) return BAD_MOD; + + int16_t r; + if(machine->internal_state.address_32_bit) + r = calculate_segment_offset_from_mode_32(machine, mod_rm, &segment, &offset); + else + r = calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + + if(r) return r; + + if(machine->internal_state.operand_32_bit) + { + uint32_t* reg = get_dword_register(machine, get_reg(mod_rm)); + if(reg == NULL) return UNDEFINED_REGISTER; + *reg = offset; + } + else + { + uint16_t* reg = get_word_register(machine, get_reg(mod_rm)); + if(reg == NULL) return UNDEFINED_REGISTER; + *reg = offset; + } + return OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/mov_operations.h b/os/kernel/src/v8086/operations/mov_operations.h new file mode 100644 index 00000000..5bba13ab --- /dev/null +++ b/os/kernel/src/v8086/operations/mov_operations.h @@ -0,0 +1,10 @@ +#ifndef MICROS_MOV_OPERATIONS_H +#define MICROS_MOV_OPERATIONS_H + +#include + +int16_t perform_mov_rm(v8086* machine, uint8_t opcode); +int16_t perform_mov_segment(v8086* machine, uint8_t opcode); +int16_t perform_lea(v8086* machine); + +#endif //MICROS_MOV_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 33840298..12dd9f00 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -4,6 +4,11 @@ #include "opcodes.h" #include "arithmetic_operations.h" #include "ascii_adjustments_operations.h" +#include "stack_operations.h" +#include "jump_operations.h" +#include "internal_funcs.h" +#include "exchange_operations.h" +#include "mov_operations.h" #define NO_CARRY 0 #define CARRY_FLAG_AS_NUMBER bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT @@ -118,4 +123,81 @@ OPCODE_PROTO(inc) OPCODE_PROTO(dec) { return perform_inc_dec(machine, opcode, true); +} + +OPCODE_PROTO(push_gpr) +{ + return push_gpr(machine, opcode); +} + +OPCODE_PROTO(pop_gpr) +{ + return pop_gpr(machine, opcode); +} + +OPCODE_PROTO(jcc) +{ + return jump_short_relative_on_condition(machine, opcode); +} + +OPCODE_PROTO(group1) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t recalculated_opcode = opcode - 0x80; + switch(get_reg(mod_rm)) + { + case 0: //ADD + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, + perform_adding); + case 1: //OR + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, perform_or); + case 2: //ADC + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, + CARRY_FLAG_AS_NUMBER, perform_adding); + case 3: //SBB + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, + CARRY_FLAG_AS_NUMBER, perform_subtracting); + case 4: //AND + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, perform_and); + case 5: //SUB + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, + perform_subtracting); + case 6: //XOR + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, perform_xor); + case 7: //CMP + return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, perform_cmp); + default: + return BAD_REG; + } +} + +OPCODE_PROTO(test) +{ + return execute_test(machine, opcode); +} + +OPCODE_PROTO(xchg) +{ + return perform_exchange_rm(machine, opcode); +} + +OPCODE_PROTO(mov_rm) +{ + return perform_mov_rm(machine, opcode); +} + +OPCODE_PROTO(mov_segment) +{ + return perform_mov_segment(machine, opcode); +} + +OPCODE_PROTO(lea) +{ + return perform_lea(machine); +} + +OPCODE_PROTO(pop_rm) +{ + return pop_rm(machine); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index a15fde04..a8aaf908 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -5,7 +5,7 @@ #define OPCODE_PROTO_NAME(name) v8086_opcode_##name #define OPCODE_PROTO(name) int16_t OPCODE_PROTO_NAME(name)(v8086* machine, uint8_t opcode) -#define ASSIGN_NULL(i) machine->operations[i] = NULL; +#define ASSIGN_NULL(i) machine->operations[i] = NULL #define ASSIGN_OPCODE(i, name) machine->operations[i] = OPCODE_PROTO_NAME(name) #define GROUP_OF_OPCODES(from, to, name) for(uint8_t i = from; i <= to; i++) ASSIGN_OPCODE(i, name) @@ -30,5 +30,16 @@ OPCODE_PROTO(cmp); OPCODE_PROTO(aas); OPCODE_PROTO(inc); OPCODE_PROTO(dec); +OPCODE_PROTO(push_gpr); +OPCODE_PROTO(pop_gpr); +OPCODE_PROTO(jcc); +OPCODE_PROTO(group1); +OPCODE_PROTO(test); +OPCODE_PROTO(xchg); +OPCODE_PROTO(mov_rm); +OPCODE_PROTO(mov_segment); +OPCODE_PROTO(lea); +OPCODE_PROTO(pop_rm); + #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c new file mode 100644 index 00000000..e2cc14e4 --- /dev/null +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include "stack_operations.h" + +uint16_t push_gpr(v8086* machine, uint8_t opcode) +{ + uint8_t width = 16; + void* reg = NULL; + if(machine->internal_state.operand_32_bit) width = 32; + reg = get_variable_length_register(machine, opcode & 7u, width); + if(reg == NULL) return UNDEFINED_REGISTER; + if(width==16) push_word(machine, *((uint16_t*)reg)); + else push_dword(machine, *((uint32_t*)reg)); + return OK; +} + +uint16_t pop_gpr(v8086* machine, uint8_t opcode) +{ + uint8_t width = 16; + void* reg = NULL; + if(machine->internal_state.operand_32_bit) width = 32; + reg = get_variable_length_register(machine, opcode & 7u, width); + if(reg == NULL) return UNDEFINED_REGISTER; + if(width==16) *((uint16_t*)reg) = pop_word(machine); + else *((uint32_t*)reg) = pop_dword(machine); + return OK; +} + +uint16_t pop_rm(v8086* machine) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(width == 16) + *((uint16_t*)dest) = pop_word(machine); + else + *((uint32_t*)dest) = pop_dword(machine); + return OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/stack_operations.h b/os/kernel/src/v8086/operations/stack_operations.h new file mode 100644 index 00000000..7ec8bfc2 --- /dev/null +++ b/os/kernel/src/v8086/operations/stack_operations.h @@ -0,0 +1,10 @@ +#ifndef MICROS_STACK_OPERATIONS_H +#define MICROS_STACK_OPERATIONS_H + +#include "../v8086.h" + +uint16_t push_gpr(v8086* machine, uint8_t opcode); +uint16_t pop_gpr(v8086* machine, uint8_t opcode); +uint16_t pop_rm(v8086* machine); + +#endif //MICROS_STACK_OPERATIONS_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e2676e69..e44ac925 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -44,6 +44,18 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0x3fu, aas); GROUP_OF_OPCODES(0x40u, 0x47u, inc); GROUP_OF_OPCODES(0x48u, 0x4f, dec); + GROUP_OF_OPCODES(0x50u, 0x57u, push_gpr); + GROUP_OF_OPCODES(0x58u, 0x5fu, pop_gpr); + //NOT DEFINED IN 8086 processor + for(uint8_t i = 0x60u; i <= 0x6fu; i++) ASSIGN_NULL(i); + GROUP_OF_OPCODES(0x70u, 0x7fu, jcc); + GROUP_OF_OPCODES(0x80u, 0x83u, group1); + GROUP_OF_OPCODES(0x84u, 0x85u, test); + GROUP_OF_OPCODES(0x86u, 0x87u, xchg); + GROUP_OF_OPCODES(0x88u, 0x8bu, mov_rm); + ASSIGN_OPCODE(0x8cu, mov_segment); + ASSIGN_OPCODE(0x8du, lea); + ASSIGN_OPCODE(0x8eu, mov_segment); } @@ -141,46 +153,6 @@ int16_t parse_and_execute_instruction(v8086* machine) { goto decode; //ommit prefix, contniue parsinf opcode; } - //GROUP 1 - else if(opcode >= 0x80 && opcode <= 0x83) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t recalculated_opcode = opcode - 0x80; - switch(get_reg(mod_rm)) - { - case 0: //ADD - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, - perform_adding); - break; - case 1: //OR - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_or); - break; - case 2: //ADC - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, - bit_get(machine->regs.w.flags, 1u << CARRY_FLAG_BIT) != - 0, perform_adding); - break; - case 3: //SBB - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, - bit_get(machine->regs.w.flags, 1u << CARRY_FLAG_BIT) != - 0, perform_subtracting); - break; - case 4: //AND - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_and); - break; - case 5: //SUB - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, - perform_subtracting); - break; - case 6: //XOR - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_xor); - break; - case 7: //CMP - status = perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, 0, perform_cmp); - break; - } - } //GROUP 3 else if(opcode >= 0xf6 && opcode <= 0xf7) { @@ -248,107 +220,13 @@ int16_t parse_and_execute_instruction(v8086* machine) } } //PUSH Operations - //PUSH General purpose registers - else if(opcode >= 0x50 && opcode <= 0x57) - { - uint8_t width = 16; - void* reg = NULL; - if(machine->internal_state.operand_32_bit) width = 16; - reg = get_variable_length_register(machine, opcode & 7u, width); - if(reg == NULL) return UNDEFINED_REGISTER; - if(width==16) push_word(machine, *((uint16_t*)reg)); - else if(width==32) push_dword(machine, *((uint32_t*)reg)); - else return BAD_WIDTH; - } //PUSH FLAGS else if(opcode == 0x9c) push_word(machine, machine->regs.w.flags); //POP Operations - //POP General purpose registers - else if(opcode >= 0x50 && opcode <= 0x57) - { - uint8_t width = 16; - void* reg = NULL; - if(machine->internal_state.operand_32_bit) width = 16; - reg = get_variable_length_register(machine, opcode & 7u, width); - if(reg == NULL) return UNDEFINED_REGISTER; - if(width==16) *((uint16_t*)reg) = pop_word(machine); - else if(width==32) *((uint32_t*)reg) = pop_dword(machine); - else return BAD_WIDTH; - } //POP FLAGS else if(opcode == 0x9d) machine->regs.w.flags = pop_word(machine); - //XCHG group - //XCHG GRP with AX or EAX - else if(opcode >= 90 && opcode <= 97) - { - uint8_t width = 16; - if(machine->internal_state.operand_32_bit) width = 32; - if(width == 16) - { - uint16_t temp; - uint16_t* regA = get_word_register(machine, AX); - uint16_t* regB = get_word_register(machine, opcode & 7u); - if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; - temp = *regA; - *regA = *regB; - *regB = temp; - } - else if(width == 32) - { - uint32_t temp; - uint32_t* regA = get_dword_register(machine, EAX); - uint32_t* regB = get_dword_register(machine, opcode & 7u); - if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; - temp = *regA; - *regA = *regB; - *regB = temp; - } - else return -1; - } - //XCHG r8, rm8 or XCHG r16, rm16 or XCHG r32, rm32 - else if(opcode >= 0x86 && opcode <= 0x87) - { - int8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - if(opcode == 0x86) - { - uint8_t* source = get_byte_register(machine, get_reg(mod_rm)); - uint8_t* dest = get_memory_from_mode(machine, mod_rm, 8); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - uint8_t temp; - temp = *source; - *source = *dest; - *dest = temp; - } - else if(opcode == 0x87) - { - if(machine->internal_state.operand_32_bit) - { - uint32_t* source = get_dword_register(machine, get_reg(mod_rm)); - uint32_t* dest = get_memory_from_mode(machine, mod_rm, 32); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - uint32_t temp; - temp = *source; - *source = *dest; - *dest = temp; - } - else - { - uint16_t* source = get_word_register(machine, get_reg(mod_rm)); - uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - uint16_t temp; - temp = *source; - *source = *dest; - *dest = temp; - } - } - } //ROLS and RORS Group (Group 2) else if(opcode >= 0xd0 && opcode <= 0xd3) { @@ -390,78 +268,6 @@ int16_t parse_and_execute_instruction(v8086* machine) } } //Jumps Group - //SHORT JUMPS on conditions - else if((opcode >= 0x70 && opcode <= 0x7f) || (opcode == 0xe3)) - { - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint32_t tempIP = machine->IP.w.ip; - uint8_t jump = 0; - if(opcode != 0xe3) - switch(opcode & 0x0fu) - { - case 0: //JO - if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <internal_state.operand_32_bit) - { - if(!machine->regs.d.ecx) jump = 1; - } - else - if(!machine->regs.w.cx) jump = 1; - } - if(jump) tempIP += offset; - if(tempIP > 0xFFFF) return -1; - machine->IP.w.ip = tempIP; - } //Short relative JMP else if(opcode == 0xeb) { @@ -584,74 +390,6 @@ int16_t parse_and_execute_instruction(v8086* machine) return UNKNOWN_ERROR; } } - //MOV r8/r16/r32, rm8/rm16/rm32 or MOV rm8/rm16/rm32, r8/r16/r32 - else if(opcode >= 0x88 && opcode <= 0x8b) - { - //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - void* source = NULL; - void* dest = NULL; - uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; - switch (opcode) - { - case 0x88: - source = get_byte_register(machine, get_reg(mod_rm)); - dest = get_memory_from_mode(machine, mod_rm, 8); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - *((uint8_t*)dest) = *((uint8_t*) source); - break; - case 0x89: - source = get_variable_length_register(machine, get_reg(mod_rm), width); - dest = get_memory_from_mode(machine, mod_rm, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); - else *((uint32_t*)dest) = *((uint32_t*) source); - break; - case 0x8a: - dest = get_byte_register(machine, get_reg(mod_rm)); - source = get_memory_from_mode(machine, mod_rm, 8); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; - *((uint8_t*)dest) = *((uint8_t*) source); - break; - case 0x8b: - dest = get_variable_length_register(machine, get_reg(mod_rm), width); - source = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; - if(width == 16) *((uint16_t*)dest) = *((uint16_t*) source); - else *((uint32_t*)dest) = *((uint32_t*) source); - break; - default: - return UNKNOWN_ERROR; - } - } - //MOV Segment to/from r/m - else if(opcode == 0x8c || opcode == 0x8e) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint16_t* source = NULL; - uint16_t* dest = NULL; - if(opcode == 0x8c) - { - source = select_segment_register(machine, get_reg(mod_rm)); - dest = get_memory_from_mode(machine, mod_rm, 16); - if(source == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - } - else - { - dest = select_segment_register(machine, get_reg(mod_rm)); - source = get_memory_from_mode(machine, mod_rm, 16); - if(dest == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; - } - *dest = *source; - } //MOV rm, imm else if(opcode >= 0xc6 && opcode <= 0xc7) { @@ -686,30 +424,6 @@ int16_t parse_and_execute_instruction(v8086* machine) } } //TEST GROUP - else if(opcode == 0x84) - { - //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t* reg = get_byte_register(machine, get_reg(mod_rm)); - uint8_t* memory = get_memory_from_mode(machine, mod_rm, 8); - if(reg == NULL) return UNDEFINED_REGISTER; - if(memory == NULL) return UNABLE_GET_MEMORY; - status = perform_test(machine, reg, memory, 8); - } - else if(opcode == 0x85) - { - //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t width = 16; - if(machine->internal_state.operand_32_bit) width = 32; - void* source = get_variable_length_register(machine, get_reg(mod_rm), width); - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; - status = perform_test(machine, source, dest, width); - } else if(opcode == 0xa8) { //Mod/RM @@ -977,31 +691,6 @@ int16_t parse_and_execute_instruction(v8086* machine) } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); } //LOAD Operations group - //LEA - else if(opcode == 0x8d) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - uint16_t segment; - uint32_t offset; - - if((mod_rm >> 6u) > 3) return -1; - - int16_t r = calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); - if(r) return r; - - if(machine->internal_state.operand_32_bit) - { - uint32_t* reg = get_dword_register(machine, get_reg(mod_rm)); - *reg = offset; - } - else - { - uint16_t* reg = get_word_register(machine, get_reg(mod_rm)); - *reg = offset; - } - } //LDS or LES else if(opcode >= 0xc4 && opcode <= 0xc5) { @@ -1324,17 +1013,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //GROUP 1A else if(opcode == 0x8f) { - //ITS only POP rm16/32 - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t width = 16; - if(machine->internal_state.operand_32_bit) width = 32; - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(width == 16) - *((uint16_t*)dest) = pop_word(machine); - else if(width == 32) - *((uint32_t*)dest) = pop_dword(machine); } else return UNDEFINED_OPCODE; recalculate_ip: machine->IP.w.ip += machine->internal_state.IPOffset; diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 1e4b7d40..6a79bd28 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -49,6 +49,7 @@ typedef enum _machine_status { BAD_BASE = -11, UNDEFINED_RECALCULATED_OPCODE = -12, BAD_INT_NUMBER = -13, + RELATIVE_JMP_OVERFLOW = -14, UNKNOWN_ERROR = -69 } machine_status; From 5c7993e315df32225f7449136e97f6ffa4963c8d Mon Sep 17 00:00:00 2001 From: SzateX Date: Thu, 28 May 2020 02:51:59 +0200 Subject: [PATCH 058/165] Still refactoring things... Slowly like a slime, but careful to not make mistake. --- os/kernel/src/v8086/memory_operations.h | 1 + .../v8086/operations/arithmetic_operations.c | 111 ++- .../v8086/operations/arithmetic_operations.h | 4 + .../src/v8086/operations/io_operations.c | 47 ++ .../src/v8086/operations/io_operations.h | 10 + .../src/v8086/operations/jump_operations.c | 61 ++ .../src/v8086/operations/jump_operations.h | 3 + .../src/v8086/operations/misc_operations.c | 1 + .../src/v8086/operations/misc_operations.h | 4 + .../src/v8086/operations/mov_operations.c | 114 ++- .../src/v8086/operations/mov_operations.h | 7 + os/kernel/src/v8086/operations/opcodes.c | 120 ++- os/kernel/src/v8086/operations/opcodes.h | 21 + .../v8086/operations/procedure_operations.c | 103 +++ .../v8086/operations/procedure_operations.h | 15 + .../src/v8086/operations/string_operations.c | 182 +++++ .../src/v8086/operations/string_operations.h | 14 + os/kernel/src/v8086/v8086.c | 748 +----------------- 18 files changed, 839 insertions(+), 727 deletions(-) create mode 100644 os/kernel/src/v8086/operations/io_operations.c create mode 100644 os/kernel/src/v8086/operations/io_operations.h create mode 100644 os/kernel/src/v8086/operations/misc_operations.c create mode 100644 os/kernel/src/v8086/operations/misc_operations.h create mode 100644 os/kernel/src/v8086/operations/procedure_operations.c create mode 100644 os/kernel/src/v8086/operations/procedure_operations.h create mode 100644 os/kernel/src/v8086/operations/string_operations.c create mode 100644 os/kernel/src/v8086/operations/string_operations.h diff --git a/os/kernel/src/v8086/memory_operations.h b/os/kernel/src/v8086/memory_operations.h index b08cdabf..30f1777a 100644 --- a/os/kernel/src/v8086/memory_operations.h +++ b/os/kernel/src/v8086/memory_operations.h @@ -2,6 +2,7 @@ #define V8086_MEMORY_OPERATIONS_H #include +#include static inline uint32_t get_absolute_address(uint32_t segment, uint32_t offset) { diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 3dd6519e..23fad1c9 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -626,4 +626,113 @@ int16_t execute_test(v8086* machine, uint8_t opcode) if(source == NULL) return UNDEFINED_REGISTER; if(dest == NULL) return UNABLE_GET_MEMORY; return perform_test(machine, source, dest, width); -} \ No newline at end of file +} + +int16_t execute_test_immediate(v8086* machine, uint8_t opcode) +{ + uint8_t width = 8; + if(opcode == 0xa9u) width = machine->internal_state.operand_32_bit ? 32 : 16; + void* immediate = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); + machine->internal_state.IPOffset += width / 8; + void* reg = get_variable_length_register(machine, AX, width); + if(immediate == NULL) return UNABLE_GET_MEMORY; + if(reg == NULL) return UNDEFINED_REGISTER; + return perform_test(machine, immediate, reg, width); +} + +int16_t execute_group_2(v8086 *machine, uint8_t opcode) { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t arg = opcode <=0xd1 ? 1 : machine->regs.h.cl; + uint8_t width = 8; + if(opcode % 2){ + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + } + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(dest == NULL) return UNABLE_GET_MEMORY; + switch(get_reg(mod_rm)) + { + case 0: + return perform_rol(machine, dest, arg, width); + case 1: + return perform_ror(machine, dest, arg, width); + case 2: + return perform_rcl(machine, dest, arg, width); + case 3: + return perform_rcr(machine, dest, arg, width); + case 4: + return perform_shl(machine, dest, arg, width); + case 5: + return perform_shr(machine, dest, arg, width); + case 6: + return UNDEFINED_OPCODE; + case 7: + return perform_sar(machine, dest, arg, width); + default: + return BAD_REG; + } +} + +int16_t execute_group_3(v8086* machine, uint8_t opcode) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + if(opcode == 0xf7) + { + if(machine->internal_state.operand_32_bit) width = 32; + else width = 16; + } + + void* dest = get_memory_from_mode(machine, mod_rm, width); + + if(dest == NULL) return UNABLE_GET_MEMORY; + + switch(get_reg(mod_rm)) + { + case 0: //TEST + { + uint32_t immediate; + if(width == 8) + { + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 1; + } + else if(width == 16) + { + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 2; + } + else if(width == 32) + { + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine -> internal_state.IPOffset += 4; + } + return perform_test(machine, &immediate, dest, width); + break; + } + case 2: //NOT + if(width == 8) + *((uint8_t*)dest) = ~(*((uint8_t*)dest)); + else if(width == 16) + *((uint16_t*)dest) = ~(*((uint16_t*)dest)); + else if(width == 32) + *((uint32_t*)dest) = ~(*((uint32_t*)dest)); + else return BAD_WIDTH; + return OK; + break; + case 3: //NEG + return perform_neg(machine, dest, width); + case 4: //MUL + return perform_multiplication(machine, dest, 0, width); + case 5: //IMUL + return perform_multiplication(machine, dest, 1, width); + case 6: //DIV + return perform_division(machine, dest, 0, width); + case 7: //IDIV + return perform_division(machine, dest, 1, width); + default: + return BAD_REG; + } +} diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.h b/os/kernel/src/v8086/operations/arithmetic_operations.h index 7b46c21d..fc9faa8c 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.h +++ b/os/kernel/src/v8086/operations/arithmetic_operations.h @@ -25,4 +25,8 @@ int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalc int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)); int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec); int16_t execute_test(v8086* machine, uint8_t opcode); +int16_t execute_test_immediate(v8086* machine, uint8_t opcode); +int16_t execute_group_2(v8086* machine, uint8_t opcode); +int16_t execute_group_3(v8086* machine, uint8_t opcode); + #endif //V8086_ARITHMETIC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/io_operations.c b/os/kernel/src/v8086/operations/io_operations.c new file mode 100644 index 00000000..95388b4d --- /dev/null +++ b/os/kernel/src/v8086/operations/io_operations.c @@ -0,0 +1,47 @@ +#include +#include +#include "io_operations.h" + +int16_t perform_in_imm(v8086* machine, uint8_t width) +{ + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 8) machine->regs.h.al = io_in_byte(immediate); + else if(width == 16) machine->regs.w.ax = io_in_word(immediate); + else if(width == 32) machine->regs.d.eax = io_in_long(immediate); + else return BAD_WIDTH; + return OK; +} + +int16_t perform_in_dx(v8086* machine, uint8_t width) +{ + if(width == 8) machine->regs.h.al = io_in_byte(machine->regs.x.dx); + else if(width == 16) machine->regs.w.ax = io_in_word(machine->regs.x.dx); + else if(width == 32) machine->regs.d.eax = io_in_long(machine->regs.x.dx); + else return BAD_WIDTH; + return OK; +} + +int16_t perform_out_imm(v8086* machine, uint8_t width) +{ + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 8) io_out_byte(immediate, machine->regs.h.al); + else if(width == 16) io_out_word(immediate, machine->regs.w.ax); + else if(width == 32) io_out_long(immediate, machine->regs.d.eax); + else return BAD_WIDTH; + + return OK; +} + +int16_t perform_out_dx(v8086* machine, uint8_t width) +{ + if(width == 8) io_out_byte(machine->regs.x.dx, machine->regs.h.al); + else if(width == 16) io_out_word(machine->regs.x.dx, machine->regs.w.ax); + else if(width == 32) io_out_long(machine->regs.x.dx, machine->regs.d.eax); + else return BAD_WIDTH; + + return OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/io_operations.h b/os/kernel/src/v8086/operations/io_operations.h new file mode 100644 index 00000000..f22945dc --- /dev/null +++ b/os/kernel/src/v8086/operations/io_operations.h @@ -0,0 +1,10 @@ +#ifndef MICROS_IO_OPERATIONS_H +#define MICROS_IO_OPERATIONS_H + +#include +#include + +int16_t perform_in_imm(v8086* machine, uint8_t width); +int16_t perform_in_dx(v8086* machine, uint8_t width); + +#endif //MICROS_IO_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c index 0477e825..3bfefa70 100644 --- a/os/kernel/src/v8086/operations/jump_operations.c +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -14,6 +14,25 @@ int16_t jump_short_relative(v8086* machine) return OK; } +int16_t jump_near_relative(v8086* machine) +{ + int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + machine->IP.w.ip += offset; + return OK; +} + +int16_t jump_far(v8086* machine) +{ + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->sregs.cs = newCS; + machine->IP.w.ip = newIP; + machine->internal_state.IPOffset = 0; + return OK; +} + int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) { uint8_t jump = 0; @@ -80,4 +99,46 @@ int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) } if(jump) return jump_short_relative(machine); return OK; +} + +int16_t perform_loop_loopne(v8086* machine, uint8_t opcode) +{ + uint8_t jump = 0; + int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(machine->internal_state.operand_32_bit) machine->regs.d.ecx--; + else machine->regs.w.cx--; + + switch (opcode) + { + case 0xe0: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; + } + else + if(machine->regs.w.cx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; + break; + case 0xe1: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; + } + else + if(machine->regs.w.cx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; + break; + case 0xe2: + if(machine->internal_state.operand_32_bit){ + if(machine->regs.d.ecx) jump = 1; + } + else + if(machine->regs.w.cx) jump = 1; + break; + default: + return UNKNOWN_ERROR; + } + + if(jump) + machine->IP.w.ip += offset; + + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/jump_operations.h b/os/kernel/src/v8086/operations/jump_operations.h index 0325ebd2..b6992fcf 100644 --- a/os/kernel/src/v8086/operations/jump_operations.h +++ b/os/kernel/src/v8086/operations/jump_operations.h @@ -4,6 +4,9 @@ #include "../v8086.h" int16_t jump_short_relative(v8086* machine); +int16_t jump_near_relative(v8086* machine); +int16_t jump_far(v8086* machine); +int16_t perform_loop_loopne(v8086* machine, uint8_t opcode); int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode); #endif //MICROS_JUMP_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c new file mode 100644 index 00000000..4e71d410 --- /dev/null +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -0,0 +1 @@ +#include "misc_operations.h" diff --git a/os/kernel/src/v8086/operations/misc_operations.h b/os/kernel/src/v8086/operations/misc_operations.h new file mode 100644 index 00000000..745f1e6b --- /dev/null +++ b/os/kernel/src/v8086/operations/misc_operations.h @@ -0,0 +1,4 @@ +#ifndef MICROS_MISC_OPERATIONS_H +#define MICROS_MISC_OPERATIONS_H + +#endif //MICROS_MISC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index 9dd942dd..251b0263 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -29,7 +29,7 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode) machine->internal_state.IPOffset += 1; uint8_t width = 8; if(opcode % 2) - machine->internal_state.operand_32_bit ? 32 : 16; + width = machine->internal_state.operand_32_bit ? 32 : 16; void* source = get_variable_length_register(machine, get_reg(mod_rm), width); void* dest = get_memory_from_mode(machine, mod_rm, width); if(source == NULL) return UNDEFINED_REGISTER; @@ -63,6 +63,82 @@ int16_t perform_mov_segment(v8086* machine, uint8_t opcode) else return UNKNOWN_ERROR; } +uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode) +{ + uint8_t width; + if(opcode >= 0xb0 && opcode <= 0xb7) width = 8; + else if(opcode >= 0xb8 && opcode <= 0xbf) width = machine->internal_state.operand_32_bit ? 32 : 16; + else return UNKNOWN_ERROR; + uint8_t reg_selector = (opcode >= 0xb8) ? (opcode - 0xb8u) & 0x7u : opcode & 0x7u; + void* reg = get_variable_length_register(machine, reg_selector, width); + if(reg == NULL) return UNDEFINED_REGISTER; + void* imm = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); + machine->internal_state.IPOffset += width / 8; + return perform_mov(imm, reg, width); +} + +uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + if(opcode == 0xc6) + { + uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); + if(mem == NULL) return UNABLE_GET_MEMORY; + *mem = immediate; + } + else + { + if(machine->internal_state.operand_32_bit) + { + uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); + if(mem == NULL) return UNABLE_GET_MEMORY; + *mem = immediate; + } + else + { + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); + if(mem == NULL) return UNABLE_GET_MEMORY; + *mem = immediate; + } + } + return OK; +} + +int16_t perform_mov_moffset(v8086* machine, uint8_t opcode) +{ + uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + uint16_t* segment = machine->internal_state.segment_reg_select == DEFAULT ? select_segment_register(machine, DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + switch (opcode) + { + case 0xa0: + machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); + break; + case 0xa1: + if(machine->internal_state.operand_32_bit) machine->regs.d.eax = read_dword_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); + else machine->regs.x.ax = read_word_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); + break; + case 0xa2: + write_byte_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.h.al); + break; + case 0xa3: + if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.d.eax); + else write_word_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.x.ax); + break; + default: + return UNKNOWN_ERROR; + } + return OK; +} + int16_t perform_lea(v8086* machine) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); @@ -94,4 +170,40 @@ int16_t perform_lea(v8086* machine) *reg = offset; } return OK; +} + +int16_t convert_byte_to_word(v8086* machine) +{ + if(machine->internal_state.operand_32_bit) + machine->regs.d.eax = ((int32_t)(machine->regs.w.ax)); + else + machine->regs.w.ax = ((int16_t)(machine->regs.h.al)); + return OK; +} + +int16_t convert_word_to_double(v8086* machine) +{ + if(machine->internal_state.operand_32_bit){ + int64_t t = machine->regs.d.eax; + machine->regs.d.edx = ((uint64_t)t >> 32u); + } + else{ + int32_t t = machine->regs.w.ax; + machine->regs.w.dx = ((uint32_t)t >> 16u); + } + return OK; +} + +int16_t store_flags(v8086* machine) +{ + for(uint8_t i = 0; i < 8; i++) + if(i != 1 && i != 3 && i != 5) + bit_write(machine->regs.w.flags, 1u <regs.h.ah, 1u <regs.h.ah = machine->regs.w.flags & 0xFFu; + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/mov_operations.h b/os/kernel/src/v8086/operations/mov_operations.h index 5bba13ab..f5a206d4 100644 --- a/os/kernel/src/v8086/operations/mov_operations.h +++ b/os/kernel/src/v8086/operations/mov_operations.h @@ -5,6 +5,13 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode); int16_t perform_mov_segment(v8086* machine, uint8_t opcode); +int16_t perform_mov_moffset(v8086* machine, uint8_t opcode); +uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode); +uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode); int16_t perform_lea(v8086* machine); +int16_t convert_byte_to_word(v8086* machine); +int16_t convert_word_to_double(v8086* machine); +int16_t store_flags(v8086* machine); +int16_t load_flags(v8086* machine); #endif //MICROS_MOV_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 12dd9f00..4f241e2f 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -9,6 +9,10 @@ #include "internal_funcs.h" #include "exchange_operations.h" #include "mov_operations.h" +#include "procedure_operations.h" +#include "string_operations.h" +#include "io_operations.h" +#include "misc_operations.h" #define NO_CARRY 0 #define CARRY_FLAG_AS_NUMBER bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT @@ -200,4 +204,118 @@ OPCODE_PROTO(lea) OPCODE_PROTO(pop_rm) { return pop_rm(machine); -} \ No newline at end of file +} + +OPCODE_PROTO(xchg_ax) +{ + return perform_exchange_ax_register(machine, opcode); +} + +OPCODE_PROTO(cbw) +{ + return convert_byte_to_word(machine); +} + +OPCODE_PROTO(cwd) +{ + return convert_word_to_double(machine); +} + +OPCODE_PROTO(far_call) +{ + return far_call(machine); +} + +OPCODE_PROTO(pushf) +{ + push_word(machine, machine->regs.w.flags); + return OK; +} + +OPCODE_PROTO(popf) +{ + machine->regs.w.flags = pop_word(machine); + return OK; +} + +OPCODE_PROTO(sahf) +{ + return store_flags(machine); +} + +OPCODE_PROTO(lahf) +{ + return load_flags(machine); +} + +OPCODE_PROTO(mov_moffset) +{ + return perform_mov_moffset(machine, opcode); +} +OPCODE_PROTO(movsb) +{ + return perform_movs(machine, 8); +} +OPCODE_PROTO(movsw) +{ + return perform_movs(machine, machine->internal_state.operand_32_bit ? 32: 16); +} +OPCODE_PROTO(cmpsb) +{ + return perform_cmps(machine, 8); +} +OPCODE_PROTO(cmpsw) +{ + return perform_cmps(machine, machine->internal_state.operand_32_bit ? 32: 16); +} +OPCODE_PROTO(test_imm) +{ + return execute_test_immediate(machine, opcode); +} +OPCODE_PROTO(stosb) +{ + return perform_stos(machine, 8); +} +OPCODE_PROTO(stosw) +{ + return perform_stos(machine, machine->internal_state.operand_32_bit ? 32: 16); +} +OPCODE_PROTO(lodsb) +{ + return perform_lods(machine, 8); +} +OPCODE_PROTO(lodsw) +{ + return perform_lods(machine, machine->internal_state.operand_32_bit ? 32: 16); +} +OPCODE_PROTO(scasb) +{ + return perform_scas(machine, 8); +} +OPCODE_PROTO(scasw) +{ + return perform_scas(machine, machine->internal_state.operand_32_bit ? 32: 16); +} +OPCODE_PROTO(mov_gpr_imm) +{ + return perform_mov_gpr_imm(machine, opcode); +} + + +/* + * //INT, imm and INT 3 and INTO + else if(opcode >= 0xcc && opcode <= 0xce) + { + uint8_t interrupt_number = 3; + if(opcode == 0xcd) //INT, imm + { + interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } + else if(opcode == 0xce) //INTO + { + if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) goto recalculate_ip; + interrupt_number = 4; + } + } + */ \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index a8aaf908..44c75588 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -40,6 +40,27 @@ OPCODE_PROTO(mov_rm); OPCODE_PROTO(mov_segment); OPCODE_PROTO(lea); OPCODE_PROTO(pop_rm); +OPCODE_PROTO(xchg_ax); +OPCODE_PROTO(cbw); +OPCODE_PROTO(cwd); +OPCODE_PROTO(far_call); +OPCODE_PROTO(pushf); +OPCODE_PROTO(popf); +OPCODE_PROTO(sahf); +OPCODE_PROTO(lahf); +OPCODE_PROTO(mov_moffset); +OPCODE_PROTO(movsb); +OPCODE_PROTO(movsw); +OPCODE_PROTO(cmpsb); +OPCODE_PROTO(cmpsw); +OPCODE_PROTO(test_imm); +OPCODE_PROTO(stosb); +OPCODE_PROTO(stosw); +OPCODE_PROTO(lodsb); +OPCODE_PROTO(lodsw); +OPCODE_PROTO(scasb); +OPCODE_PROTO(scasw); +OPCODE_PROTO(mov_gpr_imm); #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/procedure_operations.c b/os/kernel/src/v8086/operations/procedure_operations.c new file mode 100644 index 00000000..e6b46c16 --- /dev/null +++ b/os/kernel/src/v8086/operations/procedure_operations.c @@ -0,0 +1,103 @@ +#include +#include +#include "procedure_operations.h" + +int16_t near_relative_call(v8086* machine) +{ + int16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + + machine->IP.w.ip += machine->internal_state.IPOffset; + push_word(machine, machine->IP.w.ip); + machine->IP.w.ip += immediate; + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t far_call(v8086 *machine){ + int32_t newIP; + if (machine->internal_state.operand_32_bit) + { + newIP = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + } + else + { + newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP.w.ip + machine->internal_state.IPOffset); + machine->IP.w.ip = newIP; + machine->sregs.cs = newCS; + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t near_ret(v8086* machine) +{ + machine->IP.w.ip = pop_word(machine); + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t near_ret_imm(v8086* machine) +{ + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + machine->IP.w.ip = pop_word(machine); + machine->regs.w.sp += immediate; + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t far_ret(v8086* machine) +{ + machine->IP.w.ip = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t far_ret_imm(v8086* machine) +{ + uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + machine->IP.w.ip = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->regs.w.sp += immediate; + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number) +{ + int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4)); + int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4 + 2)); + + push_word(machine, machine->regs.w.flags); + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP.w.ip); + + machine->IP.w.ip = newIP; + machine->sregs.cs = newCS; + + machine->internal_state.IPOffset = 0; + return OK; +} + +int16_t perform_iret(v8086* machine) +{ + machine->IP.w.ip = pop_word(machine); + machine->sregs.cs = pop_word(machine); + machine->regs.w.flags = pop_word(machine); + + machine->internal_state.IPOffset = 0; + return OK; +} diff --git a/os/kernel/src/v8086/operations/procedure_operations.h b/os/kernel/src/v8086/operations/procedure_operations.h new file mode 100644 index 00000000..b3a15573 --- /dev/null +++ b/os/kernel/src/v8086/operations/procedure_operations.h @@ -0,0 +1,15 @@ +#ifndef MICROS_PROCEDURE_OPERATIONS_H +#define MICROS_PROCEDURE_OPERATIONS_H + +#include +#include + +int16_t near_relative_call(v8086* machine); +int16_t far_call(v8086* machine); + +int16_t near_ret(v8086* machine); +int16_t near_ret_imm(v8086* machine); +int16_t far_ret(v8086* machine); +int16_t far_ret_imm(v8086* machine); + +#endif //MICROS_PROCEDURE_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c new file mode 100644 index 00000000..0e833328 --- /dev/null +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include "string_operations.h" + +uint16_t perform_movs(v8086 *machine, uint8_t width) { + uint16_t* source_segment; + uint16_t* dest_segment = select_segment_register(machine, ES); + if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + + do{ + void* source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + void* dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(width == 8) + *((uint8_t*)dest) = *((uint8_t*) source); + else if(width == 16) + *((uint16_t*)dest) = *((uint16_t*) source); + else if(width == 32) + *((uint32_t*)dest) = *((uint32_t*) source); + else + return BAD_WIDTH; + int8_t offset = width / 8; + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + + return OK; +} + +uint16_t perform_stos(v8086* machine, uint8_t width) +{ + uint16_t* segment = select_segment_register(machine, ES); + void* source; + void* dest; + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + + do{ + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); + source = get_variable_length_register(machine, AL, width); + if(source == NULL) return UNDEFINED_REGISTER; + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return -1; + + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + + return OK; +} + +uint16_t perform_cmps(v8086* machine, uint8_t width) +{ + uint16_t* source_segment; + uint16_t* dest_segment = select_segment_register(machine, ES); + void* source; + void* dest; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + uint64_t result; + + if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) return OK; + + do{ + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return BAD_WIDTH; + + result = dest_before - source_before; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || + (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; + } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); + + return OK; +} + +uint16_t perform_lods(v8086* machine, uint8_t width) +{ + uint16_t* segment; + void* source; + void* dest; + + if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); + else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + + do{ + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); + dest = get_variable_length_register(machine, AL, width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return BAD_WIDTH; + + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + return OK; +} + +uint16_t perform_scas(v8086* machine, uint8_t width) +{ + uint16_t* source_segment = select_segment_register(machine, ES); + void* source; + void* dest; + uint32_t dest_before; //for overflow flag checking + uint32_t source_before; + uint64_t result; + + if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) return OK; + + do{ + dest = get_variable_length_register(machine, AX, width); + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); + if(dest == NULL) return UNDEFINED_REGISTER; + if(width == 8){ + dest_before = *((uint8_t*)dest); + source_before = *((uint8_t*)source); + } else if(width == 16){ + dest_before = *((uint16_t*)dest); + source_before = *((uint16_t*)source); + } else if(width == 32){ + dest_before = *((uint32_t*)dest); + source_before = *((uint32_t*)source); + } else return BAD_WIDTH; + + result = dest_before - source_before; + bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + uint8_t parrity = result & 1u; + for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || + (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; + + } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); + return OK; +} diff --git a/os/kernel/src/v8086/operations/string_operations.h b/os/kernel/src/v8086/operations/string_operations.h new file mode 100644 index 00000000..5492b31f --- /dev/null +++ b/os/kernel/src/v8086/operations/string_operations.h @@ -0,0 +1,14 @@ +#include +#include + +#ifndef MICROS_STRING_OPERATIONS_H +#define MICROS_STRING_OPERATIONS_H + +uint16_t perform_movs(v8086* machine, uint8_t width); +uint16_t perform_stos(v8086* machine, uint8_t width); +uint16_t perform_cmps(v8086* machine, uint8_t width); +uint16_t perform_lods(v8086* machine, uint8_t width); +uint16_t perform_scas(v8086* machine, uint8_t width); + + +#endif //MICROS_STRING_OPERATIONS_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e44ac925..abb51b6b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -56,7 +56,30 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0x8cu, mov_segment); ASSIGN_OPCODE(0x8du, lea); ASSIGN_OPCODE(0x8eu, mov_segment); - + ASSIGN_OPCODE(0x8fu, pop_rm); + GROUP_OF_OPCODES(0x90u, 0x97u, xchg_ax); + ASSIGN_OPCODE(0x98u, cbw); + ASSIGN_OPCODE(0x99u, cwd); + ASSIGN_OPCODE(0x9au, far_call); + //NO COPROCESSOR + ASSIGN_NULL(0x9bu); + ASSIGN_OPCODE(0x9cu, pushf); + ASSIGN_OPCODE(0x9du, popf); + ASSIGN_OPCODE(0x9eu, sahf); + ASSIGN_OPCODE(0x9fu, lahf); + GROUP_OF_OPCODES(0xa0u, 0xa3u, mov_moffset); + ASSIGN_OPCODE(0xa4u, movsb); + ASSIGN_OPCODE(0xa5u, movsw); + ASSIGN_OPCODE(0xa6u, cmpsb); + ASSIGN_OPCODE(0xa7u, cmpsw); + GROUP_OF_OPCODES(0xa8u, 0xa9u, test_imm); + ASSIGN_OPCODE(0xaau, stosb); + ASSIGN_OPCODE(0xabu, stosw); + ASSIGN_OPCODE(0xacu, lodsb); + ASSIGN_OPCODE(0xadu, lodsw); + ASSIGN_OPCODE(0xaeu, scasb); + ASSIGN_OPCODE(0xafu, scasw); + GROUP_OF_OPCODES(0xb0u, 0xbfu, mov_gpr_imm); } v8086* v8086_create_machine() @@ -153,543 +176,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { goto decode; //ommit prefix, contniue parsinf opcode; } - //GROUP 3 - else if(opcode >= 0xf6 && opcode <= 0xf7) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t width = 8; - if(opcode == 0xf7) - { - if(machine->internal_state.operand_32_bit) width = 32; - else width = 16; - } - void* dest = get_memory_from_mode(machine, mod_rm, width); - - if(dest == NULL) return UNABLE_GET_MEMORY; - - switch(get_reg(mod_rm)) - { - case 0: //TEST - { - uint32_t immediate; - if(width == 8) - { - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 1; - } - else if(width == 16) - { - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 2; - } - else if(width == 32) - { - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 4; - } - status = perform_test(machine, &immediate, dest, width); - break; - } - case 2: //NOT - if(width == 8) - *((uint8_t*)dest) = ~(*((uint8_t*)dest)); - else if(width == 16) - *((uint16_t*)dest) = ~(*((uint16_t*)dest)); - else if(width == 32) - *((uint32_t*)dest) = ~(*((uint32_t*)dest)); - break; - case 3: //NEG - status = perform_neg(machine, dest, width); - break; - case 4: //MUL - status = perform_multiplication(machine, dest, 0, width); - break; - case 5: //IMUL - status = perform_multiplication(machine, dest, 1, width); - break; - case 6: //DIV - status = perform_division(machine, dest, 0, width); - break; - case 7: - status = perform_division(machine, dest, 1, width); - break; - default: - return BAD_REG; - } - } - //PUSH Operations - //PUSH FLAGS - else if(opcode == 0x9c) - push_word(machine, machine->regs.w.flags); - //POP Operations - //POP FLAGS - else if(opcode == 0x9d) - machine->regs.w.flags = pop_word(machine); - //ROLS and RORS Group (Group 2) - else if(opcode >= 0xd0 && opcode <= 0xd3) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t arg = opcode <=0xd1 ? 1 : machine->regs.h.cl; - uint8_t width = 8; - if(opcode % 2){ - if(machine->internal_state.operand_32_bit) width = 32; - else width = 16; - } - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; - switch(get_reg(mod_rm)) - { - case 0: - status = perform_rol(machine, dest, arg, width); - break; - case 1: - status = perform_ror(machine, dest, arg, width); - break; - case 2: - status = perform_rcl(machine, dest, arg, width); - break; - case 3: - status = perform_rcr(machine, dest, arg, width); - break; - case 4: - status = perform_shl(machine, dest, arg, width); - break; - case 5: - status = perform_shr(machine, dest, arg, width); - break; - case 6: - return UNDEFINED_OPCODE; - case 7: - status = perform_sar(machine, dest, arg, width); - break; - } - } - //Jumps Group - //Short relative JMP - else if(opcode == 0xeb) - { - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - machine->IP.w.ip += offset; - } - //Near realtive JMP - else if(opcode == 0xe9) - { - int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - machine->IP.w.ip += offset; - } - //Far JMP - else if(opcode == 0xea) - { - int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->sregs.cs = newCS; - machine->IP.w.ip = newIP; - machine->internal_state.IPOffset = 0; - } - //LOOP Group - //LOOP LOOPE LOOPNE - else if(opcode >= 0xe0 && opcode <= 0xe2) - { - uint8_t jump = 0; - int8_t offset = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - if(machine->internal_state.operand_32_bit) machine->regs.d.ecx--; - else machine->regs.w.cx--; - - switch (opcode) - { - case 0xe0: - if(machine->internal_state.operand_32_bit){ - if(machine->regs.d.ecx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; - } - else - if(machine->regs.w.cx && !bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; - break; - case 0xe1: - if(machine->internal_state.operand_32_bit){ - if(machine->regs.d.ecx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; - } - else - if(machine->regs.w.cx && bit_get(machine->regs.w.flags, 1u << ZERO_FLAG_BIT)) jump = 1; - break; - case 0xe2: - if(machine->internal_state.operand_32_bit){ - if(machine->regs.d.ecx) jump = 1; - } - else - if(machine->regs.w.cx) jump = 1; - break; - default: - return UNKNOWN_ERROR; - } - - if(jump) - machine->IP.w.ip += offset; - } - //MOV Group - //MOV r8, imm8 - else if(opcode >= 0xb0 && opcode <= 0xb7) - { - uint8_t* reg = get_byte_register(machine, opcode & 0x7u); - uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - if(reg == NULL) return UNDEFINED_REGISTER; - machine->internal_state.IPOffset += 1; - *reg = imm; - } - //MOV r16, imm16 or r32, imm32 - else if(opcode >= 0xb8 && opcode <= 0xbf) - { - if(machine->internal_state.operand_32_bit) - { - uint32_t* reg = get_dword_register(machine, (opcode - 0xb8u) & 0x7u); - if(reg == NULL) return UNDEFINED_REGISTER; - uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 4; - *reg = imm; - } - else - { - uint16_t* reg = get_word_register(machine, (opcode - 0xb8u) & 0x7u); - if(reg == NULL) return UNDEFINED_REGISTER; - uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - *reg = imm; - } - } - //MOV AL/AX/EAX, moffs8/moffs16/moffs32 or MOV moffs8/moffs16/moffs32, AL/AX/EAX - else if(opcode >= 0xa0 && opcode <= 0xa3) - { - uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - uint16_t* segment = machine->internal_state.segment_reg_select == DEFAULT ? select_segment_register(machine, DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - switch (opcode) - { - case 0xa0: - machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); - break; - case 0xa1: - if(machine->internal_state.operand_32_bit) machine->regs.d.eax = read_dword_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); - else machine->regs.x.ax = read_word_from_pointer(machine->Memory, get_absolute_address(*segment, offset)); - break; - case 0xa2: - write_byte_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.h.al); - break; - case 0xa3: - if(machine->internal_state.operand_32_bit) write_dword_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.d.eax); - else write_word_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.x.ax); - break; - default: - return UNKNOWN_ERROR; - } - } - //MOV rm, imm - else if(opcode >= 0xc6 && opcode <= 0xc7) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - if(opcode == 0xc6) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); - if(mem == NULL) return UNABLE_GET_MEMORY; - *mem = immediate; - } - else - { - if(machine->internal_state.operand_32_bit) - { - uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 4; - uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); - if(mem == NULL) return UNABLE_GET_MEMORY; - *mem = immediate; - } - else - { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); - if(mem == NULL) return UNABLE_GET_MEMORY; - *mem = immediate; - } - } - } - //TEST GROUP - else if(opcode == 0xa8) - { - //Mod/RM - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t* reg = get_byte_register(machine, AL); - if(reg == NULL) return UNDEFINED_REGISTER; - uint8_t result = *reg & immediate; - bit_clear(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> 7u); //SIGN FLAG - } - else if(opcode == 0xa9) - { - //Mod/RM - uint32_t immediate; - uint8_t width = 16; - if(machine->internal_state.operand_32_bit) width = 32; - uint32_t result; - if(width == 16) - { - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - } - else if(width == 32) - { - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 4; - } - else return BAD_WIDTH; - - void* reg = get_variable_length_register(machine, AX, width); - if(reg == NULL) return UNDEFINED_REGISTER; - - if(width == 16) - result = *((uint16_t*) reg) & immediate; - else if(width == 32) - result = *((uint32_t*) reg) & immediate; - - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - } - //STRING GROUP - //MOVSB - else if(opcode==0xA4) - { - uint16_t* source_segment; - uint16_t* dest_segment = select_segment_register(machine, ES); - uint8_t* source; - uint8_t* dest; - if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); - else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; - - do{ - source = get_byte_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); - dest = get_byte_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); - *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -1 : 1; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -1 : 1; - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - } - //MOVSW or MOVSD - else if(opcode == 0xA5) - { - uint16_t* source_segment; - uint16_t* dest_segment = select_segment_register(machine, ES); - if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); - else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; - - if(machine->internal_state.operand_32_bit) - do{ - uint32_t* source = get_dword_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); - uint32_t* dest = get_dword_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); - *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -4 : 4; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -4 : 4; - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - else - do{ - uint16_t* source = get_word_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si)); - uint16_t* dest = get_word_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di)); - *dest = *source; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -2 : 2; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -2 : 2; - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - - } - //CMPSB or CMPSW or CMPSD - else if(opcode >= 0xA6 && opcode <= 0xA7) - { - uint16_t* source_segment; - uint16_t* dest_segment = select_segment_register(machine, ES); - void* source; - void* dest; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - uint64_t result; - uint8_t width = 8; - if(opcode == 0xA7){ - if(machine->internal_state.operand_32_bit) width=32; - else width = 16; - } - - if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); - else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; - - do{ - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); - dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); - } else return -1; - - result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - - if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); - } - //STOSB STOSW STOSD - else if(opcode >= 0xAA && opcode <= 0xAB) - { - uint16_t* segment = select_segment_register(machine, ES); - void* source; - void* dest; - uint8_t width = 8; - if(opcode == 0xA7) - { - if(machine->internal_state.operand_32_bit) width=32; - else width = 16; - } - - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; - - do{ - dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); - source = get_variable_length_register(machine, AL, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); - else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); - else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); - else return -1; - - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - } - //LOADB LOADW LOADD - else if(opcode >= 0xAC && opcode <= 0xAD) - { - uint16_t* segment; - void* source; - void* dest; - uint8_t width = 8; - if(opcode == 0xA7) - { - if(machine->internal_state.operand_32_bit) width=32; - else width = 16; - } - - if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); - else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) goto recalculate_ip; - - do{ - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); - dest = get_variable_length_register(machine, AL, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); - else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); - else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); - else return -1; - - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - } - //SCASB or SCASW or SCADD - else if(opcode >= 0xAE && opcode <= 0xAF) - { - uint16_t* source_segment = select_segment_register(machine, ES); - void* source; - void* dest; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - uint64_t result; - uint8_t width = 8; - if(opcode == 0xA7) - { - if(machine->internal_state.operand_32_bit) width=32; - else width = 16; - } - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) goto recalculate_ip; - - do{ - dest = get_variable_length_register(machine, AX, width); - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); - } else return -1; - - result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - - if(machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - else if(machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) break; - } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); - } //LOAD Operations group //LDS or LES else if(opcode >= 0xc4 && opcode <= 0xc5) @@ -718,37 +205,6 @@ int16_t parse_and_execute_instruction(v8086* machine) } } - //CONVERSIONS group - //CBW or CWDE - else if(opcode == 0x98) - { - if(machine->internal_state.operand_32_bit) - machine->regs.d.eax = ((int32_t)(machine->regs.w.ax)); - else - machine->regs.w.ax = ((int16_t)(machine->regs.h.al)); - } - //CWD or CDQ - else if(opcode == 0x99) - { - if(machine->internal_state.operand_32_bit){ - int64_t t = machine->regs.d.eax; - machine->regs.d.edx = ((uint64_t)t >> 32u); - } - else{ - int32_t t = machine->regs.w.ax; - machine->regs.w.dx = ((uint32_t)t >> 16u); - } - } - //Store and load flags group - //SAHF - else if(opcode == 0x9e){ - for(uint8_t i = 0; i < 8; i++) - if(i != 1 && i != 3 && i != 5) - bit_write(machine->regs.w.flags, 1u <regs.h.ah, 1u <regs.h.ah = machine->regs.w.flags & 0xFFu; //FLAG Setting and clearing Group //CMC else if(opcode == 0xf5) @@ -771,157 +227,6 @@ int16_t parse_and_execute_instruction(v8086* machine) //STD else if(opcode == 0xfd) bit_set(machine->regs.w.flags, 1u <Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - machine->regs.h.al = io_in_byte(immediate); - } - //IN AX/EAX, i8 - else if(opcode == 0xe5) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - if(machine->internal_state.operand_32_bit) - machine->regs.d.eax = io_in_long(immediate); - else - machine->regs.w.ax = io_in_word(immediate); - } - //IN AL, DX - else if(opcode == 0xec) - machine->regs.h.al = io_in_byte(machine->regs.x.dx); - //IN AX/EAX, DX - else if(opcode == 0xed) - { - if(machine->internal_state.operand_32_bit) - machine->regs.d.eax = io_in_long(machine->regs.x.dx); - else - machine->regs.w.ax = io_in_word(machine->regs.x.dx); - } - //OUT i8, AL - else if(opcode == 0xe6) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - io_out_byte(immediate, machine->regs.h.al); - } - //OUT i8, AX/EAX - else if(opcode == 0xe7) - { - uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - if(machine->internal_state.operand_32_bit) - io_out_long(immediate, machine->regs.d.eax); - else - io_out_long(immediate, machine->regs.w.ax); - } - //OUT DX, AL - else if(opcode == 0xee) - io_out_byte(machine->regs.w.dx, machine->regs.h.al); - //OUT DX, AX/EAX - else if(opcode == 0xef) - { - if(machine->internal_state.operand_32_bit) - io_out_long(machine->regs.w.dx, machine->regs.d.eax); - else - io_out_long(machine->regs.w.dx, machine->regs.w.ax); - } - //CALLs and RETs group - //NEAR relative CALL - else if(opcode == 0xe8) - { - int16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - - machine->IP.w.ip += machine->internal_state.IPOffset; - push_word(machine, machine->IP.w.ip); - machine->IP.w.ip += immediate; - machine->internal_state.IPOffset = 0; - } - //FAR CALL - else if(opcode == 0x9a) - { - int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP.w.ip + machine->internal_state.IPOffset); - machine->IP.w.ip = newIP; - machine->sregs.cs = newCS; - machine->internal_state.IPOffset = 0; - } - //Near RET - else if(opcode == 0xc3) - { - machine->IP.w.ip = pop_word(machine); - machine->internal_state.IPOffset = 0; - } - //Near RET, imm16 - else if(opcode == 0xc2) - { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - machine->IP.w.ip = pop_word(machine); - machine->regs.w.sp += immediate; - machine->internal_state.IPOffset = 0; - } - //Far RET - else if(opcode == 0xcb) - { - machine->IP.w.ip = pop_word(machine); - machine->sregs.cs = pop_word(machine); - machine->internal_state.IPOffset = 0; - } - //Far RET, imm16 - else if(opcode == 0xca) - { - uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 2; - machine->IP.w.ip = pop_word(machine); - machine->sregs.cs = pop_word(machine); - machine->regs.w.sp += immediate; - machine->internal_state.IPOffset = 0; - } - //Interrupts group - //INT, imm and INT 3 and INTO - else if(opcode >= 0xcc && opcode <= 0xce) - { - uint8_t interrupt_number = 3; - if(opcode == 0xcd) //INT, imm - { - interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - } - else if(opcode == 0xce) //INTO - { - if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) goto recalculate_ip; - interrupt_number = 4; - } - - int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4)); - int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4 + 2)); - - push_word(machine, machine->regs.w.flags); - push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP.w.ip); - - machine->IP.w.ip = newIP; - machine->sregs.cs = newCS; - - machine->internal_state.IPOffset = 0; - } - //IRET - else if(opcode == 0xcf) - { - machine->IP.w.ip = pop_word(machine); - machine->sregs.cs = pop_word(machine); - machine->regs.w.flags = pop_word(machine); - - machine->internal_state.IPOffset = 0; - } //MISC group //XLAT/XLATB else if(opcode == 0xd7) @@ -1009,11 +314,6 @@ int16_t parse_and_execute_instruction(v8086* machine) default: return UNDEFINED_OPCODE; } - } - //GROUP 1A - else if(opcode == 0x8f) - { - } else return UNDEFINED_OPCODE; recalculate_ip: machine->IP.w.ip += machine->internal_state.IPOffset; From 5147d9ca38ab79fbe07392065c3e4d0ee06c6c5a Mon Sep 17 00:00:00 2001 From: SzateX Date: Thu, 11 Jun 2020 23:06:50 +0200 Subject: [PATCH 059/165] Next refactored functions --- .../v8086/operations/arithmetic_operations.h | 2 + .../src/v8086/operations/io_operations.h | 2 + .../src/v8086/operations/misc_operations.c | 108 ++++++++++ .../src/v8086/operations/misc_operations.h | 6 + .../src/v8086/operations/mov_operations.c | 40 ++++ .../src/v8086/operations/mov_operations.h | 2 + os/kernel/src/v8086/operations/opcodes.c | 178 ++++++++++++++-- os/kernel/src/v8086/operations/opcodes.h | 33 ++- .../v8086/operations/procedure_operations.h | 2 + os/kernel/src/v8086/v8086.c | 195 +++++------------- 10 files changed, 411 insertions(+), 157 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.h b/os/kernel/src/v8086/operations/arithmetic_operations.h index fc9faa8c..bf02a0e8 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.h +++ b/os/kernel/src/v8086/operations/arithmetic_operations.h @@ -1,6 +1,8 @@ #ifndef V8086_ARITHMETIC_OPERATIONS_H #define V8086_ARITHMETIC_OPERATIONS_H +#include + int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry); diff --git a/os/kernel/src/v8086/operations/io_operations.h b/os/kernel/src/v8086/operations/io_operations.h index f22945dc..463d7ea6 100644 --- a/os/kernel/src/v8086/operations/io_operations.h +++ b/os/kernel/src/v8086/operations/io_operations.h @@ -6,5 +6,7 @@ int16_t perform_in_imm(v8086* machine, uint8_t width); int16_t perform_in_dx(v8086* machine, uint8_t width); +int16_t perform_out_imm(v8086* machine, uint8_t width); +int16_t perform_out_dx(v8086* machine, uint8_t width); #endif //MICROS_IO_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index 4e71d410..6a9293e4 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -1 +1,109 @@ +#include +#include +#include +#include #include "misc_operations.h" +#include "internal_funcs.h" +#include "arithmetic_operations.h" + +int16_t perform_group_4(v8086* machine) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 8; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(dest == NULL) return UNABLE_GET_MEMORY; + switch(get_reg(mod_rm)) + { + case 0: //INC rm8 + return perform_inc(machine, dest, width); + break; + case 1: //DEC rm8 + return perform_dec(machine, dest, width); + break; + default: + return UNDEFINED_OPCODE; + } +} + +int16_t perform_group_5(v8086* machine) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + + void* dest = get_memory_from_mode(machine, mod_rm, width); + if(dest == NULL) return UNABLE_GET_MEMORY; + switch(get_reg(mod_rm)) + { + case 0: //INC rm8 + return perform_inc(machine, dest, width); + case 1: //DEC rm8 + return perform_dec(machine, dest, width); + case 2: //Near absolute indirect call + machine->IP.w.ip += machine->internal_state.IPOffset; + push_word(machine, machine->IP.w.ip); + if(width == 16) + machine->IP.w.ip += *((uint16_t*) dest); + else return BAD_WIDTH; + machine->internal_state.IPOffset = 0; + return OK; + case 3: // Far absolute indirect call + machine->IP.w.ip += machine->internal_state.IPOffset; + push_word(machine, machine->sregs.cs); + push_word(machine, machine->IP.w.ip); + machine->IP.w.ip = *((uint16_t*) dest); + machine->sregs.cs = *(((uint16_t*)dest)+1); + machine->internal_state.IPOffset = 0; + return OK; + case 4: //Near absolute indirect jmp + if(width == 16) + machine->IP.w.ip += *((uint16_t*) dest); + else return BAD_WIDTH; + machine->internal_state.IPOffset = 0; + return OK; + case 5: //Far absolute indirect jmp + machine->IP.w.ip = *((uint16_t*) dest); + machine->sregs.cs = *(((uint16_t*)dest)+1); + machine->internal_state.IPOffset = 0; + return OK; + case 6: + if(width == 16) push_word(machine, *((uint16_t*)dest)); + else push_dword(machine, *((uint32_t*)dest)); + return OK; + default: + return UNDEFINED_OPCODE; + } + return UNKNOWN_ERROR; +} + +int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode) +{ + //FLAG Setting and clearing Group + //CMC + if(opcode == 0xf5) + bit_flip(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u < + +int16_t perform_group_4(v8086* machine); +int16_t perform_group_5(v8086* machine); +int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode); + #endif //MICROS_MISC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index 251b0263..d6ac5fd7 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -206,4 +206,44 @@ int16_t load_flags(v8086* machine) { machine->regs.h.ah = machine->regs.w.flags & 0xFFu; return OK; +} + +int16_t perform_lds_les(v8086* machine, uint8_t les_op) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + uint16_t* segment_register; + if(les_op) segment_register = select_segment_register(machine, ES); + else segment_register = select_segment_register(machine, DS); + if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; + uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); + if(source == NULL) return UNABLE_GET_MEMORY; + + if(machine->internal_state.operand_32_bit) + { + uint32_t* dest = get_dword_register(machine, get_reg(mod_rm)); + *dest = *((uint32_t*) source); + *segment_register = *(source+2); + } + else + { + uint16_t* dest = get_word_register(machine, get_reg(mod_rm)); + *dest = *source; + *segment_register = *(source+1); + } + return OK; +} + +int16_t perform_xlat(v8086* machine) +{ + uint8_t tempAL = machine->regs.h.al; + uint16_t* segment; + if(machine->internal_state.segment_reg_select != DEFAULT) + segment = select_segment_register(machine, machine->internal_state.segment_reg_select); + else + segment = select_segment_register(machine, DS); + if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/mov_operations.h b/os/kernel/src/v8086/operations/mov_operations.h index f5a206d4..2f8c0da8 100644 --- a/os/kernel/src/v8086/operations/mov_operations.h +++ b/os/kernel/src/v8086/operations/mov_operations.h @@ -13,5 +13,7 @@ int16_t convert_byte_to_word(v8086* machine); int16_t convert_word_to_double(v8086* machine); int16_t store_flags(v8086* machine); int16_t load_flags(v8086* machine); +int16_t perform_lds_les(v8086* machine, uint8_t les_op); +int16_t perform_xlat(v8086* machine); #endif //MICROS_MOV_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 4f241e2f..ddcb4d30 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -296,26 +296,174 @@ OPCODE_PROTO(scasw) { return perform_scas(machine, machine->internal_state.operand_32_bit ? 32: 16); } + OPCODE_PROTO(mov_gpr_imm) { return perform_mov_gpr_imm(machine, opcode); } +OPCODE_PROTO(retn) +{ + return near_ret(machine); +} + +OPCODE_PROTO(retn_imm) +{ + return near_ret_imm(machine); +} + +OPCODE_PROTO(les) +{ + return perform_lds_les(machine, 1); +} + +OPCODE_PROTO(lds) +{ + return perform_lds_les(machine, 0); +} + +OPCODE_PROTO(mov_rm_imm) +{ + return perform_mov_rm_imm(machine, opcode); +} + +OPCODE_PROTO(retf_imm) +{ + return far_ret_imm(machine); +} + +OPCODE_PROTO(retf) +{ + return far_ret(machine); +} -/* - * //INT, imm and INT 3 and INTO - else if(opcode >= 0xcc && opcode <= 0xce) +OPCODE_PROTO(interrupt) +{ + uint8_t interrupt_number = 3; + if(opcode == 0xcd) //INT, imm + { + interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } + else if(opcode == 0xce) //INTO { - uint8_t interrupt_number = 3; - if(opcode == 0xcd) //INT, imm - { - interrupt_number = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - } - else if(opcode == 0xce) //INTO - { - if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) goto recalculate_ip; - interrupt_number = 4; - } + if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) return OK; + interrupt_number = 4; } - */ \ No newline at end of file + + return perform_interrupt(machine, interrupt_number); +} + +OPCODE_PROTO(iret) +{ + return perform_iret(machine); +} + +OPCODE_PROTO(group_2) +{ + return execute_group_2(machine, opcode); +} + +OPCODE_PROTO(aam) +{ + return adjust_after_mul_div(machine, 0); +} + +OPCODE_PROTO(aad) +{ + return adjust_after_mul_div(machine, 1); +} + +OPCODE_PROTO(xlat) +{ + return perform_xlat(machine); +} + +OPCODE_PROTO(loop) +{ + return perform_loop_loopne(machine, opcode); +} + +OPCODE_PROTO(jrcxz) +{ + return jump_short_relative_on_condition(machine, opcode); +} + +OPCODE_PROTO(inb_imm) +{ + return perform_in_imm(machine, 8); +} + +OPCODE_PROTO(inw_imm) +{ + return perform_in_imm(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(outb_imm) +{ + return perform_out_imm(machine, 8); +} + +OPCODE_PROTO(outw_imm) +{ + return perform_in_imm(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(call_near) +{ + return near_relative_call(machine); +} + +OPCODE_PROTO(jmp_near) +{ + return jump_near_relative(machine); +} + +OPCODE_PROTO(jmp_far) +{ + return jump_far(machine); +} + +OPCODE_PROTO(jmp_short) +{ + return jump_short_relative(machine); +} + +OPCODE_PROTO(inb_dx) +{ + return perform_in_dx(machine, 8); +} + +OPCODE_PROTO(inw_dx) +{ + return perform_in_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(outb_dx) +{ + return perform_out_dx(machine, 8); +} + +OPCODE_PROTO(outw_dx) +{ + return perform_in_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(set_flag) +{ + return setting_and_clearing_flags(machine, opcode); +} + +OPCODE_PROTO(group_3) +{ + return execute_group_3(machine, opcode); +} + +OPCODE_PROTO(group_4) +{ + return perform_group_4(machine); +} +OPCODE_PROTO(group_5) +{ + return perform_group_5(machine); +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 44c75588..4f828938 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -61,6 +61,35 @@ OPCODE_PROTO(lodsw); OPCODE_PROTO(scasb); OPCODE_PROTO(scasw); OPCODE_PROTO(mov_gpr_imm); - - +OPCODE_PROTO(retn); +OPCODE_PROTO(retn_imm); +OPCODE_PROTO(les); +OPCODE_PROTO(lds); +OPCODE_PROTO(mov_rm_imm); +OPCODE_PROTO(retf_imm); +OPCODE_PROTO(retf); +OPCODE_PROTO(interrupt); +OPCODE_PROTO(iret); +OPCODE_PROTO(group_2); +OPCODE_PROTO(aam); +OPCODE_PROTO(aad); +OPCODE_PROTO(xlat); +OPCODE_PROTO(loop); +OPCODE_PROTO(jrcxz); +OPCODE_PROTO(inb_imm); +OPCODE_PROTO(inw_imm); +OPCODE_PROTO(outb_imm); +OPCODE_PROTO(outw_imm); +OPCODE_PROTO(call_near); +OPCODE_PROTO(jmp_near); +OPCODE_PROTO(jmp_far); +OPCODE_PROTO(jmp_short); +OPCODE_PROTO(inb_dx); +OPCODE_PROTO(inw_dx); +OPCODE_PROTO(outb_dx); +OPCODE_PROTO(outw_dx); +OPCODE_PROTO(set_flag); +OPCODE_PROTO(group_3); +OPCODE_PROTO(group_4); +OPCODE_PROTO(group_5); #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/procedure_operations.h b/os/kernel/src/v8086/operations/procedure_operations.h index b3a15573..d143c228 100644 --- a/os/kernel/src/v8086/operations/procedure_operations.h +++ b/os/kernel/src/v8086/operations/procedure_operations.h @@ -11,5 +11,7 @@ int16_t near_ret(v8086* machine); int16_t near_ret_imm(v8086* machine); int16_t far_ret(v8086* machine); int16_t far_ret_imm(v8086* machine); +int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number); +int16_t perform_iret(v8086* machine); #endif //MICROS_PROCEDURE_OPERATIONS_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index abb51b6b..2485204c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -80,6 +80,56 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0xaeu, scasb); ASSIGN_OPCODE(0xafu, scasw); GROUP_OF_OPCODES(0xb0u, 0xbfu, mov_gpr_imm); + //NOT DEFINED IN 8086 processor + ASSIGN_NULL(0xc0u); + ASSIGN_NULL(0xc1u); + ASSIGN_OPCODE(0xc2u, retn); + ASSIGN_OPCODE(0xc3u, retn_imm); + ASSIGN_OPCODE(0xc4u, les); + ASSIGN_OPCODE(0xc5u, lds); + GROUP_OF_OPCODES(0xc6u, 0xc7u, mov_rm_imm); + //NOT DEFINED IN 8086 processor + ASSIGN_NULL(0xc8u); + ASSIGN_NULL(0xc9u); + GROUP_OF_OPCODES(0xccu, 0xceu, interrupt); + ASSIGN_OPCODE(0xcfu, iret); + GROUP_OF_OPCODES(0xd0u, 0xd3u, group_2); + ASSIGN_OPCODE(0xd4u, aam); + ASSIGN_OPCODE(0xd5u, aad); + //NOT DEFINED IN 8086 processor + ASSIGN_NULL(0xd6u); + ASSIGN_OPCODE(0xd7u, xlat); + //NO COPROCESSOR + for(uint8_t i = 0xd8u; i <= 0xdfu; ++i) ASSIGN_NULL(i); + GROUP_OF_OPCODES(0xe0u, 0xe2u, loop); + ASSIGN_OPCODE(0xe3u, jrcxz); + ASSIGN_OPCODE(0xe4u, inb_imm); + ASSIGN_OPCODE(0xe5u, inw_imm); + ASSIGN_OPCODE(0xe6u, outb_imm); + ASSIGN_OPCODE(0xe7u, outw_imm); + ASSIGN_OPCODE(0xe8u, call_near); + ASSIGN_OPCODE(0xe9u, jmp_near); + ASSIGN_OPCODE(0xeau, jmp_far); + ASSIGN_OPCODE(0xebu, jmp_short); + ASSIGN_OPCODE(0xe4u, inb_dx); + ASSIGN_OPCODE(0xe5u, inw_dx); + ASSIGN_OPCODE(0xe6u, outb_dx); + ASSIGN_OPCODE(0xe7u, outw_dx); + //RESERVED FOR LOCK PREFIX + ASSIGN_NULL(0xf0u); + //NOT DEFINED IN 8086 + ASSIGN_NULL(0xf1u); + //RESERVED FOR REPNE PREFIX + ASSIGN_NULL(0xf2u); + //RESERVED FOR REP PREFIX + ASSIGN_NULL(0xf3u); + //NO EXTERNAL INTERRUPTS, HLT NOT WORKING + ASSIGN_NULL(0xf4u); + ASSIGN_OPCODE(0xf5u, set_flag); + GROUP_OF_OPCODES(0xf6u, 0xf7u, group_3); + GROUP_OF_OPCODES(0xf8u, 0xfdu, set_flag); + ASSIGN_OPCODE(0xfeu, group_4); + ASSIGN_OPCODE(0xffu, group_5); } v8086* v8086_create_machine() @@ -177,146 +227,11 @@ int16_t parse_and_execute_instruction(v8086* machine) goto decode; //ommit prefix, contniue parsinf opcode; } - //LOAD Operations group - //LDS or LES - else if(opcode >= 0xc4 && opcode <= 0xc5) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - - uint16_t* segment_register; - if(opcode == 0xc4) segment_register = select_segment_register(machine, ES); - else segment_register = select_segment_register(machine, DS); - if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; - uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); - if(source == NULL) return UNABLE_GET_MEMORY; - - if(machine->internal_state.operand_32_bit) - { - uint32_t* dest = get_dword_register(machine, get_reg(mod_rm)); - *dest = *((uint32_t*) source); - *segment_register = *(source+2); - } - else - { - uint16_t* dest = get_word_register(machine, get_reg(mod_rm)); - *dest = *source; - *segment_register = *(source+1); - } - - } - //FLAG Setting and clearing Group - //CMC - else if(opcode == 0xf5) - bit_flip(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.h.al; - uint16_t* segment; - if(machine->internal_state.segment_reg_select != DEFAULT) - segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - else - segment = select_segment_register(machine, DS); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); - } - //GROUP 4 - else if(opcode == 0xfe) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t width = 8; - - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; - switch(get_reg(mod_rm)) - { - case 0: //INC rm8 - status = perform_inc(machine, dest, width); - break; - case 1: //DEC rm8 - status = perform_dec(machine, dest, width); - break; - default: - return UNDEFINED_OPCODE; - } - } - //GROUP 5 - else if(opcode == 0xff) - { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; - uint8_t width = 16; - if(machine->internal_state.operand_32_bit) width = 32; - - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; - switch(get_reg(mod_rm)) - { - case 0: //INC rm8 - status = perform_inc(machine, dest, width); - break; - case 1: //DEC rm8 - status = perform_dec(machine, dest, width); - break; - case 2: //Near absolute indirect call - machine->IP.w.ip += machine->internal_state.IPOffset; - push_word(machine, machine->IP.w.ip); - if(width == 16) - machine->IP.w.ip += *((uint16_t*) dest); - else return BAD_WIDTH; - machine->internal_state.IPOffset = 0; - break; - case 3: // Far absolute indirect call - machine->IP.w.ip += machine->internal_state.IPOffset; - push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP.w.ip); - machine->IP.w.ip = *((uint16_t*) dest); - machine->sregs.cs = *(((uint16_t*)dest)+1); - machine->internal_state.IPOffset = 0; - break; - case 4: //Near absolute indirect jmp - if(width == 16) - machine->IP.w.ip += *((uint16_t*) dest); - else return BAD_WIDTH; - machine->internal_state.IPOffset = 0; - break; - case 5: //Far absolute indirect jmp - machine->IP.w.ip = *((uint16_t*) dest); - machine->sregs.cs = *(((uint16_t*)dest)+1); - machine->internal_state.IPOffset = 0; - break; - case 6: - if(width == 16) push_word(machine, *((uint16_t*)dest)); - else if(width == 32) push_dword(machine, *((uint32_t*)dest)); - else return BAD_WIDTH; - break; - default: - return UNDEFINED_OPCODE; - } - } - else return UNDEFINED_OPCODE; - recalculate_ip: machine->IP.w.ip += machine->internal_state.IPOffset; + if(machine->operations[opcode] != NULL) + status = machine->operations[opcode](machine, opcode); + else + return UNDEFINED_OPCODE; + machine->IP.w.ip += machine->internal_state.IPOffset; return status; } \ No newline at end of file From e5d42e58cc2f14153b4518c68ffc8d9b5a56c18d Mon Sep 17 00:00:00 2001 From: SzateX Date: Tue, 14 Jul 2020 00:20:27 +0200 Subject: [PATCH 060/165] Added BOUND instruction --- .../src/v8086/operations/misc_operations.c | 29 ++++++++++ .../src/v8086/operations/misc_operations.h | 1 + os/kernel/src/v8086/operations/opcodes.c | 17 ++++++ os/kernel/src/v8086/operations/opcodes.h | 6 ++ .../src/v8086/operations/stack_operations.c | 57 +++++++++++++++++++ .../src/v8086/operations/stack_operations.h | 3 + os/kernel/src/v8086/v8086.c | 8 +++ os/kernel/src/v8086/v8086.h | 1 + 8 files changed, 122 insertions(+) diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index 6a9293e4..38be4a6c 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -106,4 +106,33 @@ int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode) else return UNKNOWN_ERROR; return OK; +} + +int16_t check_bounds(v8086* machine) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 16; + if(machine->internal_state.operand_32_bit) width = 32; + + void* index = get_variable_length_register(machine, get_reg(mod_rm), width); + void* bounds = get_memory_from_mode(machine, mod_rm, width); + + if(width==16) + { + int16_t* i = (int16_t*) index; + int16_t* lb = (int16_t*) bounds; + int16_t* ub = ((int16_t*) bounds + 1); + + if((*i < *lb) || (*i > *ub)) return BOUND_ERROR; + } + else + { + int32_t* i = (int32_t*) index; + int32_t* lb = (int32_t*) bounds; + int32_t* ub = ((int32_t*) bounds + 1); + + if((*i < *lb) || (*i > *ub)) return BOUND_ERROR; + } + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/misc_operations.h b/os/kernel/src/v8086/operations/misc_operations.h index 3ef4a0fc..b1f289a3 100644 --- a/os/kernel/src/v8086/operations/misc_operations.h +++ b/os/kernel/src/v8086/operations/misc_operations.h @@ -6,5 +6,6 @@ int16_t perform_group_4(v8086* machine); int16_t perform_group_5(v8086* machine); int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode); +int16_t check_bounds(v8086* machine); #endif //MICROS_MISC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index ddcb4d30..66062e1d 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -466,4 +466,21 @@ OPCODE_PROTO(group_4) OPCODE_PROTO(group_5) { return perform_group_5(machine); +} + +//386 PROTOS + +OPCODE_PROTO(push_all) +{ + return push_all(machine); +} + +OPCODE_PROTO(pop_all) +{ + return pop_all(machine); +} + +OPCODE_PROTO(bound) +{ + return check_bounds(machine); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 4f828938..e273a302 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -92,4 +92,10 @@ OPCODE_PROTO(set_flag); OPCODE_PROTO(group_3); OPCODE_PROTO(group_4); OPCODE_PROTO(group_5); + +//386 PROTOS +OPCODE_PROTO(push_all); +OPCODE_PROTO(pop_all); +OPCODE_PROTO(bound); + #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index e2cc14e4..6531183f 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -42,4 +42,61 @@ uint16_t pop_rm(v8086* machine) else *((uint32_t*)dest) = pop_dword(machine); return OK; +} + +uint16_t push_all(v8086* machine) +{ + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + uint32_t temp_sp = width == 16 ? machine->regs.w.sp : machine->regs.d.esp; + if(width == 16) + { + push_word(machine, machine->regs.x.ax); + push_word(machine, machine->regs.x.cx); + push_word(machine, machine->regs.x.dx); + push_word(machine, machine->regs.x.bx); + push_word(machine, temp_sp); + push_word(machine, machine->regs.x.bp); + push_word(machine, machine->regs.x.si); + push_word(machine, machine->regs.x.di); + } else + { + push_dword(machine, machine->regs.d.eax); + push_dword(machine, machine->regs.d.ecx); + push_dword(machine, machine->regs.d.edx); + push_dword(machine, machine->regs.d.ebx); + push_dword(machine, temp_sp); + push_dword(machine, machine->regs.d.ebp); + push_dword(machine, machine->regs.d.esi); + push_dword(machine, machine->regs.d.edi); + } + return OK; +} + +uint16_t pop_all(v8086* machine) +{ + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + if(width == 16) + { + machine->regs.x.di = pop_word(machine); + machine->regs.x.si = pop_word(machine); + machine->regs.x.bp = pop_word(machine); + //Throw away sp; + pop_word(machine); + machine->regs.x.bx = pop_word(machine); + machine->regs.x.dx = pop_word(machine); + machine->regs.x.cx = pop_word(machine); + machine->regs.x.ax = pop_word(machine); + } else + { + machine->regs.d.edi = pop_dword(machine); + machine->regs.d.esi = pop_dword(machine); + machine->regs.d.ebp = pop_dword(machine); + //Throw away esp; + pop_dword(machine); + machine->regs.d.ebx = pop_dword(machine); + machine->regs.d.edx = pop_dword(machine); + machine->regs.d.ecx = pop_dword(machine); + machine->regs.d.eax = pop_dword(machine); + } + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/stack_operations.h b/os/kernel/src/v8086/operations/stack_operations.h index 7ec8bfc2..5d76031c 100644 --- a/os/kernel/src/v8086/operations/stack_operations.h +++ b/os/kernel/src/v8086/operations/stack_operations.h @@ -6,5 +6,8 @@ uint16_t push_gpr(v8086* machine, uint8_t opcode); uint16_t pop_gpr(v8086* machine, uint8_t opcode); uint16_t pop_rm(v8086* machine); +uint16_t push_all(v8086* machine); +uint16_t pop_all(v8086* machine); + #endif //MICROS_STACK_OPERATIONS_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 2485204c..b225461e 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -132,6 +132,14 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0xffu, group_5); } +void v8086_set_386_instruction_set(v8086* machine) +{ + v8086_set_8086_instruction_set(machine); + ASSIGN_OPCODE(0x60u, push_all); + ASSIGN_OPCODE(0x61u, pop_all); + ASSIGN_OPCODE(0x62u, bound); +} + v8086* v8086_create_machine() { v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 6a79bd28..78189ddd 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -50,6 +50,7 @@ typedef enum _machine_status { UNDEFINED_RECALCULATED_OPCODE = -12, BAD_INT_NUMBER = -13, RELATIVE_JMP_OVERFLOW = -14, + BOUND_ERROR = -15, UNKNOWN_ERROR = -69 } machine_status; From b692b960a24d1481d9de6ea4e5f0de2fc37780f6 Mon Sep 17 00:00:00 2001 From: SzateX Date: Fri, 24 Jul 2020 01:10:15 +0200 Subject: [PATCH 061/165] Added Instructions from 0x60 to 0x6f opcodes. Corrected mistake in STOS and simmilar functions. Only needed to implement ENTER and LEAVE... and cook potatoes for dinner. I'm going now to drink beer. Cheers! --- .../v8086/operations/arithmetic_operations.c | 86 +++++++++++++++++++ .../v8086/operations/arithmetic_operations.h | 1 + .../src/v8086/operations/io_operations.c | 57 ++++++++++++ .../src/v8086/operations/io_operations.h | 2 + os/kernel/src/v8086/operations/opcodes.c | 55 ++++++++++++ os/kernel/src/v8086/operations/opcodes.h | 8 ++ .../src/v8086/operations/stack_operations.c | 26 ++++++ .../src/v8086/operations/stack_operations.h | 1 + .../src/v8086/operations/string_operations.c | 72 +++++++++++++--- os/kernel/src/v8086/stack.h | 12 +++ os/kernel/src/v8086/v8086.c | 21 +++++ 11 files changed, 327 insertions(+), 14 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 23fad1c9..2da0580c 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -366,6 +366,92 @@ int16_t perform_multiplication(v8086* machine, void* source, uint8_t signed_mul, return OK; } +int16_t perform_multiplication_3_byte(v8086* machine, void* dest, void* source, void* imm, uint8_t signed_mul, uint8_t width, uint8_t second_width) +{ + uint16_t temp_flags; + if(signed_mul) { + if (width == 16) { + if (second_width == 8) { + int8_t a_imm = *((int8_t*) imm); + __asm__ __volatile__( + "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else if(second_width == 16) + { + int16_t a_imm = *((int16_t*) imm); + __asm__ __volatile__( + "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else return BAD_WIDTH; + } + else if(width == 32) { + if (second_width == 8) { + int8_t a_imm = *((int8_t*) imm); + __asm__ __volatile__( + "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else if(second_width == 32) + { + int32_t a_imm = *((int32_t*) imm); + __asm__ __volatile__( + "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else return BAD_WIDTH; + } + else return BAD_WIDTH; + } + else{ + if (width == 16) { + if (second_width == 8) { + uint8_t a_imm = *((uint8_t*) imm); + __asm__ __volatile__( + "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else if(second_width == 16) + { + uint16_t a_imm = *((uint16_t*) imm); + __asm__ __volatile__( + "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else return BAD_WIDTH; + } + else if(width == 32) { + if (second_width == 8) { + uint8_t a_imm = *((uint8_t*) imm); + __asm__ __volatile__( + "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else if(second_width == 32) + { + uint32_t a_imm = *((uint32_t*) imm); + __asm__ __volatile__( + "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" + : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) + ); + } + else return BAD_WIDTH; + } + else return BAD_WIDTH; + } + bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u < #include +#include #include "io_operations.h" int16_t perform_in_imm(v8086* machine, uint8_t width) @@ -43,5 +44,61 @@ int16_t perform_out_dx(v8086* machine, uint8_t width) else if(width == 32) io_out_long(machine->regs.x.dx, machine->regs.d.eax); else return BAD_WIDTH; + return OK; +} + +int16_t perform_ins_dx(v8086* machine, uint8_t width) +{ + uint16_t* dest_segment = select_segment_register(machine, ES); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + + do{ + void* dest = NULL; + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.esi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.si), width); + + if(width == 8) *((uint8_t*)dest) = io_in_byte(machine->regs.x.dx); + else if(width == 16) *((uint16_t*)dest) = io_in_word(machine->regs.x.dx); + else if(width == 32) *((uint32_t*)dest)= io_in_long(machine->regs.x.dx); + else return BAD_WIDTH; + int8_t offset = width / 8; + if(machine->internal_state.address_32_bit) + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + else + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + + return OK; +} + +int16_t perform_outs_dx(v8086* machine, uint8_t width) +{ + uint16_t* dest_segment = select_segment_register(machine, ES); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + + do{ + void* dest = NULL; + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.esi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.si), width); + + if(width == 8) io_out_byte(machine->regs.x.dx, *((uint8_t*)dest)); + else if(width == 16) io_out_word(machine->regs.x.dx, *((uint16_t*)dest)); + else if(width == 32) io_out_long(machine->regs.x.dx, *((uint32_t*)dest)); + else return BAD_WIDTH; + int8_t offset = width / 8; + if(machine->internal_state.address_32_bit) + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + else + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/io_operations.h b/os/kernel/src/v8086/operations/io_operations.h index 463d7ea6..8aadc6aa 100644 --- a/os/kernel/src/v8086/operations/io_operations.h +++ b/os/kernel/src/v8086/operations/io_operations.h @@ -8,5 +8,7 @@ int16_t perform_in_imm(v8086* machine, uint8_t width); int16_t perform_in_dx(v8086* machine, uint8_t width); int16_t perform_out_imm(v8086* machine, uint8_t width); int16_t perform_out_dx(v8086* machine, uint8_t width); +int16_t perform_ins_dx(v8086* machine, uint8_t width); +int16_t perform_outs_dx(v8086* machine, uint8_t width); #endif //MICROS_IO_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 66062e1d..8456b3ed 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "opcodes.h" #include "arithmetic_operations.h" #include "ascii_adjustments_operations.h" @@ -483,4 +484,58 @@ OPCODE_PROTO(pop_all) OPCODE_PROTO(bound) { return check_bounds(machine); +} + +OPCODE_PROTO(push_imm16_32) +{ + return push_immediate(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(push_imm8) +{ + return push_immediate(machine, 8); +} + +OPCODE_PROTO(imul_reg_reg_imm) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + void* mem_or_reg = get_memory_from_mode(machine, mod_rm, width); + void* reg = get_variable_length_register(machine, get_reg(mod_rm), width); + void* imm = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); + machine->internal_state.IPOffset += width/8; + + return perform_multiplication_3_byte(machine, reg, mem_or_reg, imm, 1, width, width); +} + +OPCODE_PROTO(imul_reg_reg_imm8) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + void* mem_or_reg = get_memory_from_mode(machine, mod_rm, width); + void* reg = get_variable_length_register(machine, get_reg(mod_rm), width); + uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + return perform_multiplication_3_byte(machine, reg, mem_or_reg, &imm, 1, width, 8); +} + +OPCODE_PROTO(ins8){ + return perform_ins_dx(machine, 8); +} + +OPCODE_PROTO(ins) +{ + return perform_ins_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(outs8){ + return perform_outs_dx(machine, 8); +} + +OPCODE_PROTO(outs) +{ + return perform_outs_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index e273a302..a5ab1d5c 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -97,5 +97,13 @@ OPCODE_PROTO(group_5); OPCODE_PROTO(push_all); OPCODE_PROTO(pop_all); OPCODE_PROTO(bound); +OPCODE_PROTO(push_imm16_32); +OPCODE_PROTO(push_imm8); +OPCODE_PROTO(imul_reg_reg_imm); +OPCODE_PROTO(imul_reg_reg_imm8); +OPCODE_PROTO(ins8); +OPCODE_PROTO(ins); +OPCODE_PROTO(outs8); +OPCODE_PROTO(outs); #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index 6531183f..0d66c034 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -99,4 +99,30 @@ uint16_t pop_all(v8086* machine) machine->regs.d.eax = pop_dword(machine); } return OK; +} + +uint16_t push_immediate(v8086* machine, uint8_t width) +{ + if(width == 8) + { + uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + push_byte(machine, imm); + return OK; + } + if(width == 16) + { + uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + push_word(machine, imm); + return OK; + } + if(width == 32) + { + uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + push_dword(machine, imm); + return OK; + } + return BAD_WIDTH; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/stack_operations.h b/os/kernel/src/v8086/operations/stack_operations.h index 5d76031c..56cc391c 100644 --- a/os/kernel/src/v8086/operations/stack_operations.h +++ b/os/kernel/src/v8086/operations/stack_operations.h @@ -8,6 +8,7 @@ uint16_t pop_gpr(v8086* machine, uint8_t opcode); uint16_t pop_rm(v8086* machine); uint16_t push_all(v8086* machine); uint16_t pop_all(v8086* machine); +uint16_t push_immediate(v8086* machine, uint8_t width); #endif //MICROS_STACK_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index 0e833328..ae1638f6 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -15,8 +15,16 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; do{ - void* source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); - void* dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + void* source = NULL; + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.esi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + void* dest = NULL; + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); if(width == 8) *((uint8_t*)dest) = *((uint8_t*) source); else if(width == 16) @@ -26,8 +34,14 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { else return BAD_WIDTH; int8_t offset = width / 8; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + if(machine->internal_state.address_32_bit){ + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } + else { + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); return OK; @@ -43,7 +57,10 @@ uint16_t perform_stos(v8086* machine, uint8_t width) if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; do{ - dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); source = get_variable_length_register(machine, AL, width); if(source == NULL) return UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); @@ -51,7 +68,10 @@ uint16_t perform_stos(v8086* machine, uint8_t width) else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); else return -1; - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + if(machine->internal_state.address_32_bit) + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + else + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); return OK; @@ -75,8 +95,14 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) return OK; do{ - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); - dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.esi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); @@ -98,8 +124,14 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) bit_write(machine->regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + if(machine->internal_state.address_32_bit){ + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + } + else { + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + } if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; @@ -121,7 +153,10 @@ uint16_t perform_lods(v8086* machine, uint8_t width) if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; do{ - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.esi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); dest = get_variable_length_register(machine, AL, width); if(dest == NULL) return UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); @@ -129,7 +164,10 @@ uint16_t perform_lods(v8086* machine, uint8_t width) else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); else return BAD_WIDTH; - machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + if(machine->internal_state.address_32_bit) + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + else + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); return OK; } @@ -149,7 +187,10 @@ uint16_t perform_scas(v8086* machine, uint8_t width) do{ dest = get_variable_length_register(machine, AX, width); - source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.edi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); if(dest == NULL) return UNDEFINED_REGISTER; if(width == 8){ dest_before = *((uint8_t*)dest); @@ -172,7 +213,10 @@ uint16_t perform_scas(v8086* machine, uint8_t width) bit_write(machine->regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + if(machine->internal_state.address_32_bit) + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + else + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; diff --git a/os/kernel/src/v8086/stack.h b/os/kernel/src/v8086/stack.h index 16e1325b..ddfa3fe8 100644 --- a/os/kernel/src/v8086/stack.h +++ b/os/kernel/src/v8086/stack.h @@ -4,6 +4,11 @@ #include "v8086.h" #include "memory_operations.h" +static inline void push_byte(v8086* machine, uint8_t value) +{ + write_byte_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 1), value); +} + static inline void push_word(v8086* machine, uint16_t value) { write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); @@ -14,6 +19,13 @@ static inline void push_dword(v8086* machine, uint32_t value) write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 4), value); } +static inline uint8_t pop_byte(v8086* machine) +{ + uint8_t v = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + machine->regs.w.sp += 1; + return v; +} + static inline uint16_t pop_word(v8086* machine) { uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index b225461e..190361c6 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -138,6 +138,20 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_OPCODE(0x60u, push_all); ASSIGN_OPCODE(0x61u, pop_all); ASSIGN_OPCODE(0x62u, bound); + //ARPL Not working in REAL MODE + ASSIGN_NULL(0x63u); + //RESERVED FOR SEG=FS + ASSIGN_NULL(0x64u); + //RESERVED FOR SEG=GS + ASSIGN_NULL(0x65u); + ASSIGN_OPCODE(0x68u, push_imm16_32); + ASSIGN_OPCODE(0x69u, imul_reg_reg_imm); + ASSIGN_OPCODE(0x6au, push_imm8); + ASSIGN_OPCODE(0x6bu, imul_reg_reg_imm8); + ASSIGN_OPCODE(0x6cu, ins8); + ASSIGN_OPCODE(0x6du, ins); + ASSIGN_OPCODE(0x6eu, outs8); + ASSIGN_OPCODE(0x6fu, outs); } v8086* v8086_create_machine() @@ -180,6 +194,7 @@ int16_t parse_and_execute_instruction(v8086* machine) { machine->internal_state.IPOffset = 0; machine->internal_state.operand_32_bit = 0; + machine->internal_state.address_32_bit = 0; machine->internal_state.segment_reg_select = DEFAULT; machine->internal_state.rep_prefix = NONE; @@ -217,6 +232,12 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.operand_32_bit = 1; goto decode; //continue parsing opcode; } + //Address Szie Prefix + else if(opcode == 0x67) + { + machine->internal_state.address_32_bit = 1; + goto decode; + } //REPNE Prefix else if(opcode == 0xF2) { From e8326655c4c1e70c2ac23155a928c5f38c989cc9 Mon Sep 17 00:00:00 2001 From: Tearth Date: Fri, 31 Jul 2020 21:20:57 +0200 Subject: [PATCH 062/165] Add syscall which creates a new thread --- library/src/micros/micros_process.c | 16 ++++++++++++++++ library/src/micros/micros_process.h | 10 ++++++++++ .../process/syscalls/handlers/process_calls.c | 11 +++++++++++ .../process/syscalls/handlers/process_calls.h | 1 + .../src/process/syscalls/syscalls_manager.c | 1 + 5 files changed, 39 insertions(+) diff --git a/library/src/micros/micros_process.c b/library/src/micros/micros_process.c index 89bb98db..27a5e472 100644 --- a/library/src/micros/micros_process.c +++ b/library/src/micros/micros_process.c @@ -53,4 +53,20 @@ void micros_process_finish_signal_handler(micros_signal_params *old_state) void micros_process_wait_for_process(uint32_t process_id_to_wait) { micros_interrupt_1a(0x9A, process_id_to_wait); +} + +uint32_t micros_process_start_thread(void *entry_point) +{ + uint32_t stack_size = 1024 * 1024 * 4 - 4; + char *stack_area = (char *)malloc(stack_size); + char *stack = stack_area + stack_size; + + *(uint32_t*)stack = __micros_process_close_thread; + + return micros_interrupt_2a(0x9B, entry_point, stack); +} + +void __micros_process_close_thread() +{ + micros_process_exit(0); } \ No newline at end of file diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index 25be67f0..9ec69175 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -221,6 +221,16 @@ void micros_process_finish_signal_handler(micros_signal_params *old_state); */ void micros_process_wait_for_process(uint32_t process_id_to_wait); +//! Creates new thread +/*! + Creates new thread with the specified parameters. + \param entry_point Address of the entry point from which thread will start. + \return ID of the create thread. +*/ +uint32_t micros_process_start_thread(void *entry_point); + +void __micros_process_close_thread(); + #ifdef __cplusplus } #endif diff --git a/os/kernel/src/process/syscalls/handlers/process_calls.c b/os/kernel/src/process/syscalls/handlers/process_calls.c index 990a2ee4..2b3f579b 100644 --- a/os/kernel/src/process/syscalls/handlers/process_calls.c +++ b/os/kernel/src/process/syscalls/handlers/process_calls.c @@ -59,4 +59,15 @@ void syscall_process_finish_signal_handler(interrupt_state *state) void syscall_process_wait_for_process(interrupt_state *state) { process_manager_current_process_wait_for_process(state->registers.ebx); +} + +void syscall_process_start_thread(interrupt_state *state) +{ + uint32_t process_id = process_manager_get_current_process()->id; + uint32_t thread_id = process_manager_create_thread(process_id, state->registers.ebx, state->registers.ecx); + + terminal_struct* current_terminal = find_terminal_for_process(process_id); + attach_process_to_terminal(current_terminal->terminal_id, process_manager_get_process(thread_id)); + + state->registers.eax = thread_id; } \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/handlers/process_calls.h b/os/kernel/src/process/syscalls/handlers/process_calls.h index 38a412b0..cafd08ed 100644 --- a/os/kernel/src/process/syscalls/handlers/process_calls.h +++ b/os/kernel/src/process/syscalls/handlers/process_calls.h @@ -15,5 +15,6 @@ void syscall_process_start_process(interrupt_state *state); void syscall_process_set_current_process_signal_handler(interrupt_state *state); void syscall_process_finish_signal_handler(interrupt_state *state); void syscall_process_wait_for_process(interrupt_state *state); +void syscall_process_start_thread(interrupt_state *state); #endif \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/syscalls_manager.c b/os/kernel/src/process/syscalls/syscalls_manager.c index 3442fb48..eaf2c272 100644 --- a/os/kernel/src/process/syscalls/syscalls_manager.c +++ b/os/kernel/src/process/syscalls/syscalls_manager.c @@ -79,6 +79,7 @@ void syscalls_manager_init() syscalls_manager_attach_handler(0x98, syscall_process_set_current_process_signal_handler); syscalls_manager_attach_handler(0x99, syscall_process_finish_signal_handler); syscalls_manager_attach_handler(0x9A, syscall_process_wait_for_process); + syscalls_manager_attach_handler(0x9B, syscall_process_start_thread); // 0xAX - Memory syscalls_manager_attach_handler(0xA0, syscall_memory_get_physical_memory_stats); From a0ab59cf5e9a4610d59c138041e84a50f6d1f981 Mon Sep 17 00:00:00 2001 From: Tearth Date: Fri, 31 Jul 2020 21:56:10 +0200 Subject: [PATCH 063/165] Add partial support for threads --- os/kernel/src/process/manager/process_info.h | 1 + .../src/process/manager/process_manager.c | 90 +++++++++++++++---- .../src/process/manager/process_manager.h | 3 +- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/os/kernel/src/process/manager/process_info.h b/os/kernel/src/process/manager/process_info.h index 9e8df172..c253af85 100644 --- a/os/kernel/src/process/manager/process_info.h +++ b/os/kernel/src/process/manager/process_info.h @@ -18,6 +18,7 @@ typedef struct process_info uint32_t id; uint32_t parent_id; char name[32]; + bool is_thread; process_status status; uint32_t size_in_memory; diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index 97ddabf7..3dfe3a6c 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -39,6 +39,7 @@ uint32_t process_manager_create_process(char *path, char *parameters, uint32_t p process->current_cpu_usage = 0; process->last_cpu_usage = 0; process->sleep_deadline = 0; + process->is_thread = false; process->page_directory = heap_kernel_alloc(1024 * 4, 1024 * 4); @@ -129,6 +130,59 @@ uint32_t process_manager_create_process(char *path, char *parameters, uint32_t p return process->id; } +uint32_t process_manager_create_thread(uint32_t process_id, void *entry_point, void *stack) +{ + process_info *process = process_manager_get_process_info(process_id); + + process_info *thread = (process_info *)heap_kernel_alloc(sizeof(process_info), 0); + thread->id = next_process_id++; + thread->parent_id = process_id; + thread->status = process_status_ready; + thread->current_cpu_usage = 0; + thread->last_cpu_usage = 0; + thread->sleep_deadline = 0; + thread->page_directory = process->page_directory; + thread->user_stack = stack; + thread->heap = process->heap; + thread->signal_handler = process->signal_handler; + thread->terminal_id = process->terminal_id; + thread->is_thread = true; + + thread->state.eip = entry_point; + thread->state.esp = (uint32_t)thread->user_stack - 4; + thread->state.interrupt_number = 0; + thread->state.eflags = 0x200; + thread->state.cs = 0x1B; + thread->state.ss = 0x23; + + thread->state.registers.eax = 0; + thread->state.registers.ebx = 0; + thread->state.registers.ecx = 0; + thread->state.registers.edx = 0; + thread->state.registers.esp_unused = (uint32_t)thread->state.esp; + thread->state.registers.ebp = 0; + thread->state.registers.esi = 0; + thread->state.registers.edi = 0; + + thread->state.fpu_state.control_word = 0x37F; + thread->state.fpu_state.status_word = 0; + thread->state.fpu_state.tag_word = 0xFFFF; + thread->state.fpu_state.instruction_pointer_offset = 0; + thread->state.fpu_state.instruction_pointer_selector = 0; + thread->state.fpu_state.opcode = 0; + thread->state.fpu_state.operand_pointer_offset = 0; + thread->state.fpu_state.operand_pointer_selector = 0; + memcpy(thread->name, "SLAVE", 32); + + if (processes.count == 0) + { + current_process_id = thread->id; + } + + kvector_add(&processes, thread); + return thread->id; +} + process_info *process_manager_get_process(uint32_t process_id) { for (uint32_t i = 0; i < processes.count; i++) @@ -222,11 +276,10 @@ void process_manager_switch_to_next_process() void process_manager_close_current_process() { process_info *current_process = processes.data[current_process_id]; - dettached_process_from_terminal(current_process); - process_manager_close_process(current_process->id); + process_manager_close_process(current_process->id, true); } -void process_manager_close_process(uint32_t process_id) +void process_manager_close_process(uint32_t process_id, bool allow_to_switch) { io_disable_interrupts(); @@ -234,6 +287,8 @@ void process_manager_close_process(uint32_t process_id) process_info* process = processes.data[process_index]; kvector_remove(&processes, process_index); + dettached_process_from_terminal(process); + void *page_directory_backup = (uint32_t*)paging_get_page_directory(); void *heap_backup = (uint32_t*)heap_get_user_heap(); @@ -259,30 +314,33 @@ void process_manager_close_process(uint32_t process_id) if(potential_child_process->parent_id == process->id) { - process_manager_close_process(potential_child_process->id); + process_manager_close_process(potential_child_process->id, false); } } io_enable_interrupts(); - if (processes.count > 0) + if (allow_to_switch) { - bool switch_to_next_process = process_index == current_process_id; - - if(process->id <= current_process_id) + if (processes.count > 0) { - current_process_id--; + bool switch_to_next_process = process_index == current_process_id; + + if(process->id <= current_process_id) + { + current_process_id--; + } + + if(switch_to_next_process) + { + process_manager_switch_to_next_process(); + } } - - if(switch_to_next_process) + else { - process_manager_switch_to_next_process(); + panic_screen_show(NULL, 31, "No active process"); } } - else - { - panic_screen_show(NULL, 31, "No active process"); - } } uint32_t process_manager_get_processes_count() diff --git a/os/kernel/src/process/manager/process_manager.h b/os/kernel/src/process/manager/process_manager.h index a3061161..578fe4c6 100644 --- a/os/kernel/src/process/manager/process_manager.h +++ b/os/kernel/src/process/manager/process_manager.h @@ -19,6 +19,7 @@ void process_manager_init(); uint32_t process_manager_create_process(char *path, char *parameters, uint32_t parent_id, bool active); +uint32_t process_manager_create_thread(uint32_t process_id, void *entry_point, void *stack); process_info *process_manager_get_process(uint32_t process_id); process_info *process_manager_get_current_process(); @@ -28,7 +29,7 @@ uint32_t process_manager_get_root_process(); void process_manager_save_current_process_state(interrupt_state *state, uint32_t delta); void process_manager_switch_to_next_process(); void process_manager_close_current_process(); -void process_manager_close_process(uint32_t process_id); +void process_manager_close_process(uint32_t process_id, bool allow_to_switch); uint32_t process_manager_get_processes_count(); uint32_t process_manager_get_process_index(uint32_t process_id); process_info *process_manager_get_process_info(uint32_t id); From fa998c00543383beb69de7fb2bcd6a78ec4330d8 Mon Sep 17 00:00:00 2001 From: Tearth Date: Fri, 31 Jul 2020 22:19:46 +0200 Subject: [PATCH 064/165] Add proper returning from the thread function --- library/src/micros/micros_process.c | 16 ++++---- library/src/micros/micros_process.h | 5 ++- .../signal/default/default_sigsegv_handler.c | 2 +- library/src/stdlib/abort.c | 2 +- library/src/stdlib/exit.c | 2 +- .../src/process/manager/process_manager.c | 37 ++++++++++--------- .../src/process/manager/process_manager.h | 4 +- .../process/syscalls/handlers/process_calls.c | 2 +- os/kernel/src/terminal/terminal_manager.c | 2 +- 9 files changed, 39 insertions(+), 33 deletions(-) diff --git a/library/src/micros/micros_process.c b/library/src/micros/micros_process.c index 27a5e472..153e86c4 100644 --- a/library/src/micros/micros_process.c +++ b/library/src/micros/micros_process.c @@ -1,8 +1,8 @@ #include "micros_process.h" -void micros_process_exit(int status) +void micros_process_exit(int status, bool is_thread) { - micros_interrupt_1a(0x90, status); + micros_interrupt_2a(0x90, status, is_thread); } uint32_t micros_process_get_processes_count() @@ -57,16 +57,18 @@ void micros_process_wait_for_process(uint32_t process_id_to_wait) uint32_t micros_process_start_thread(void *entry_point) { - uint32_t stack_size = 1024 * 1024 * 4 - 4; - char *stack_area = (char *)malloc(stack_size); - char *stack = stack_area + stack_size; + uint32_t stack_size = 1024 * 1024 * 4; - *(uint32_t*)stack = __micros_process_close_thread; + uint32_t *stack_area = (uint32_t *)malloc(stack_size); + uint32_t *stack = stack_area + stack_size / 4; + + *(stack - 1) = __micros_process_close_thread; + uint32_t test = *(stack - 1); return micros_interrupt_2a(0x9B, entry_point, stack); } void __micros_process_close_thread() { - micros_process_exit(0); + micros_process_exit(0, true); } \ No newline at end of file diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index 9ec69175..63872b45 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -142,9 +142,10 @@ extern "C" { //! Forces current process to exit /*! Forces current process to exit with the specified status code (typically 0 means success). - \param status Exis status code. + \param status Exit status code. + \param is_thread Flag indicating if the system should close only current thread or whole process. */ -void micros_process_exit(int status); +void micros_process_exit(int status, bool is_thread); //! Returns number of processes /*! diff --git a/library/src/signal/default/default_sigsegv_handler.c b/library/src/signal/default/default_sigsegv_handler.c index df615dde..b63a2624 100644 --- a/library/src/signal/default/default_sigsegv_handler.c +++ b/library/src/signal/default/default_sigsegv_handler.c @@ -3,5 +3,5 @@ void default_sigsegv_handler(int param) { fprintf(stderr, "SIGSEGV received. Address: %#x\n", param); - micros_process_exit(-1); + micros_process_exit(-1, false); } \ No newline at end of file diff --git a/library/src/stdlib/abort.c b/library/src/stdlib/abort.c index 3448d16f..8ddfc79c 100644 --- a/library/src/stdlib/abort.c +++ b/library/src/stdlib/abort.c @@ -2,5 +2,5 @@ void abort() { - micros_process_exit(-1); + micros_process_exit(-1, false); } \ No newline at end of file diff --git a/library/src/stdlib/exit.c b/library/src/stdlib/exit.c index 7eee3d7a..d93559ce 100644 --- a/library/src/stdlib/exit.c +++ b/library/src/stdlib/exit.c @@ -2,5 +2,5 @@ void exit(int status) { - micros_process_exit(status); + micros_process_exit(status, false); } \ No newline at end of file diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index 3dfe3a6c..adfc04e8 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -149,7 +149,7 @@ uint32_t process_manager_create_thread(uint32_t process_id, void *entry_point, v thread->is_thread = true; thread->state.eip = entry_point; - thread->state.esp = (uint32_t)thread->user_stack - 4; + thread->state.esp = (uint32_t)thread->user_stack - sizeof(void*); thread->state.interrupt_number = 0; thread->state.eflags = 0x200; thread->state.cs = 0x1B; @@ -273,13 +273,13 @@ void process_manager_switch_to_next_process() enter_user_space(&new_process->state); } -void process_manager_close_current_process() +void process_manager_close_current_process(bool is_thread) { process_info *current_process = processes.data[current_process_id]; - process_manager_close_process(current_process->id, true); + process_manager_close_process(current_process->id, is_thread, true); } -void process_manager_close_process(uint32_t process_id, bool allow_to_switch) +void process_manager_close_process(uint32_t process_id, bool is_thread, bool allow_to_switch) { io_disable_interrupts(); @@ -289,21 +289,24 @@ void process_manager_close_process(uint32_t process_id, bool allow_to_switch) dettached_process_from_terminal(process); - void *page_directory_backup = (uint32_t*)paging_get_page_directory(); - void *heap_backup = (uint32_t*)heap_get_user_heap(); - - paging_set_page_directory(process->page_directory); - heap_set_user_heap((void *)(process->heap)); - - uint32_t allocated_pages_count = virtual_memory_get_allocated_pages_count(false); - for(uint32_t i=0; ipage_directory); + heap_set_user_heap((void *)(process->heap)); + + uint32_t allocated_pages_count = virtual_memory_get_allocated_pages_count(false); + for(uint32_t i=0; i= 0; i--) { process_info* potential_child_process = processes.data[i]; @@ -314,7 +317,7 @@ void process_manager_close_process(uint32_t process_id, bool allow_to_switch) if(potential_child_process->parent_id == process->id) { - process_manager_close_process(potential_child_process->id, false); + process_manager_close_process(potential_child_process->id, potential_child_process->is_thread, false); } } diff --git a/os/kernel/src/process/manager/process_manager.h b/os/kernel/src/process/manager/process_manager.h index 578fe4c6..0d8e9cdf 100644 --- a/os/kernel/src/process/manager/process_manager.h +++ b/os/kernel/src/process/manager/process_manager.h @@ -28,8 +28,8 @@ uint32_t process_manager_get_root_process(); void process_manager_save_current_process_state(interrupt_state *state, uint32_t delta); void process_manager_switch_to_next_process(); -void process_manager_close_current_process(); -void process_manager_close_process(uint32_t process_id, bool allow_to_switch); +void process_manager_close_current_process(bool is_thread); +void process_manager_close_process(uint32_t process_id, bool is_thread, bool allow_to_switch); uint32_t process_manager_get_processes_count(); uint32_t process_manager_get_process_index(uint32_t process_id); process_info *process_manager_get_process_info(uint32_t id); diff --git a/os/kernel/src/process/syscalls/handlers/process_calls.c b/os/kernel/src/process/syscalls/handlers/process_calls.c index 2b3f579b..31eac002 100644 --- a/os/kernel/src/process/syscalls/handlers/process_calls.c +++ b/os/kernel/src/process/syscalls/handlers/process_calls.c @@ -2,7 +2,7 @@ void syscall_process_exit(interrupt_state *state) { - process_manager_close_current_process(state); + process_manager_close_current_process(state->registers.ecx); } void syscall_process_get_processes_count(interrupt_state *state) diff --git a/os/kernel/src/terminal/terminal_manager.c b/os/kernel/src/terminal/terminal_manager.c index c99834d6..8bab392e 100644 --- a/os/kernel/src/terminal/terminal_manager.c +++ b/os/kernel/src/terminal/terminal_manager.c @@ -131,7 +131,7 @@ int8_t destroy_terminal(uint32_t terminal_id) for(uint32_t i; iid); + process_manager_close_process(s.attached_processes[i]->id, s.attached_processes[i]->is_thread, true); } heap_kernel_dealloc(s.attached_processes); From a6b9cb3692ad5f2820c244bb9ac30b000296b4ea Mon Sep 17 00:00:00 2001 From: Tearth Date: Fri, 31 Jul 2020 22:20:33 +0200 Subject: [PATCH 065/165] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62b24180..4dc4b9ff 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,12 @@ Documentation: https://tearth.github.io/MicrOS/ * Standard library for C * ATA Hard disk drive support * CPUID +* Multithreading ## TODO * Other standards of hard disk drive support * More advanced scheduler with priorities and IO blocking * Support for network cards (and protocols related to them) -* Support for threads * Lock/mutex, synchronization objects, queues... * ... From e2f897a3a1da70f450ed9ef1df6a12f7d923651f Mon Sep 17 00:00:00 2001 From: Tearth Date: Fri, 31 Jul 2020 23:28:15 +0200 Subject: [PATCH 066/165] Fix warnings --- library/src/micros/micros_process.c | 5 ++--- library/src/micros/micros_process.h | 1 + os/kernel/src/process/manager/process_manager.c | 2 +- os/kernel/src/process/syscalls/handlers/process_calls.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/src/micros/micros_process.c b/library/src/micros/micros_process.c index 153e86c4..048b7068 100644 --- a/library/src/micros/micros_process.c +++ b/library/src/micros/micros_process.c @@ -62,10 +62,9 @@ uint32_t micros_process_start_thread(void *entry_point) uint32_t *stack_area = (uint32_t *)malloc(stack_size); uint32_t *stack = stack_area + stack_size / 4; - *(stack - 1) = __micros_process_close_thread; - uint32_t test = *(stack - 1); + *(stack - 1) = (uint32_t)__micros_process_close_thread; - return micros_interrupt_2a(0x9B, entry_point, stack); + return micros_interrupt_2a(0x9B, (uint32_t)entry_point, (uint32_t)stack); } void __micros_process_close_thread() diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index 63872b45..7c1ff8ff 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -2,6 +2,7 @@ #define MICROS_PROCESS_H #include +#include "../stdlib.h" #include "micros_interrupts.h" //! Process status retrieved from the kernel diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index adfc04e8..1572572b 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -148,7 +148,7 @@ uint32_t process_manager_create_thread(uint32_t process_id, void *entry_point, v thread->terminal_id = process->terminal_id; thread->is_thread = true; - thread->state.eip = entry_point; + thread->state.eip = (uint32_t)entry_point; thread->state.esp = (uint32_t)thread->user_stack - sizeof(void*); thread->state.interrupt_number = 0; thread->state.eflags = 0x200; diff --git a/os/kernel/src/process/syscalls/handlers/process_calls.c b/os/kernel/src/process/syscalls/handlers/process_calls.c index 31eac002..fe390ddf 100644 --- a/os/kernel/src/process/syscalls/handlers/process_calls.c +++ b/os/kernel/src/process/syscalls/handlers/process_calls.c @@ -64,7 +64,7 @@ void syscall_process_wait_for_process(interrupt_state *state) void syscall_process_start_thread(interrupt_state *state) { uint32_t process_id = process_manager_get_current_process()->id; - uint32_t thread_id = process_manager_create_thread(process_id, state->registers.ebx, state->registers.ecx); + uint32_t thread_id = process_manager_create_thread(process_id, (void *)state->registers.ebx, (void *)state->registers.ecx); terminal_struct* current_terminal = find_terminal_for_process(process_id); attach_process_to_terminal(current_terminal->terminal_id, process_manager_get_process(thread_id)); From f36253eb892980c713af666df8609a3dec1f4949 Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 1 Aug 2020 00:36:03 +0200 Subject: [PATCH 067/165] Added Enter and Leave... Wherever I will enter and leave. --- os/kernel/src/v8086/operations/opcodes.c | 13 ++- os/kernel/src/v8086/operations/opcodes.h | 2 + .../src/v8086/operations/stack_operations.c | 83 +++++++++++++++++-- .../src/v8086/operations/stack_operations.h | 14 ++-- os/kernel/src/v8086/v8086.c | 2 + 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 8456b3ed..ddbf855c 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -535,7 +535,16 @@ OPCODE_PROTO(outs8){ return perform_outs_dx(machine, 8); } -OPCODE_PROTO(outs) -{ +OPCODE_PROTO(outs) { return perform_outs_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(enter) +{ + return enter(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(leave) +{ + return leave(machine, machine->internal_state.operand_32_bit ? 32 : 16); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index a5ab1d5c..c2a1cb6e 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -105,5 +105,7 @@ OPCODE_PROTO(ins8); OPCODE_PROTO(ins); OPCODE_PROTO(outs8); OPCODE_PROTO(outs); +OPCODE_PROTO(enter); +OPCODE_PROTO(leave); #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index 0d66c034..6fef673c 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -5,7 +5,7 @@ #include #include "stack_operations.h" -uint16_t push_gpr(v8086* machine, uint8_t opcode) +int16_t push_gpr(v8086* machine, uint8_t opcode) { uint8_t width = 16; void* reg = NULL; @@ -17,7 +17,7 @@ uint16_t push_gpr(v8086* machine, uint8_t opcode) return OK; } -uint16_t pop_gpr(v8086* machine, uint8_t opcode) +int16_t pop_gpr(v8086* machine, uint8_t opcode) { uint8_t width = 16; void* reg = NULL; @@ -29,7 +29,7 @@ uint16_t pop_gpr(v8086* machine, uint8_t opcode) return OK; } -uint16_t pop_rm(v8086* machine) +int16_t pop_rm(v8086* machine) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; @@ -44,7 +44,7 @@ uint16_t pop_rm(v8086* machine) return OK; } -uint16_t push_all(v8086* machine) +int16_t push_all(v8086* machine) { uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; uint32_t temp_sp = width == 16 ? machine->regs.w.sp : machine->regs.d.esp; @@ -72,7 +72,7 @@ uint16_t push_all(v8086* machine) return OK; } -uint16_t pop_all(v8086* machine) +int16_t pop_all(v8086* machine) { uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; if(width == 16) @@ -101,7 +101,7 @@ uint16_t pop_all(v8086* machine) return OK; } -uint16_t push_immediate(v8086* machine, uint8_t width) +int16_t push_immediate(v8086* machine, uint8_t width) { if(width == 8) { @@ -125,4 +125,75 @@ uint16_t push_immediate(v8086* machine, uint8_t width) return OK; } return BAD_WIDTH; +} + +int16_t enter(v8086* machine, uint8_t width) +{ + uint16_t alloc_size = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + + uint8_t nesting_level = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + nesting_level = nesting_level & 0x1fu; + + uint32_t temp_ebp; + + if(width == 32) + { + push_dword(machine, machine->regs.d.ebp); + temp_ebp = machine->regs.d.esp; + } + else if(width == 16) + { + push_word(machine, machine->regs.w.bp); + temp_ebp = machine->regs.w.sp; + } + else return BAD_WIDTH; + + if(nesting_level > 0) + { + for(uint8_t i = 1; i < nesting_level; i++) + { + if(width == 32) + { + machine->regs.d.ebp -= 4; + push_dword(machine, read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.d.ebp))); + } + else{ + machine->regs.w.bp -= 2; + push_word(machine, read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.bp))); + } + } + if(width == 32) + push_dword(machine, temp_ebp); + else + push_word(machine, temp_ebp); + } + + if(width == 32) { + machine->regs.d.ebp = temp_ebp; + machine->regs.d.esp -= alloc_size; + } + else { + machine->regs.w.bp = temp_ebp; + machine->regs.w.sp -= alloc_size; + } + + return OK; +} + +int16_t leave(v8086* machine, uint8_t width) +{ + if(width == 32) { + machine->regs.d.esp = machine->regs.d.ebp; + machine->regs.d.ebp = pop_dword(machine); + return OK; + } + if(width == 16){ + machine -> regs.w.sp = machine->regs.w.sp; + machine->regs.w.bp = pop_word(machine); + return OK; + } + return BAD_WIDTH; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/stack_operations.h b/os/kernel/src/v8086/operations/stack_operations.h index 56cc391c..bdcba4cf 100644 --- a/os/kernel/src/v8086/operations/stack_operations.h +++ b/os/kernel/src/v8086/operations/stack_operations.h @@ -3,12 +3,14 @@ #include "../v8086.h" -uint16_t push_gpr(v8086* machine, uint8_t opcode); -uint16_t pop_gpr(v8086* machine, uint8_t opcode); -uint16_t pop_rm(v8086* machine); -uint16_t push_all(v8086* machine); -uint16_t pop_all(v8086* machine); -uint16_t push_immediate(v8086* machine, uint8_t width); +int16_t push_gpr(v8086* machine, uint8_t opcode); +int16_t pop_gpr(v8086* machine, uint8_t opcode); +int16_t pop_rm(v8086* machine); +int16_t push_all(v8086* machine); +int16_t pop_all(v8086* machine); +int16_t push_immediate(v8086* machine, uint8_t width); +int16_t enter(v8086* machine, uint8_t width); +int16_t leave(v8086* machine, uint8_t width); #endif //MICROS_STACK_OPERATIONS_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 190361c6..023103e1 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -152,6 +152,8 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_OPCODE(0x6du, ins); ASSIGN_OPCODE(0x6eu, outs8); ASSIGN_OPCODE(0x6fu, outs); + ASSIGN_OPCODE(0xc8u, enter); + ASSIGN_OPCODE(0xc9u, leave); } v8086* v8086_create_machine() From cb0b80b7a8676295b204b1f850a54348b611b258 Mon Sep 17 00:00:00 2001 From: Tearth Date: Sat, 1 Aug 2020 11:26:07 +0200 Subject: [PATCH 068/165] Add is_thread flag to the user process info --- library/src/micros/micros_process.h | 3 +++ os/kernel/src/process/manager/process_manager.c | 1 + os/kernel/src/process/manager/process_user_info.h | 1 + 3 files changed, 5 insertions(+) diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index 7c1ff8ff..bdab9e0d 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -44,6 +44,9 @@ typedef struct micros_process_user_info //! Current process memory usage calculated by the kernel uint32_t memory_usage; + + //! Flag indicating if this is a process or a thread + bool is_thread; } __attribute__((packed)) micros_process_user_info; //! Process registers state diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index 1572572b..9f1e5386 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -486,6 +486,7 @@ void process_manager_convert_process_info_to_user_info(process_info *process, pr user_info->status = (uint32_t)process->status; user_info->cpu_usage = process->last_cpu_usage; user_info->memory_usage = process_manager_get_process_memory_usage(process); + user_info->is_thread = process->is_thread; } uint32_t process_manager_get_process_memory_usage(process_info *process) diff --git a/os/kernel/src/process/manager/process_user_info.h b/os/kernel/src/process/manager/process_user_info.h index 1fd01dfa..3b56a136 100644 --- a/os/kernel/src/process/manager/process_user_info.h +++ b/os/kernel/src/process/manager/process_user_info.h @@ -10,6 +10,7 @@ typedef struct process_user_info uint32_t status; float cpu_usage; uint32_t memory_usage; + bool is_thread; } __attribute__((packed)) process_user_info; #endif \ No newline at end of file From 481dd56b23f3c17917d4206478b2ba7df077e86d Mon Sep 17 00:00:00 2001 From: Tearth Date: Sat, 1 Aug 2020 11:26:36 +0200 Subject: [PATCH 069/165] Add better displaying of threads in tasks app --- environment/tasks/src/main.c | 46 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/environment/tasks/src/main.c b/environment/tasks/src/main.c index 889cc8c4..b6a21192 100644 --- a/environment/tasks/src/main.c +++ b/environment/tasks/src/main.c @@ -2,6 +2,8 @@ #include #include +bool show_threads; + void draw_process_tree(micros_process_user_info *processes, uint32_t root_id, uint32_t level, uint32_t count); void print_total_process_count(int process_count); void draw_bar(uint32_t filled_entries, uint32_t total_entries); @@ -10,11 +12,29 @@ void draw_memory_usage_bar(micros_physical_memory_stats *memory_stats, uint32_t void print_process_info(micros_process_user_info *process_info); void print_memory_stats(micros_physical_memory_stats *memory_stats); +void shuka1() +{ + while(true) + { + + } +} +void shuka2() +{ + while(true) + { + + } +} + int main(int argc, char *argv[]) { micros_process_set_current_process_name("TASKS"); micros_console_set_cursor_visibility(false); printf("TASKS"); + + micros_process_start_thread(shuka1); + micros_process_start_thread(shuka2); while (1) { @@ -60,7 +80,8 @@ int main(int argc, char *argv[]) print_memory_stats(&memory_stats); printf("\n\n\n\n"); - printf(" Press ESC to exit"); + printf(" Press T to show/hide threads\n"); + printf(" Press ESC to exit\n"); free(processes); micros_process_current_process_sleep(1500); @@ -74,6 +95,10 @@ int main(int argc, char *argv[]) { break; } + else if(pressed_key.scancode == key_t) + { + show_threads = !show_threads; + } } } @@ -82,7 +107,7 @@ int main(int argc, char *argv[]) } void draw_process_tree(micros_process_user_info *processes, uint32_t root_id, uint32_t level, uint32_t count) -{ +{ micros_process_user_info *root_process = NULL; for (uint32_t i = 0; i < count; i++) { @@ -92,6 +117,11 @@ void draw_process_tree(micros_process_user_info *processes, uint32_t root_id, ui root_process = &processes[i]; } } + + if (!show_threads && root_process->is_thread) + { + return; + } if (level != 0) { @@ -111,7 +141,8 @@ void draw_process_tree(micros_process_user_info *processes, uint32_t root_id, ui micros_process_user_info *process = &processes[i]; if (process->id != 0 && process->parent_id == root_id) { - draw_process_tree(processes, process->id, level + 2, count); + + draw_process_tree(processes, process->id, level + 2, count); } } } @@ -160,7 +191,14 @@ void draw_memory_usage_bar(micros_physical_memory_stats *memory_stats, uint32_t void print_process_info(micros_process_user_info *process_info) { - printf("%s - ID: %d", process_info->name, process_info->id); + if (show_threads) + { + printf("[%s] %s - ID: %d", process_info->is_thread ? "T" : "P", process_info->name, process_info->id); + } + else + { + printf("%s - ID: %d", process_info->name, process_info->id); + } if (process_info->id != process_info->parent_id) { From a7cf432c2ed31ac966208d26b3cb8ad334297b83 Mon Sep 17 00:00:00 2001 From: Tearth Date: Sat, 1 Aug 2020 11:41:38 +0200 Subject: [PATCH 070/165] Fix invalid calculation of CPU utilization --- environment/tasks/src/main.c | 31 +++++-------------- .../src/process/manager/process_manager.c | 6 ++++ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/environment/tasks/src/main.c b/environment/tasks/src/main.c index b6a21192..1edc5cbd 100644 --- a/environment/tasks/src/main.c +++ b/environment/tasks/src/main.c @@ -12,35 +12,17 @@ void draw_memory_usage_bar(micros_physical_memory_stats *memory_stats, uint32_t void print_process_info(micros_process_user_info *process_info); void print_memory_stats(micros_physical_memory_stats *memory_stats); -void shuka1() -{ - while(true) - { - - } -} -void shuka2() -{ - while(true) - { - - } -} - int main(int argc, char *argv[]) { micros_process_set_current_process_name("TASKS"); micros_console_set_cursor_visibility(false); printf("TASKS"); - - micros_process_start_thread(shuka1); - micros_process_start_thread(shuka2); while (1) { micros_console_clear(); - printf("TASKS v1.1 @ MicrOS\n"); + printf("TASKS v1.2 @ MicrOS\n"); printf("\n"); uint32_t processes_count = micros_process_get_processes_count(); @@ -53,8 +35,12 @@ int main(int argc, char *argv[]) for (uint32_t i = 0; i < processes_count; i++) { micros_process_user_info *process = &processes[i]; - total_cpu_usage += process->cpu_usage; - total_memory_usage += process->memory_usage; + + if (!process->is_thread) + { + total_cpu_usage += process->cpu_usage; + total_memory_usage += process->memory_usage; + } } micros_physical_memory_stats memory_stats; @@ -141,8 +127,7 @@ void draw_process_tree(micros_process_user_info *processes, uint32_t root_id, ui micros_process_user_info *process = &processes[i]; if (process->id != 0 && process->parent_id == root_id) { - - draw_process_tree(processes, process->id, level + 2, count); + draw_process_tree(processes, process->id, level + 2, count); } } } diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index 9f1e5386..4c4deb1c 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -217,6 +217,12 @@ void process_manager_save_current_process_state(interrupt_state *state, uint32_t memcpy(&old_process->state, state, sizeof(interrupt_state)); old_process->current_cpu_usage += delta; + + if (old_process->is_thread) + { + process_info *parent_process = process_manager_get_process_info(old_process->parent_id); + parent_process->current_cpu_usage += delta; + } } void process_manager_switch_to_next_process() From 94fba26c341aed605df5776243fb149ac369a4a1 Mon Sep 17 00:00:00 2001 From: Tearth Date: Sat, 1 Aug 2020 12:04:48 +0200 Subject: [PATCH 071/165] Add ability to pass a parameter to the thread's function --- library/src/micros/micros_process.c | 5 +++-- library/src/micros/micros_process.h | 3 ++- os/kernel/src/process/manager/process_manager.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/src/micros/micros_process.c b/library/src/micros/micros_process.c index 048b7068..fdee95c7 100644 --- a/library/src/micros/micros_process.c +++ b/library/src/micros/micros_process.c @@ -55,14 +55,15 @@ void micros_process_wait_for_process(uint32_t process_id_to_wait) micros_interrupt_1a(0x9A, process_id_to_wait); } -uint32_t micros_process_start_thread(void *entry_point) +uint32_t micros_process_start_thread(void *entry_point, void *param) { uint32_t stack_size = 1024 * 1024 * 4; uint32_t *stack_area = (uint32_t *)malloc(stack_size); uint32_t *stack = stack_area + stack_size / 4; - *(stack - 1) = (uint32_t)__micros_process_close_thread; + *(stack - 1) = (uint32_t)param; + *(stack - 2) = (uint32_t)__micros_process_close_thread; return micros_interrupt_2a(0x9B, (uint32_t)entry_point, (uint32_t)stack); } diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index bdab9e0d..e91168e5 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -230,9 +230,10 @@ void micros_process_wait_for_process(uint32_t process_id_to_wait); /*! Creates new thread with the specified parameters. \param entry_point Address of the entry point from which thread will start. + \param param Parameter which will be passed to the thread function. \return ID of the create thread. */ -uint32_t micros_process_start_thread(void *entry_point); +uint32_t micros_process_start_thread(void *entry_point, void *param); void __micros_process_close_thread(); diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index 4c4deb1c..cec45e61 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -149,7 +149,7 @@ uint32_t process_manager_create_thread(uint32_t process_id, void *entry_point, v thread->is_thread = true; thread->state.eip = (uint32_t)entry_point; - thread->state.esp = (uint32_t)thread->user_stack - sizeof(void*); + thread->state.esp = (uint32_t)thread->user_stack - 2 * sizeof(void*); thread->state.interrupt_number = 0; thread->state.eflags = 0x200; thread->state.cs = 0x1B; From 010c5f312b3a50852c8987b94f0d4f8cd8c2aca1 Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 1 Aug 2020 23:12:16 +0200 Subject: [PATCH 072/165] Created wrapper for two byte opcodes with 0x0f primary opcode --- os/kernel/src/v8086/operations/opcodes.c | 12 ++++++++++++ os/kernel/src/v8086/operations/opcodes.h | 5 +++++ os/kernel/src/v8086/v8086.c | 4 ++++ os/kernel/src/v8086/v8086.h | 1 + 4 files changed, 22 insertions(+) diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index ddbf855c..37b56c8a 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -547,4 +547,16 @@ OPCODE_PROTO(enter) OPCODE_PROTO(leave) { return leave(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +//386 2_bytes_protos 0x0f Prefix + +OPCODE_PROTO(two_byte_0fh){ + uint8_t secondary_opcode; + secondary_opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(machine->operations_0fh[opcode] == NULL) return UNDEFINED_OPCODE; + + return machine->operations_0fh[opcode](machine, secondary_opcode); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index c2a1cb6e..3a413326 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -7,7 +7,9 @@ #define OPCODE_PROTO(name) int16_t OPCODE_PROTO_NAME(name)(v8086* machine, uint8_t opcode) #define ASSIGN_NULL(i) machine->operations[i] = NULL #define ASSIGN_OPCODE(i, name) machine->operations[i] = OPCODE_PROTO_NAME(name) +#define ASSIGN_0FH_OPCODE(i, name) machine->operations_0fh[i] = OPCODE_PROTO_NAME(name) #define GROUP_OF_OPCODES(from, to, name) for(uint8_t i = from; i <= to; i++) ASSIGN_OPCODE(i, name) +#define GROUP_OF_0FH_OPCODES(from, to, name) for(uint8_t i = from; i <= to; i++) ASSIGN_0FH_OPCODE(i, name) OPCODE_PROTO(add); OPCODE_PROTO(push_es); @@ -107,5 +109,8 @@ OPCODE_PROTO(outs8); OPCODE_PROTO(outs); OPCODE_PROTO(enter); OPCODE_PROTO(leave); +//386 2_bytes_protos 0x0f Prefix +OPCODE_PROTO(two_byte_0fh); + #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 023103e1..043edb49 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -154,6 +154,10 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_OPCODE(0x6fu, outs); ASSIGN_OPCODE(0xc8u, enter); ASSIGN_OPCODE(0xc9u, leave); + + //2 byte opcodes 0fh_prefix + ASSIGN_OPCODE(0x0fu, two_byte_0fh); + } v8086* v8086_create_machine() diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 78189ddd..de043ac6 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -149,6 +149,7 @@ typedef struct _v8086 uint8_t Memory[0x100000]; enum instruction_set_compatibility is_compatibility; int16_t (*operations[256]) (struct _v8086*, uint8_t); + int16_t (*operations_0fh[256]) (struct _v8086*, uint8_t); } v8086; From 3f30673fd00c7625153b530247f773b4704b130e Mon Sep 17 00:00:00 2001 From: SzateX Date: Sun, 2 Aug 2020 00:32:15 +0200 Subject: [PATCH 073/165] Filled with null not supported operations in 386. --- os/kernel/src/v8086/operations/opcodes.h | 1 + os/kernel/src/v8086/v8086.c | 30 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 3a413326..869d1ba4 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -6,6 +6,7 @@ #define OPCODE_PROTO_NAME(name) v8086_opcode_##name #define OPCODE_PROTO(name) int16_t OPCODE_PROTO_NAME(name)(v8086* machine, uint8_t opcode) #define ASSIGN_NULL(i) machine->operations[i] = NULL +#define ASSIGN_NULL_0FH(i) machine->operations_0fh[i] = NULL #define ASSIGN_OPCODE(i, name) machine->operations[i] = OPCODE_PROTO_NAME(name) #define ASSIGN_0FH_OPCODE(i, name) machine->operations_0fh[i] = OPCODE_PROTO_NAME(name) #define GROUP_OF_OPCODES(from, to, name) for(uint8_t i = from; i <= to; i++) ASSIGN_OPCODE(i, name) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 043edb49..443430e9 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -130,6 +130,11 @@ void v8086_set_8086_instruction_set(v8086* machine) GROUP_OF_OPCODES(0xf8u, 0xfdu, set_flag); ASSIGN_OPCODE(0xfeu, group_4); ASSIGN_OPCODE(0xffu, group_5); + + for(uint16_t i = 0u; i < 256; i++) + { + machine->operations_0fh[i] = NULL; + } } void v8086_set_386_instruction_set(v8086* machine) @@ -157,6 +162,31 @@ void v8086_set_386_instruction_set(v8086* machine) //2 byte opcodes 0fh_prefix ASSIGN_OPCODE(0x0fu, two_byte_0fh); + //NO Protected mode and CR0 emulated + ASSIGN_NULL_0FH(0x00u); + ASSIGN_NULL_0FH(0x01u); + ASSIGN_NULL_0FH(0x02u); + ASSIGN_NULL_0FH(0x03u); + //NO DEFINED IN 386 + ASSIGN_NULL_0FH(0x04u); + ASSIGN_NULL_0FH(0x05u); + //NO Protected mode and CR0 emulated + ASSIGN_NULL_0FH(0x06u); + //NOT DEFINED IN 386 + for(uint8_t i = 0x07; i <= 0x1fu; i++) + { + machine->operations_0fh[i] = NULL; + } + //NO CR, DEBUG, TEST registers emulated + for(uint8_t i = 0x20u; i <= 0x26u; i++) + { + machine->operations_0fh[i] = NULL; + } + //NOT DEFINED IN 386 + for(uint8_t i = 0x27u; i <= 0x7fu; i++) + { + machine->operations_0fh[i] = NULL; + } } From a70ed10166e977bbdf45f30f9c8461edfc1c0735 Mon Sep 17 00:00:00 2001 From: Tearth Date: Sun, 2 Aug 2020 12:14:07 +0200 Subject: [PATCH 074/165] Add function to abort current thread --- library/src/micros/micros_process.c | 10 +++++----- library/src/micros/micros_process.h | 9 ++++++--- library/src/signal/default/default_sigsegv_handler.c | 2 +- library/src/stdlib/abort.c | 2 +- library/src/stdlib/exit.c | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/library/src/micros/micros_process.c b/library/src/micros/micros_process.c index fdee95c7..d3c08d17 100644 --- a/library/src/micros/micros_process.c +++ b/library/src/micros/micros_process.c @@ -1,8 +1,8 @@ #include "micros_process.h" -void micros_process_exit(int status, bool is_thread) +void micros_process_exit_process(int status) { - micros_interrupt_2a(0x90, status, is_thread); + micros_interrupt_2a(0x90, status, false); } uint32_t micros_process_get_processes_count() @@ -63,12 +63,12 @@ uint32_t micros_process_start_thread(void *entry_point, void *param) uint32_t *stack = stack_area + stack_size / 4; *(stack - 1) = (uint32_t)param; - *(stack - 2) = (uint32_t)__micros_process_close_thread; + *(stack - 2) = (uint32_t)micros_process_abort_thread; return micros_interrupt_2a(0x9B, (uint32_t)entry_point, (uint32_t)stack); } -void __micros_process_close_thread() +void micros_process_abort_thread() { - micros_process_exit(0, true); + micros_interrupt_2a(0x90, 0, true); } \ No newline at end of file diff --git a/library/src/micros/micros_process.h b/library/src/micros/micros_process.h index e91168e5..6b3805f6 100644 --- a/library/src/micros/micros_process.h +++ b/library/src/micros/micros_process.h @@ -147,9 +147,8 @@ extern "C" { /*! Forces current process to exit with the specified status code (typically 0 means success). \param status Exit status code. - \param is_thread Flag indicating if the system should close only current thread or whole process. */ -void micros_process_exit(int status, bool is_thread); +void micros_process_exit_process(int status); //! Returns number of processes /*! @@ -235,7 +234,11 @@ void micros_process_wait_for_process(uint32_t process_id_to_wait); */ uint32_t micros_process_start_thread(void *entry_point, void *param); -void __micros_process_close_thread(); +//! Forces current thread to exit +/*! + Forces current thread to exit. +*/ +void micros_process_abort_thread(); #ifdef __cplusplus } diff --git a/library/src/signal/default/default_sigsegv_handler.c b/library/src/signal/default/default_sigsegv_handler.c index b63a2624..06afb076 100644 --- a/library/src/signal/default/default_sigsegv_handler.c +++ b/library/src/signal/default/default_sigsegv_handler.c @@ -3,5 +3,5 @@ void default_sigsegv_handler(int param) { fprintf(stderr, "SIGSEGV received. Address: %#x\n", param); - micros_process_exit(-1, false); + micros_process_exit_process(-1); } \ No newline at end of file diff --git a/library/src/stdlib/abort.c b/library/src/stdlib/abort.c index 8ddfc79c..eac37ccd 100644 --- a/library/src/stdlib/abort.c +++ b/library/src/stdlib/abort.c @@ -2,5 +2,5 @@ void abort() { - micros_process_exit(-1, false); + micros_process_exit_process(-1); } \ No newline at end of file diff --git a/library/src/stdlib/exit.c b/library/src/stdlib/exit.c index d93559ce..b1a129ac 100644 --- a/library/src/stdlib/exit.c +++ b/library/src/stdlib/exit.c @@ -2,5 +2,5 @@ void exit(int status) { - micros_process_exit(status, false); + micros_process_exit_process(status); } \ No newline at end of file From fa3ad6edc0342c2c4fe46df43857f11e158abf6c Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 13:38:19 +0200 Subject: [PATCH 075/165] Added long jcc, setcc, push and pop for GS and FS. --- .../src/v8086/operations/jump_operations.c | 148 ++++++++++++------ .../src/v8086/operations/jump_operations.h | 1 + .../src/v8086/operations/misc_operations.c | 62 ++++++++ .../src/v8086/operations/misc_operations.h | 1 + os/kernel/src/v8086/operations/opcodes.c | 36 ++++- os/kernel/src/v8086/operations/opcodes.h | 7 + os/kernel/src/v8086/v8086.c | 9 ++ 7 files changed, 212 insertions(+), 52 deletions(-) diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c index 3bfefa70..d371ca24 100644 --- a/os/kernel/src/v8086/operations/jump_operations.c +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -14,6 +14,31 @@ int16_t jump_short_relative(v8086* machine) return OK; } +int16_t jump_long_relative(v8086* machine, uint8_t width) +{ + int32_t offset; + if(width == 32) + { + offset = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; + } + else if(width == 16) + { + offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } + else return BAD_WIDTH; + + uint32_t tempIP = machine->IP.w.ip; + tempIP += offset; + if(width == 16) + tempIP &= 0xffffu; + + if((tempIP > 0xFFFF)) return RELATIVE_JMP_OVERFLOW; + machine->IP.w.ip = tempIP; + return OK; +} + int16_t jump_near_relative(v8086* machine) { int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); @@ -33,61 +58,78 @@ int16_t jump_far(v8086* machine) return OK; } +int16_t jump_on_condition(v8086* machine, uint8_t opcode, uint8_t width) +{ + uint8_t jump = 0; + switch(opcode & 0x0fu) + { + case 0: //JO + if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <internal_state.IPOffset += width/8; + } + return OK; +} + int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) { uint8_t jump = 0; if(opcode != 0xe3) - switch(opcode & 0x0fu) - { - case 0: //JO - if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <internal_state.operand_32_bit) @@ -98,6 +140,10 @@ int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) if(!machine->regs.w.cx) jump = 1; } if(jump) return jump_short_relative(machine); + else + { + machine->internal_state.IPOffset += 1; + } return OK; } diff --git a/os/kernel/src/v8086/operations/jump_operations.h b/os/kernel/src/v8086/operations/jump_operations.h index b6992fcf..3fd037a8 100644 --- a/os/kernel/src/v8086/operations/jump_operations.h +++ b/os/kernel/src/v8086/operations/jump_operations.h @@ -8,5 +8,6 @@ int16_t jump_near_relative(v8086* machine); int16_t jump_far(v8086* machine); int16_t perform_loop_loopne(v8086* machine, uint8_t opcode); int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode); +int16_t jump_on_condition(v8086* machine, uint8_t opcode, uint8_t width); #endif //MICROS_JUMP_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index 38be4a6c..c6bea97a 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -135,4 +135,66 @@ int16_t check_bounds(v8086* machine) if((*i < *lb) || (*i > *ub)) return BOUND_ERROR; } return OK; +} + +int16_t set_byte(v8086* machine, uint8_t opcode) +{ + uint8_t set_byte = 0; + switch(opcode & 0x0fu) + { + case 0: //JO + if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t* memory = (uint8_t*) get_memory_from_mode(machine, mod_rm, 8); + *memory = set_byte; + return OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/misc_operations.h b/os/kernel/src/v8086/operations/misc_operations.h index b1f289a3..4c048452 100644 --- a/os/kernel/src/v8086/operations/misc_operations.h +++ b/os/kernel/src/v8086/operations/misc_operations.h @@ -7,5 +7,6 @@ int16_t perform_group_4(v8086* machine); int16_t perform_group_5(v8086* machine); int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode); int16_t check_bounds(v8086* machine); +int16_t set_byte(v8086* machine, uint8_t opcode); #endif //MICROS_MISC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 37b56c8a..f152b56d 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -559,4 +559,38 @@ OPCODE_PROTO(two_byte_0fh){ if(machine->operations_0fh[opcode] == NULL) return UNDEFINED_OPCODE; return machine->operations_0fh[opcode](machine, secondary_opcode); -} \ No newline at end of file +} + +OPCODE_PROTO(jcc_l) +{ + return jump_on_condition(machine, opcode, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(setcc) +{ + return set_byte(machine, opcode); +} + +OPCODE_PROTO(push_fs) +{ + push_word(machine, machine->sregs.fs); + return OK; +} + +OPCODE_PROTO(pop_fs) +{ + machine->sregs.fs = pop_word(machine); + return OK; +} + +OPCODE_PROTO(push_gs) +{ + push_word(machine, machine->sregs.gs); + return OK; +} + +OPCODE_PROTO(pop_gs) +{ + machine->sregs.gs = pop_word(machine); + return OK; +} diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 869d1ba4..feef32ed 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -112,6 +112,13 @@ OPCODE_PROTO(enter); OPCODE_PROTO(leave); //386 2_bytes_protos 0x0f Prefix OPCODE_PROTO(two_byte_0fh); +OPCODE_PROTO(jcc_l); +OPCODE_PROTO(setcc); +OPCODE_PROTO(push_fs); +OPCODE_PROTO(pop_fs); +OPCODE_PROTO(push_gs); +OPCODE_PROTO(pop_gs); + #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 443430e9..60fa4e50 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -187,6 +187,15 @@ void v8086_set_386_instruction_set(v8086* machine) { machine->operations_0fh[i] = NULL; } + GROUP_OF_0FH_OPCODES(0x80u, 0x8fu, jcc_l); + GROUP_OF_0FH_OPCODES(0x90u, 0x9fu, setcc); + ASSIGN_0FH_OPCODE(0xa0u, push_fs); + ASSIGN_0FH_OPCODE(0xa1u, pop_fs); + + ASSIGN_0FH_OPCODE(0xa8u, push_gs); + ASSIGN_0FH_OPCODE(0xa9u, pop_gs); + + } From 9670aa4e2d4b0ae4ae43715f1dbfeb56e7d113c6 Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 14:09:38 +0200 Subject: [PATCH 076/165] Corrected ASM for 3-byte IMUL added new file --- .../v8086/operations/arithmetic_operations.c | 938 ++++++++---------- .../src/v8086/operations/bit_operations.c | 1 + .../src/v8086/operations/bit_operations.h | 4 + os/kernel/src/v8086/operations/opcodes.c | 1 + 4 files changed, 442 insertions(+), 502 deletions(-) create mode 100644 os/kernel/src/v8086/operations/bit_operations.c create mode 100644 os/kernel/src/v8086/operations/bit_operations.h diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 2da0580c..c6f069de 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -7,738 +7,673 @@ #include "arithmetic_operations.h" #include "internal_funcs.h" -int16_t perform_adding(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint64_t result = 0; uint32_t dest_before; //for overflow flag checking uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); + if (width == 8) { + dest_before = *((uint8_t *) dest); + source_before = *((uint8_t *) source); + } else if (width == 16) { + dest_before = *((uint16_t *) dest); + source_before = *((uint16_t *) source); + } else if (width == 32) { + dest_before = *((uint32_t *) dest); + source_before = *((uint32_t *) source); } else return BAD_WIDTH; result = dest_before + source_before + carry; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, + (((dest_before & 0xfu) + (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, + ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; else return BAD_WIDTH; return OK; } -int16_t perform_subtracting(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint64_t result = 0; uint32_t dest_before; //for overflow flag checking uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); + if (width == 8) { + dest_before = *((uint8_t *) dest); + source_before = *((uint8_t *) source); + } else if (width == 16) { + dest_before = *((uint16_t *) dest); + source_before = *((uint16_t *) source); + } else if (width == 32) { + dest_before = *((uint32_t *) dest); + source_before = *((uint32_t *) source); } else return BAD_WIDTH; result = dest_before - (source_before + carry); - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, + (((dest_before & 0xfu) - (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, + ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; else return BAD_WIDTH; return OK; } -int16_t perform_or(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) | *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) | *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) | *((uint32_t*)source); + if (width == 8) + result = *((uint8_t *) dest) | *((uint8_t *) source); + else if (width == 16) + result = *((uint16_t *) dest) | *((uint16_t *) source); + else if (width == 32) + result = *((uint32_t *) dest) | *((uint32_t *) source); else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; return OK; } -int16_t perform_and(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) & *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) & *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) & *((uint32_t*)source); + if (width == 8) + result = *((uint8_t *) dest) & *((uint8_t *) source); + else if (width == 16) + result = *((uint16_t *) dest) & *((uint16_t *) source); + else if (width == 32) + result = *((uint32_t *) dest) & *((uint32_t *) source); else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; return OK; } -int16_t perform_xor(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint32_t result = 0; - if(width == 8) - result = *((uint8_t*)dest) ^ *((uint8_t*)source); - else if(width == 16) - result = *((uint16_t*)dest) ^ *((uint16_t*)source); - else if(width == 32) - result = *((uint32_t*)dest) ^ *((uint32_t*)source); + if (width == 8) + result = *((uint8_t *) dest) ^ *((uint8_t *) source); + else if (width == 16) + result = *((uint16_t *) dest) ^ *((uint16_t *) source); + else if (width == 32) + result = *((uint32_t *) dest) ^ *((uint32_t *) source); else return BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; return OK; } -int16_t perform_cmp(v8086* machine, void* dest, void* source, uint8_t width, uint32_t carry) -{ +int16_t perform_cmp(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { uint64_t result = 0; uint32_t dest_before; //for overflow flag checking uint32_t source_before; - if(width == 8){ - dest_before = *((uint8_t*)dest); - source_before = *((uint8_t*)source); - } else if(width == 16){ - dest_before = *((uint16_t*)dest); - source_before = *((uint16_t*)source); - } else if(width == 32){ - dest_before = *((uint32_t*)dest); - source_before = *((uint32_t*)source); + if (width == 8) { + dest_before = *((uint8_t *) dest); + source_before = *((uint8_t *) source); + } else if (width == 16) { + dest_before = *((uint16_t *) dest); + source_before = *((uint16_t *) source); + } else if (width == 32) { + dest_before = *((uint32_t *) dest); + source_before = *((uint32_t *) source); } else return BAD_WIDTH; result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, + (((dest_before & 0xfu) - (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, + ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG return OK; } -int16_t perform_ror(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_ror(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags = 0; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_rol(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_rol(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("rolb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("rolw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("roll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_rcl(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_rcl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("rclb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("rclw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("rcll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("rclb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("rclw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("rcll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_rcr(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_rcr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("rcrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("rcrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("rcrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("rcrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("rcrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("rcrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_shl(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_shl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("shlb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("shlw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("shll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("shlb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("shlw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("shll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return OK; } -int16_t perform_shr(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_shr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("shrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("shrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("shrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("shrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("shrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("shrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return OK; } -int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) -{ +int16_t perform_sar(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if(arg == 0) return OK; - if(width == 8) - __asm__ __volatile__("sarb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); - else if(width == 16) - __asm__ __volatile__("sarw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); - else if(width == 32) - __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + if (arg == 0) return OK; + if (width == 8) + __asm__ __volatile__("sarb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + else if (width == 16) + __asm__ __volatile__("sarw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return BAD_WIDTH; - if(arg == 1) bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return OK; } -int16_t perform_neg(v8086* machine, void* source, uint8_t width) -{ +int16_t perform_neg(v8086 *machine, void *source, uint8_t width) { uint16_t temp_flags; - if(width == 8) - __asm__ __volatile__("negb %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) source)) : "a" (*((uint8_t*) source))); - else if(width == 16) - __asm__ __volatile__("negw %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) source)) : "a" (*((uint16_t*) source))); - else if(width == 32) - __asm__ __volatile__("negl %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) source)) : "a" (*((uint16_t*) source))); + if (width == 8) + __asm__ __volatile__("negb %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) source)) : "a" (*((uint8_t *) source))); + else if (width == 16) + __asm__ __volatile__("negw %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); + else if (width == 32) + __asm__ __volatile__("negl %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); else return BAD_WIDTH; - bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_multiplication(v8086* machine, void* source, uint8_t signed_mul, uint8_t width) -{ +int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, uint8_t width) { uint16_t temp_flags; - if(signed_mul) - { - if(width == 8) - { + if (signed_mul) { + if (width == 8) { __asm__ __volatile__( "movb %%dl, %%al; imul %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); - } - else if(width == 16) - { + } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; imul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); - } - else if(width == 32) - { + } else if (width == 32) { __asm__ __volatile__( "movl %%edx, %%eax; imul %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } - else return BAD_WIDTH; - } - else - { - if(width == 8) - { + } else return BAD_WIDTH; + } else { + if (width == 8) { __asm__ __volatile__( "movb %%dl, %%al; mul %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); - } - else if(width == 16) - { + } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; mul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); - } - else if(width == 32) - { + } else if (width == 32) { __asm__ __volatile__( "movl %%edx, %%eax; mul %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } - else return BAD_WIDTH; + } else return BAD_WIDTH; } - bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_multiplication_3_byte(v8086* machine, void* dest, void* source, void* imm, uint8_t signed_mul, uint8_t width, uint8_t second_width) -{ +int16_t +perform_multiplication_3_byte(v8086 *machine, void *dest, void *source, void *imm, uint8_t signed_mul, uint8_t width, + uint8_t second_width) { uint16_t temp_flags; - if(signed_mul) { - if (width == 16) { - if (second_width == 8) { - int8_t a_imm = *((int8_t*) imm); - __asm__ __volatile__( - "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else if(second_width == 16) - { - int16_t a_imm = *((int16_t*) imm); - __asm__ __volatile__( - "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else return BAD_WIDTH; - } - else if(width == 32) { - if (second_width == 8) { - int8_t a_imm = *((int8_t*) imm); - __asm__ __volatile__( - "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else if(second_width == 32) - { - int32_t a_imm = *((int32_t*) imm); - __asm__ __volatile__( - "imul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else return BAD_WIDTH; - } - else return BAD_WIDTH; - } - else{ - if (width == 16) { - if (second_width == 8) { - uint8_t a_imm = *((uint8_t*) imm); - __asm__ __volatile__( - "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else if(second_width == 16) - { - uint16_t a_imm = *((uint16_t*) imm); - __asm__ __volatile__( - "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else return BAD_WIDTH; - } - else if(width == 32) { - if (second_width == 8) { - uint8_t a_imm = *((uint8_t*) imm); - __asm__ __volatile__( - "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else if(second_width == 32) - { - uint32_t a_imm = *((uint32_t*) imm); - __asm__ __volatile__( - "mul %%ax, %%cx, a_imm; pushfw; pop %%bx;" - : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "c" (*((uint16_t *) source)) - ); - } - else return BAD_WIDTH; - } - else return BAD_WIDTH; - } - bit_write(machine->regs.w.flags, 1u <regs.w.flags, 1u <regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); return OK; } -int16_t perform_division(v8086* machine, void* source, uint8_t signed_div, uint8_t width) -{ +int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8_t width) { uint16_t temp_flags; - if(signed_div) - { - if(width == 8) - { + if (signed_div) { + if (width == 8) { __asm__ __volatile__( "movb %%dl, %%al; idiv %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); - } - else if(width == 16) - { + } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); - } - else if(width == 32) - { + } else if (width == 32) { __asm__ __volatile__( "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } - else return BAD_WIDTH; - } - else - { - if(width == 8) - { + } else return BAD_WIDTH; + } else { + if (width == 8) { __asm__ __volatile__( "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); - } - else if(width == 16) - { + } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); - } - else if(width == 32) - { + } else if (width == 32) { __asm__ __volatile__( "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t*) source)) + : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } - else return BAD_WIDTH; + } else return BAD_WIDTH; } return OK; } -int16_t perform_test(v8086* machine, void* source, void* dest, uint8_t width) -{ +int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { uint32_t result; - if(width == 8) - result = *((uint8_t*) source) & *((uint8_t*) dest); - else if(width == 16) - result = *((uint16_t*) source) & *((uint16_t*) dest); - else if(width == 32) - result = *((uint32_t*) source) & *((uint32_t*) dest); + if (width == 8) + result = *((uint8_t *) source) & *((uint8_t *) dest); + else if (width == 16) + result = *((uint16_t *) source) & *((uint16_t *) dest); + else if (width == 32) + result = *((uint32_t *) source) & *((uint32_t *) dest); else return BAD_WIDTH; uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG return OK; } -int16_t perform_inc(v8086* machine, void* dest, uint8_t width) -{ +int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { uint64_t result = 0; uint32_t dest_before; - if (width == 8) dest_before = *((uint8_t*) dest); - else if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); + if (width == 8) dest_before = *((uint8_t *) dest); + else if (width == 16) dest_before = *((uint16_t *) dest); + else if (width == 32) dest_before = *((uint32_t *) dest); else return BAD_WIDTH; result = dest_before + 1; uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, + (((dest_before & 0xfu) + 1u) >> 4u) ? 1 : 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, + ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; return OK; } -int16_t perform_dec(v8086* machine, void* dest, uint8_t width) -{ +int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { uint64_t result = 0; uint32_t dest_before; - if (width == 8) dest_before = *((uint8_t*) dest); - else if(width == 16) dest_before = *((uint16_t*)dest); - else if(width == 32) dest_before = *((uint32_t*)dest); + if (width == 8) dest_before = *((uint8_t *) dest); + else if (width == 16) dest_before = *((uint16_t *) dest); + else if (width == 32) dest_before = *((uint32_t *) dest); else return BAD_WIDTH; result = dest_before - 1; uint8_t parrity = result & 1u; - for(uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u <> 4u) ? 1: 0); //AUX CARRY FLAG - bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - - if(width == 8) *((uint8_t*)dest) = result & 0xFFu; - else if(width == 16) *((uint16_t*)dest) = result & 0xFFFFu; - else if(width == 32) *((uint32_t*)dest) = result & 0xFFFFFFFF; + for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG + bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, + (((dest_before & 0xfu) - 1u) >> 4u) ? 1 : 0); //AUX CARRY FLAG + bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, + ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + + if (width == 8) *((uint8_t *) dest) = result & 0xFFu; + else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; + else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; return OK; } -int16_t perform_artihmetic_or_logical_instruction(v8086* machine, uint8_t recalculated_opcode, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) -{ +int16_t perform_artihmetic_or_logical_instruction(v8086 *machine, uint8_t recalculated_opcode, uint32_t carry, + int16_t (*operation)(v8086 *, void *, void *, uint8_t, uint32_t)) { //Maybe Mod/RM, Can be Immediate - uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + uint8_t mod_rm_or_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t reg = get_reg(mod_rm_or_immediate); uint8_t width = 16; - void* source = NULL; - void* dest = NULL; - if(!(recalculated_opcode % 2)) width = 8; //Odd Opcode means 16 or 32 bit operands - else if(machine->internal_state.operand_32_bit) width = 32; - switch(recalculated_opcode) - { + void *source = NULL; + void *dest = NULL; + if (!(recalculated_opcode % 2)) width = 8; //Odd Opcode means 16 or 32 bit operands + else if (machine->internal_state.operand_32_bit) width = 32; + switch (recalculated_opcode) { case 0: //OPERATION r/m8, r8 source = get_byte_register(machine, reg); dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return UNABLE_GET_MEMORY; break; case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 source = get_variable_length_register(machine, reg, width); dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return UNABLE_GET_MEMORY; break; case 2: //OPERATION r8, r/m8 dest = get_byte_register(machine, reg); source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return UNDEFINED_REGISTER; + if (source == NULL) return UNABLE_GET_MEMORY; break; case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 dest = get_variable_length_register(machine, reg, width); source = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(source == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return UNDEFINED_REGISTER; + if (source == NULL) return UNABLE_GET_MEMORY; break; case 4: //OPERATION AL, imm8 dest = get_byte_register(machine, AL); source = &(mod_rm_or_immediate); - if(dest == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return UNDEFINED_REGISTER; break; case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 dest = get_variable_length_register(machine, AX, width); - if(dest == NULL) return UNDEFINED_REGISTER; - if(width == 32) - source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); + if (dest == NULL) return UNDEFINED_REGISTER; + if (width == 32) + source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip - 1 + + machine->internal_state.IPOffset)); else - source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + machine->internal_state.IPOffset)); + source = get_word_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip - 1 + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += ((width / 8) - 1); break; default: return UNDEFINED_RECALCULATED_OPCODE; } int16_t status = operation(machine, dest, source, width, carry); - if(status) return status; + if (status) return status; return OK; } -int16_t perform_arithmetic_or_logical_instruction_group(v8086* machine, uint8_t recalculated_opcode, uint8_t mod_rm, uint32_t carry, int16_t (*operation)(v8086*, void*, void*, uint8_t, uint32_t)) -{ - void* dest = NULL; + +int16_t perform_arithmetic_or_logical_instruction_group(v8086 *machine, uint8_t recalculated_opcode, uint8_t mod_rm, + uint32_t carry, + int16_t (*operation)(v8086 *, void *, void *, uint8_t, + uint32_t)) { + void *dest = NULL; uint8_t width; uint32_t immediate; int32_t signed_immediate; - switch(recalculated_opcode) - { + switch (recalculated_opcode) { case 0: //OPERATION rm8, imm8 case 2: //OPERATION rm8, imm8 width = 8; dest = get_memory_from_mode(machine, mod_rm, width); - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; break; case 1: //OPERATION rm16, imm16 or rm32, imm32 - if(machine->internal_state.operand_32_bit) { + if (machine->internal_state.operand_32_bit) { width = 32; - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; - } - else - { + } else { width = 16; - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; } dest = get_memory_from_mode(machine, mod_rm, width); break; case 3: //OPERATION rm16, imm8, or rm32, imm8 - if(machine->internal_state.operand_32_bit) width = 32; + if (machine->internal_state.operand_32_bit) width = 32; else width = 16; - signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; dest = get_memory_from_mode(machine, mod_rm, width); break; default: return UNDEFINED_RECALCULATED_OPCODE; } - if(dest == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return UNABLE_GET_MEMORY; int16_t status; - if(recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); + if (recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); else status = operation(machine, dest, &immediate, width, carry); - if(status) return status; + if (status) return status; return OK; } -int16_t perform_inc_dec(v8086* machine, uint8_t opcode, bool dec) -{ +int16_t perform_inc_dec(v8086 *machine, uint8_t opcode, bool dec) { uint8_t width = 16; - void* dest = NULL; - if(machine->internal_state.operand_32_bit) width=32; + void *dest = NULL; + if (machine->internal_state.operand_32_bit) width = 32; dest = get_variable_length_register(machine, opcode & 7u, width); - if(dest == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return UNDEFINED_REGISTER; - if(!dec) + if (!dec) return perform_inc(machine, dest, width); return perform_dec(machine, dest, width); } -int16_t execute_test(v8086* machine, uint8_t opcode) -{ +int16_t execute_test(v8086 *machine, uint8_t opcode) { //Mod/RM - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 8; - if(opcode % 2) + if (opcode % 2) width = machine->internal_state.operand_32_bit ? 32 : 16; - void* source = get_variable_length_register(machine, get_reg(mod_rm), width); - void* dest = get_memory_from_mode(machine, mod_rm, width); + void *source = get_variable_length_register(machine, get_reg(mod_rm), width); + void *dest = get_memory_from_mode(machine, mod_rm, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return UNABLE_GET_MEMORY; return perform_test(machine, source, dest, width); } -int16_t execute_test_immediate(v8086* machine, uint8_t opcode) -{ +int16_t execute_test_immediate(v8086 *machine, uint8_t opcode) { uint8_t width = 8; - if(opcode == 0xa9u) width = machine->internal_state.operand_32_bit ? 32 : 16; - void* immediate = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); + if (opcode == 0xa9u) width = machine->internal_state.operand_32_bit ? 32 : 16; + void *immediate = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset), + width); machine->internal_state.IPOffset += width / 8; - void* reg = get_variable_length_register(machine, AX, width); - if(immediate == NULL) return UNABLE_GET_MEMORY; - if(reg == NULL) return UNDEFINED_REGISTER; + void *reg = get_variable_length_register(machine, AX, width); + if (immediate == NULL) return UNABLE_GET_MEMORY; + if (reg == NULL) return UNDEFINED_REGISTER; return perform_test(machine, immediate, reg, width); } int16_t execute_group_2(v8086 *machine, uint8_t opcode) { - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - uint8_t arg = opcode <=0xd1 ? 1 : machine->regs.h.cl; + uint8_t arg = opcode <= 0xd1 ? 1 : machine->regs.h.cl; uint8_t width = 8; - if(opcode % 2){ - if(machine->internal_state.operand_32_bit) width = 32; + if (opcode % 2) { + if (machine->internal_state.operand_32_bit) width = 32; else width = 16; } - void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; - switch(get_reg(mod_rm)) - { + void *dest = get_memory_from_mode(machine, mod_rm, width); + if (dest == NULL) return UNABLE_GET_MEMORY; + switch (get_reg(mod_rm)) { case 0: return perform_rol(machine, dest, arg, width); case 1: @@ -760,51 +695,50 @@ int16_t execute_group_2(v8086 *machine, uint8_t opcode) { } } -int16_t execute_group_3(v8086* machine, uint8_t opcode) -{ - uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); +int16_t execute_group_3(v8086 *machine, uint8_t opcode) { + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t width = 8; - if(opcode == 0xf7) - { - if(machine->internal_state.operand_32_bit) width = 32; + if (opcode == 0xf7) { + if (machine->internal_state.operand_32_bit) width = 32; else width = 16; } - void* dest = get_memory_from_mode(machine, mod_rm, width); + void *dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return UNABLE_GET_MEMORY; - switch(get_reg(mod_rm)) - { + switch (get_reg(mod_rm)) { case 0: //TEST { uint32_t immediate; - if(width == 8) - { - immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 1; - } - else if(width == 16) - { - immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 2; - } - else if(width == 32) - { - immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine -> internal_state.IPOffset += 4; + if (width == 8) { + immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } else if (width == 16) { + immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; + } else if (width == 32) { + immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; } return perform_test(machine, &immediate, dest, width); break; } case 2: //NOT - if(width == 8) - *((uint8_t*)dest) = ~(*((uint8_t*)dest)); - else if(width == 16) - *((uint16_t*)dest) = ~(*((uint16_t*)dest)); - else if(width == 32) - *((uint32_t*)dest) = ~(*((uint32_t*)dest)); + if (width == 8) + *((uint8_t *) dest) = ~(*((uint8_t *) dest)); + else if (width == 16) + *((uint16_t *) dest) = ~(*((uint16_t *) dest)); + else if (width == 32) + *((uint32_t *) dest) = ~(*((uint32_t *) dest)); else return BAD_WIDTH; return OK; break; diff --git a/os/kernel/src/v8086/operations/bit_operations.c b/os/kernel/src/v8086/operations/bit_operations.c new file mode 100644 index 00000000..9f31f8a1 --- /dev/null +++ b/os/kernel/src/v8086/operations/bit_operations.c @@ -0,0 +1 @@ +#include "bit_operations.h" diff --git a/os/kernel/src/v8086/operations/bit_operations.h b/os/kernel/src/v8086/operations/bit_operations.h new file mode 100644 index 00000000..ab7369ad --- /dev/null +++ b/os/kernel/src/v8086/operations/bit_operations.h @@ -0,0 +1,4 @@ +#ifndef MICROS_BIT_OPERATIONS_H +#define MICROS_BIT_OPERATIONS_H + +#endif //MICROS_BIT_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index f152b56d..8063c77f 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -14,6 +14,7 @@ #include "string_operations.h" #include "io_operations.h" #include "misc_operations.h" +#include "bit_operations.h" #define NO_CARRY 0 #define CARRY_FLAG_AS_NUMBER bit_get(machine->regs.d.eflags, 1u <> CARRY_FLAG_BIT From 29cda3b7f339a314bf297b05466cf99c99b10bab Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 14:50:39 +0200 Subject: [PATCH 077/165] Added BT, BTS, BTR and BTC (nope, there is no Bitcoin). --- .../src/v8086/operations/bit_operations.c | 194 ++++++++++++++++++ .../src/v8086/operations/bit_operations.h | 8 + os/kernel/src/v8086/operations/opcodes.c | 25 +++ os/kernel/src/v8086/operations/opcodes.h | 5 + os/kernel/src/v8086/v8086.c | 9 + 5 files changed, 241 insertions(+) diff --git a/os/kernel/src/v8086/operations/bit_operations.c b/os/kernel/src/v8086/operations/bit_operations.c index 9f31f8a1..c1882308 100644 --- a/os/kernel/src/v8086/operations/bit_operations.c +++ b/os/kernel/src/v8086/operations/bit_operations.c @@ -1 +1,195 @@ +#include +#include #include "bit_operations.h" +#include "internal_funcs.h" + +int16_t bit_test(v8086* machine, uint8_t width) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 16) + { + uint16_t* memory = (uint16_t*) get_memory_from_mode(machine, mod_rm, width); + uint16_t* reg = (uint16_t*) get_variable_length_register(machine, get_reg(mod_rm), width); + + bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 16) + { + uint16_t* memory = (uint16_t*) get_memory_from_mode(machine, mod_rm, width); + uint16_t* reg = (uint16_t*) get_variable_length_register(machine, get_reg(mod_rm), width); + + bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 16) + { + uint16_t* memory = (uint16_t*) get_memory_from_mode(machine, mod_rm, width); + uint16_t* reg = (uint16_t*) get_variable_length_register(machine, get_reg(mod_rm), width); + + bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + if(width == 16) + { + uint16_t* memory = (uint16_t*) get_memory_from_mode(machine, mod_rm, width); + uint16_t* reg = (uint16_t*) get_variable_length_register(machine, get_reg(mod_rm), width); + + bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + switch(get_reg(mod_rm)) + { + case 4: // BT rm, imm8 + if(width == 16) + { + uint16_t* memory = (uint16_t*) get_memory_from_mode(machine, mod_rm, width); + uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + bit_write(machine->regs.w.flags, 1u<sregs.gs = pop_word(machine); return OK; } + +OPCODE_PROTO(bt) +{ + return bit_test(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(bts) +{ + return bit_test_set(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(btr) +{ + return bit_test_reset(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(btc) +{ + return bit_test_complement(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(group_8) +{ + return perform_group_8(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index feef32ed..ee9eee27 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -118,6 +118,11 @@ OPCODE_PROTO(push_fs); OPCODE_PROTO(pop_fs); OPCODE_PROTO(push_gs); OPCODE_PROTO(pop_gs); +OPCODE_PROTO(bt); +OPCODE_PROTO(bts); +OPCODE_PROTO(btr); +OPCODE_PROTO(btc); +OPCODE_PROTO(group_8); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 60fa4e50..6d37e91d 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -191,10 +191,19 @@ void v8086_set_386_instruction_set(v8086* machine) GROUP_OF_0FH_OPCODES(0x90u, 0x9fu, setcc); ASSIGN_0FH_OPCODE(0xa0u, push_fs); ASSIGN_0FH_OPCODE(0xa1u, pop_fs); + //NO CPUID in 386 + ASSIGN_NULL_0FH(0xa2u); + ASSIGN_0FH_OPCODE(0xa3u, bt); ASSIGN_0FH_OPCODE(0xa8u, push_gs); ASSIGN_0FH_OPCODE(0xa9u, pop_gs); + //NOT Defined in 386 + ASSIGN_NULL_0FH(0xaau); + ASSIGN_0FH_OPCODE(0xabu, bts); + ASSIGN_0FH_OPCODE(0xb3u, btr); + ASSIGN_0FH_OPCODE(0xbau, group_8); + ASSIGN_0FH_OPCODE(0xbbu, btc); } From 6076f87950a0985dd08fcaa3ace6881517047d63 Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 16:42:07 +0200 Subject: [PATCH 078/165] Added SHRD and SHLD, and 2 Byte IMUL --- .../v8086/operations/arithmetic_operations.c | 50 ++++++++++++++++--- .../v8086/operations/arithmetic_operations.h | 1 + os/kernel/src/v8086/operations/opcodes.c | 31 ++++++++++++ os/kernel/src/v8086/operations/opcodes.h | 6 +++ os/kernel/src/v8086/v8086.c | 12 ++++- 5 files changed, 92 insertions(+), 8 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index c6f069de..272df82b 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -269,15 +269,30 @@ int16_t perform_shr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { return OK; } -int16_t perform_sar(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { +int16_t perform_shld(v8086 *machine, void *rm, void* reg, uint8_t arg, uint8_t width) { uint16_t temp_flags; if (arg == 0) return OK; - if (width == 8) - __asm__ __volatile__("sarb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); - else if (width == 16) - __asm__ __volatile__("sarw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + if (width == 16) + __asm__ __volatile__("shldw %%cl, %%dx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint16_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); else if (width == 32) - __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); + __asm__ __volatile__("shld %%cl, %%edx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint32_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); + else return BAD_WIDTH; + if (arg == 1) + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + return OK; +} + +int16_t perform_shrd(v8086 *machine, void *rm, void* reg, uint8_t arg, uint8_t width) { + uint16_t temp_flags; + if (arg == 0) return OK; + if (width == 16) + __asm__ __volatile__("shrdw %%cl, %%dx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint16_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); + else if (width == 32) + __asm__ __volatile__("shrd %%cl, %%edx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint32_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); else return BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); @@ -756,3 +771,26 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { return BAD_REG; } } + +int16_t execute_double_shift(v8086* machine, uint8_t width, uint8_t right_shift, uint8_t use_cl) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + + void* reg = get_variable_length_register(machine, get_reg(mod_rm), width); + void* rm = get_memory_from_mode(machine, mod_rm, width); + uint8_t imm; + if(use_cl) + imm = machine->regs.h.cl; + else{ + imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } + + if(right_shift) + return perform_shrd(machine, rm, reg, imm, width); + else + return perform_shld(machine, rm, reg, imm, width); +} diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.h b/os/kernel/src/v8086/operations/arithmetic_operations.h index 86ef1e50..aedcf3d6 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.h +++ b/os/kernel/src/v8086/operations/arithmetic_operations.h @@ -31,5 +31,6 @@ int16_t execute_test(v8086* machine, uint8_t opcode); int16_t execute_test_immediate(v8086* machine, uint8_t opcode); int16_t execute_group_2(v8086* machine, uint8_t opcode); int16_t execute_group_3(v8086* machine, uint8_t opcode); +int16_t execute_double_shift(v8086* machine, uint8_t width, uint8_t right_shift, uint8_t use_cl); #endif //V8086_ARITHMETIC_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 38e3677a..3c6e0296 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -620,3 +620,34 @@ OPCODE_PROTO(group_8) { return perform_group_8(machine, machine->internal_state.operand_32_bit ? 32 : 16); } + +OPCODE_PROTO(shld_imm) +{ + return execute_double_shift(machine, machine->internal_state.operand_32_bit ? 32 : 16, 0, 0); +} + +OPCODE_PROTO(shld_cl) +{ + return execute_double_shift(machine, machine->internal_state.operand_32_bit ? 32 : 16, 0, 1); +} + +OPCODE_PROTO(shrd_imm) +{ + return execute_double_shift(machine, machine->internal_state.operand_32_bit ? 32 : 16, 1, 0); +} + +OPCODE_PROTO(shrd_cl) +{ + return execute_double_shift(machine, machine->internal_state.operand_32_bit ? 32 : 16, 1, 1); +} + +OPCODE_PROTO(imul_2_byte) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = machine->internal_state.operand_32_bit ? 32 : 16; + void* mem_or_reg = get_memory_from_mode(machine, mod_rm, width); + void* reg = get_variable_length_register(machine, get_reg(mod_rm), width); + + return perform_multiplication_3_byte(machine, reg, reg, mem_or_reg, 1, width, width); +} diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index ee9eee27..c7aa41d3 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -123,6 +123,12 @@ OPCODE_PROTO(bts); OPCODE_PROTO(btr); OPCODE_PROTO(btc); OPCODE_PROTO(group_8); +OPCODE_PROTO(shld_imm); +OPCODE_PROTO(shld_cl); +OPCODE_PROTO(shrd_imm); +OPCODE_PROTO(shrd_cl); +OPCODE_PROTO(imul_2_byte); + diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 6d37e91d..6d26bb82 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -194,13 +194,21 @@ void v8086_set_386_instruction_set(v8086* machine) //NO CPUID in 386 ASSIGN_NULL_0FH(0xa2u); ASSIGN_0FH_OPCODE(0xa3u, bt); - + ASSIGN_0FH_OPCODE(0xa4u, shld_imm); + ASSIGN_0FH_OPCODE(0xa5u, shld_cl); + //Not Defined in 386; + ASSIGN_NULL_0FH(0xa6u); + ASSIGN_NULL_0FH(0xa7u); ASSIGN_0FH_OPCODE(0xa8u, push_gs); ASSIGN_0FH_OPCODE(0xa9u, pop_gs); //NOT Defined in 386 ASSIGN_NULL_0FH(0xaau); ASSIGN_0FH_OPCODE(0xabu, bts); - + ASSIGN_0FH_OPCODE(0xacu, shrd_imm); + ASSIGN_0FH_OPCODE(0xadu, shrd_cl); + //NOT Defined in 386 + ASSIGN_NULL(0xaeu); + ASSIGN_0FH_OPCODE(0xafu, imul_2_byte); ASSIGN_0FH_OPCODE(0xb3u, btr); ASSIGN_0FH_OPCODE(0xbau, group_8); ASSIGN_0FH_OPCODE(0xbbu, btc); From 51ae32873bb70ddfcffd70917f7f6f787b21286d Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 16:53:54 +0200 Subject: [PATCH 079/165] Added LSS LFS LGF --- .../src/v8086/operations/mov_operations.c | 5 ++--- .../src/v8086/operations/mov_operations.h | 2 +- os/kernel/src/v8086/operations/opcodes.c | 19 +++++++++++++++++-- os/kernel/src/v8086/operations/opcodes.h | 4 +++- os/kernel/src/v8086/v8086.c | 8 +++++++- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index d6ac5fd7..ee001a0e 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -208,14 +208,13 @@ int16_t load_flags(v8086* machine) return OK; } -int16_t perform_lds_les(v8086* machine, uint8_t les_op) +int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment_op) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint16_t* segment_register; - if(les_op) segment_register = select_segment_register(machine, ES); - else segment_register = select_segment_register(machine, DS); + segment_register = select_segment_register(machine, segment_op); if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); if(source == NULL) return UNABLE_GET_MEMORY; diff --git a/os/kernel/src/v8086/operations/mov_operations.h b/os/kernel/src/v8086/operations/mov_operations.h index 2f8c0da8..2b719280 100644 --- a/os/kernel/src/v8086/operations/mov_operations.h +++ b/os/kernel/src/v8086/operations/mov_operations.h @@ -13,7 +13,7 @@ int16_t convert_byte_to_word(v8086* machine); int16_t convert_word_to_double(v8086* machine); int16_t store_flags(v8086* machine); int16_t load_flags(v8086* machine); -int16_t perform_lds_les(v8086* machine, uint8_t les_op); +int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment_op); int16_t perform_xlat(v8086* machine); #endif //MICROS_MOV_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 3c6e0296..3b5741fe 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -316,12 +316,12 @@ OPCODE_PROTO(retn_imm) OPCODE_PROTO(les) { - return perform_lds_les(machine, 1); + return perform_load_far_pointer(machine, ES); } OPCODE_PROTO(lds) { - return perform_lds_les(machine, 0); + return perform_load_far_pointer(machine, DS); } OPCODE_PROTO(mov_rm_imm) @@ -651,3 +651,18 @@ OPCODE_PROTO(imul_2_byte) return perform_multiplication_3_byte(machine, reg, reg, mem_or_reg, 1, width, width); } + +OPCODE_PROTO(lss) +{ + return perform_load_far_pointer(machine, SS); +} + +OPCODE_PROTO(lfs) +{ + return perform_load_far_pointer(machine, FS); +} + +OPCODE_PROTO(lgs) +{ + return perform_load_far_pointer(machine, GS); +} diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index c7aa41d3..63f23ec4 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -128,7 +128,9 @@ OPCODE_PROTO(shld_cl); OPCODE_PROTO(shrd_imm); OPCODE_PROTO(shrd_cl); OPCODE_PROTO(imul_2_byte); - +OPCODE_PROTO(lss); +OPCODE_PROTO(lfs); +OPCODE_PROTO(lgs); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 6d26bb82..dd8a606c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -207,9 +207,15 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_0FH_OPCODE(0xacu, shrd_imm); ASSIGN_0FH_OPCODE(0xadu, shrd_cl); //NOT Defined in 386 - ASSIGN_NULL(0xaeu); + ASSIGN_NULL_0FH(0xaeu); ASSIGN_0FH_OPCODE(0xafu, imul_2_byte); + //NOT Defined in 386 + ASSIGN_NULL_0FH(0xb0u); + ASSIGN_NULL_0FH(0xb1u); + ASSIGN_0FH_OPCODE(0xb2u, lss); ASSIGN_0FH_OPCODE(0xb3u, btr); + ASSIGN_0FH_OPCODE(0xb4u, lfs); + ASSIGN_0FH_OPCODE(0xb5u, lgs); ASSIGN_0FH_OPCODE(0xbau, group_8); ASSIGN_0FH_OPCODE(0xbbu, btc); From 262ff4d37e8793f558527883e0838aa34aa430b3 Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 23:04:03 +0200 Subject: [PATCH 080/165] Added MOVZX, MOVSX, BSF and BSR... So next step is debugging... Very lovely... --- .../src/v8086/operations/bit_operations.c | 72 ++++++++++++++++ .../src/v8086/operations/bit_operations.h | 2 + .../src/v8086/operations/mov_operations.c | 82 +++++++++++++++++++ .../src/v8086/operations/mov_operations.h | 2 + os/kernel/src/v8086/operations/opcodes.c | 20 +++++ os/kernel/src/v8086/operations/opcodes.h | 5 ++ os/kernel/src/v8086/v8086.c | 10 +++ 7 files changed, 193 insertions(+) diff --git a/os/kernel/src/v8086/operations/bit_operations.c b/os/kernel/src/v8086/operations/bit_operations.c index c1882308..0484eee2 100644 --- a/os/kernel/src/v8086/operations/bit_operations.c +++ b/os/kernel/src/v8086/operations/bit_operations.c @@ -192,4 +192,76 @@ int16_t perform_group_8(v8086* machine, uint8_t width) default: return UNDEFINED_OPCODE; } +} + +int16_t bit_scan_forward(v8086* machine, uint8_t width) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + void* dest = get_variable_length_register(machine, get_reg(mod_rm), width); + void* source = get_memory_from_mode(machine, mod_rm, width); + + if(width == 16) + { + uint16_t s = *((uint16_t*) source); + if(s == 0) + { + bit_set(machine->regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + void* dest = get_variable_length_register(machine, get_reg(mod_rm), width); + void* source = get_memory_from_mode(machine, mod_rm, width); + + if(width == 16) + { + uint16_t s = *((uint16_t*) source); + if(s == 0) + { + bit_set(machine->regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 32; + if(!(opcode % 2)) + width = machine->internal_state.operand_32_bit ? 32 : 16; + void* dest = get_variable_length_register(machine, get_reg(mod_rm), width); + + if(opcode == 0xb6u) + { + void* source = get_memory_from_mode(machine, mod_rm, 8); + return perform_movzx_variable_length(source, dest, 8, width); + } + else if(opcode == 0xb7u) + { + void* source = get_memory_from_mode(machine, mod_rm, 16); + return perform_movzx_variable_length(source, dest, 16, width); + } + else return UNKNOWN_ERROR; +} + +int16_t perform_movsx(v8086* machine, uint8_t opcode) +{ + uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + uint8_t width = 32; + if(!(opcode % 2)) + width = machine->internal_state.operand_32_bit ? 32 : 16; + void* dest = get_variable_length_register(machine, get_reg(mod_rm), width); + + if(opcode == 0xbeu) + { + void* source = get_memory_from_mode(machine, mod_rm, 8); + return perform_movsx_variable_length(source, dest, 8, width); + } + else if(opcode == 0xbfu) + { + void* source = get_memory_from_mode(machine, mod_rm, 16); + return perform_movsx_variable_length(source, dest, 16, width); + } + else return UNKNOWN_ERROR; +} + int16_t perform_mov_segment(v8086* machine, uint8_t opcode) { uint8_t mod_rm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); diff --git a/os/kernel/src/v8086/operations/mov_operations.h b/os/kernel/src/v8086/operations/mov_operations.h index 2b719280..b0fe2264 100644 --- a/os/kernel/src/v8086/operations/mov_operations.h +++ b/os/kernel/src/v8086/operations/mov_operations.h @@ -15,5 +15,7 @@ int16_t store_flags(v8086* machine); int16_t load_flags(v8086* machine); int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment_op); int16_t perform_xlat(v8086* machine); +int16_t perform_movzx(v8086* machine, uint8_t opcode); +int16_t perform_movsx(v8086* machine, uint8_t opcode); #endif //MICROS_MOV_OPERATIONS_H diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 3b5741fe..2d74daa7 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -666,3 +666,23 @@ OPCODE_PROTO(lgs) { return perform_load_far_pointer(machine, GS); } + +OPCODE_PROTO(movzx) +{ + return perform_movzx(machine, opcode); +} + +OPCODE_PROTO(movsx) +{ + return perform_movsx(machine, opcode); +} + +OPCODE_PROTO(bsf) +{ + return bit_scan_forward(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} + +OPCODE_PROTO(bsr) +{ + return bit_scan_backward(machine, machine->internal_state.operand_32_bit ? 32 : 16); +} diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 63f23ec4..4d1b5747 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -131,6 +131,11 @@ OPCODE_PROTO(imul_2_byte); OPCODE_PROTO(lss); OPCODE_PROTO(lfs); OPCODE_PROTO(lgs); +OPCODE_PROTO(movzx); +OPCODE_PROTO(movsx); +OPCODE_PROTO(bsf); +OPCODE_PROTO(bsr); + diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index dd8a606c..9f7e2e08 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -216,8 +216,18 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_0FH_OPCODE(0xb3u, btr); ASSIGN_0FH_OPCODE(0xb4u, lfs); ASSIGN_0FH_OPCODE(0xb5u, lgs); + ASSIGN_0FH_OPCODE(0xb6u, movzx); // BYTE MOVZX + ASSIGN_0FH_OPCODE(0xb7u, movzx); // WORD MOVZX + //NOT defined in 386 + ASSIGN_NULL_0FH(0xb8u); + ASSIGN_NULL_0FH(0xb9u); ASSIGN_0FH_OPCODE(0xbau, group_8); ASSIGN_0FH_OPCODE(0xbbu, btc); + ASSIGN_0FH_OPCODE(0xbcu, bsf); + ASSIGN_0FH_OPCODE(0xbdu, bsr); + ASSIGN_0FH_OPCODE(0xbeu, movsx); // BYTE MOVSX + ASSIGN_0FH_OPCODE(0xbfu, movsx); //BYTE MOVSX + } From 4e84e12340936d224887e93f14572da0125225d4 Mon Sep 17 00:00:00 2001 From: SzateX Date: Mon, 3 Aug 2020 23:10:06 +0200 Subject: [PATCH 081/165] Restore accidentaly removed perform_sar function --- .../v8086/operations/arithmetic_operations.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 272df82b..8bb2da35 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -269,6 +269,25 @@ int16_t perform_shr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { return OK; } +int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) +{ + uint16_t temp_flags; + if(arg == 0) return 0; + if(width == 8) + __asm__ __volatile__("sarb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t*) dest)) : "a" (*((uint8_t*) dest)), "c" (arg)); + else if(width == 16) + __asm__ __volatile__("sarw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t*) dest)) : "a" (*((uint16_t*) dest)), "c" (arg)); + else if(width == 32) + __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); + else return -1; + if(arg == 1) bit_write(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1< Date: Mon, 3 Aug 2020 23:10:55 +0200 Subject: [PATCH 082/165] Cleaned some warnings. --- os/kernel/src/v8086/operations/arithmetic_operations.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 8bb2da35..90141383 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -280,11 +280,11 @@ int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) else if(width == 32) __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); else return -1; - if(arg == 1) bit_write(machine->regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u< Date: Tue, 4 Aug 2020 23:23:52 +0200 Subject: [PATCH 083/165] [Fuck] - HDD --- os/kernel/src/kernel.c | 350 +---------------------- os/kernel/src/v8086/operations/opcodes.c | 6 +- os/kernel/src/v8086/v8086.c | 5 +- os/kernel/src/v8086/v8086.h | 4 +- 4 files changed, 20 insertions(+), 345 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 37c84271..5ec4609c 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -393,23 +393,20 @@ int kmain() vga_clear_screen(); switch_active_terminal(0); - + + //process_manager_run(); + v8086* v8086 = v8086_create_machine(); + v8086_set_386_instruction_set(v8086); + + filesystem_create_file("B:/DUMP.BIN"); + bool dupa = filesystem_save_to_file("B:/DUMP.BIN", (char*) v8086->Memory, 0x100000); + + v8086->regs.h.ah = 0x00; v8086->regs.h.al = 0x13; int16_t status = v8086_call_int(v8086, 0x10); - // terminal_manager_print_string(p, "CIASTKO"); - // p = process_manager_create_process("A:/ENV/SHELL.ELF", "", 1000, false); - // attach_process_to_terminal(ts[0].terminal_id, process_manager_get_process(p)); - // terminal_manager_print_string(p, "KARMEL"); - // p = process_manager_create_process("A:/ENV/SHELL.ELF", "", 1000, false); - // attach_process_to_terminal(ts[1].terminal_id, process_manager_get_process(p)); - // terminal_manager_print_string(p, "CZEKOLAAAAAAAAADA!"); - //terminal_manager_print_string(ts[1].active_process->id, "KARMAEL"); - //terminal_manager_print_string(ts[2].active_process->id, "CZEKOLADA!"); - //process_manager_run(); - //destroy_active_terminal(); - char str[100] = ""; + /*char str[100] = ""; vga_printstring("IP: "); uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); uint16_t CS = *(uint16_t*)(v8086->Memory + 0x10 * 4 + 2); @@ -426,332 +423,7 @@ int kmain() itoa(mem, str, 16); vga_printstring(str); vga_printstring(" "); - } + }*/ while (1); - // { - // sleep(5000); - // next_terminal(); - // - // } - // ; - /*char buff[50]; - video_mode *currentMode; - srand(clock()); - char shouldDrawLines = 0; - char screenSaver = 0; - while (1) - { - if (!keyboard_is_buffer_empty()) - { - keyboard_scan_ascii_pair c; - keyboard_get_key_from_buffer(&c); - if (c.scancode == 59) //F1 - { - video_card_set_video_mode(0x3); - logger_log_ok("UDALO SIE WSKOCZYC na 0x03\n"); - currentMode = video_card_get_current_video_mode(); - vga_printstring("Szerokosc Trybu: "); - itoa(currentMode->width, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("Wysokosc Trybu: "); - itoa(currentMode->height, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("Ilosc Kolorow: "); - itoa(currentMode->colors, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("Monochromatyczny: "); - itoa(currentMode->monochrome, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("Pamiec platowa: "); - itoa(currentMode->planar, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("-------TESTY INNYCH FUNKCJI-------:\n"); - vga_printstring("Czy tekstowy: "); - itoa(video_card_is_text_mode(), buff, 10); - vga_printstring(buff); - vga_newline(); - } - else if (c.scancode == 60) //F2 - { - video_card_set_video_mode(0x03); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - } - else if (c.scancode == 2) //1 - { - video_card_set_video_mode(0x04); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x02, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 61) //F3 - { - video_card_set_video_mode(0x05); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x03, x, y); - } - else if (c.scancode == 3) //2 - { - video_card_set_video_mode(0x05); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 62) //F4 - { - video_card_set_video_mode(0x06); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - } - else if (c.scancode == 4) //3 - { - video_card_set_video_mode(0x06); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 63) //F5 - { - video_card_set_video_mode(0x0d); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x04, x, y); - } - else if (c.scancode == 5) //4 - { - video_card_set_video_mode(0x0d); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x05, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 64) //F6 - { - video_card_set_video_mode(0x0e); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x06, x, y); - } - else if (c.scancode == 6) //5 - { - video_card_set_video_mode(0x0e); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x07, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 65) //F7 - { - video_card_set_video_mode(0x0f); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - } - else if (c.scancode == 7) //6 - { - video_card_set_video_mode(0x0f); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x02, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 66) //F8 - { - video_card_set_video_mode(0x10); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x08, x, y); - } - else if (c.scancode == 8) //7 - { - video_card_set_video_mode(0x10); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x09, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 67) //F9 - { - video_card_set_video_mode(0x11); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - } - else if (c.scancode == 9) //8 - { - video_card_set_video_mode(0x11); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x01, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 68) //F10 - { - video_card_set_video_mode(0x12); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x0A, x, y); - } - else if (c.scancode == 10) //9 - { - video_card_set_video_mode(0x12); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x0B, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 87) //F11 - { - video_card_set_video_mode(0x13); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x10, x, y); - } - else if (c.scancode == 11) //0 - { - video_card_set_video_mode(0x13); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x25, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 88) //F12 - { - video_card_set_video_mode(0x69); - currentMode = video_card_get_current_video_mode(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x45, x, y); - } - else if (c.scancode == 12) //- - { - video_card_set_video_mode(0x69); - currentMode = video_card_get_current_video_mode(); - video_card_turn_on_buffer(); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(0x8, x, y); - video_card_swap_buffers(); - } - else if (c.scancode == 01) //ESC - { - video_card_clear_screen(); - if (video_card_is_buffer_on()) - video_card_swap_buffers(); - } - else if (c.scancode == 15) // TAB - { - currentMode = video_card_get_current_video_mode(); - uint8_t color = (rand() % (currentMode->colors - 1) + 1); - for (uint32_t x = 0; x < currentMode->width; x++) - for (uint32_t y = 0; y < currentMode->height; y++) - video_card_draw_pixel(color, x, y); - if (video_card_is_buffer_on()) - video_card_swap_buffers(); - } - else if (c.scancode == 26) //[ - { - video_card_turn_on_buffer(); - } - else if (c.scancode == 27) //] - { - video_card_turn_off_buffer(); - } - else if (c.scancode == 41) //` - { - screenSaver = 0; - shouldDrawLines = !shouldDrawLines; - } - else if (c.scancode == 13) //= - { - shouldDrawLines = 0; - screenSaver = !screenSaver; - } - else - { - if (video_card_is_text_mode()) - vga_printchar(c.ascii); - } - } - if (shouldDrawLines) - { - currentMode = video_card_get_current_video_mode(); - uint8_t color = (rand() % (currentMode->colors - 1) + 1); - uint16_t ax = (rand() % (currentMode->width)); - uint16_t ay = (rand() % (currentMode->height)); - uint16_t bx = (rand() % (currentMode->width)); - uint16_t by = (rand() % (currentMode->height)); - video_card_draw_line(color, ax, ay, bx, by); - if (video_card_is_buffer_on()) - video_card_swap_buffers(); - } - if (screenSaver) - { - if (video_card_is_buffer_on()) - { - linesStruct s; - currentMode = video_card_get_current_video_mode(); - s.color = (rand() % (currentMode->colors - 1) + 1); - //s.ax = (rand() % (currentMode->width)); - //s.ay = (rand() % (currentMode->height)); - s.ax = ssBuffer[63].bx; - s.ay = ssBuffer[63].by; - s.bx = (rand() % (currentMode->width)); - s.by = (rand() % (currentMode->height)); - video_card_clear_screen(); - for (int i = 0; i < 64; i++) - { - video_card_draw_line(ssBuffer[i].color, ssBuffer[i].ax, ssBuffer[i].ay, ssBuffer[i].bx, ssBuffer[i].by); - if (i) - ssBuffer[i - 1] = ssBuffer[i]; - } - ssBuffer[63] = s; - //video_card_draw_line(color, ax, ay, bx, by); - video_card_swap_buffers(); - } - } - } - */ return 0; } diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 2d74daa7..551869a7 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -113,7 +113,7 @@ OPCODE_PROTO(aaa) OPCODE_PROTO(cmp) { - return perform_artihmetic_or_logical_instruction(machine, opcode - 0x30, NO_CARRY, perform_cmp); + return perform_artihmetic_or_logical_instruction(machine, opcode - 0x38, NO_CARRY, perform_cmp); } OPCODE_PROTO(aas) @@ -557,9 +557,9 @@ OPCODE_PROTO(two_byte_0fh){ secondary_opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - if(machine->operations_0fh[opcode] == NULL) return UNDEFINED_OPCODE; + if(machine->operations_0fh[secondary_opcode] == NULL) return UNDEFINED_OPCODE; - return machine->operations_0fh[opcode](machine, secondary_opcode); + return machine->operations_0fh[secondary_opcode](machine, secondary_opcode); } OPCODE_PROTO(jcc_l) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 9f7e2e08..860f8f44 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -135,6 +135,8 @@ void v8086_set_8086_instruction_set(v8086* machine) { machine->operations_0fh[i] = NULL; } + + machine->is_compatibility = IS8086; } void v8086_set_386_instruction_set(v8086* machine) @@ -228,8 +230,7 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_0FH_OPCODE(0xbeu, movsx); // BYTE MOVSX ASSIGN_0FH_OPCODE(0xbfu, movsx); //BYTE MOVSX - - + machine->is_compatibility = IS386; } v8086* v8086_create_machine() diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index de043ac6..2efba613 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -150,10 +150,12 @@ typedef struct _v8086 enum instruction_set_compatibility is_compatibility; int16_t (*operations[256]) (struct _v8086*, uint8_t); int16_t (*operations_0fh[256]) (struct _v8086*, uint8_t); + } v8086; v8086* v8086_create_machine(); int16_t v8086_call_int(v8086* machine, int16_t num); - +void v8086_set_8086_instruction_set(v8086* machine); +void v8086_set_386_instruction_set(v8086* machine); #endif \ No newline at end of file From d6dfbaf661fcf76db47c294174027c33bf8ff901 Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Wed, 5 Aug 2020 00:03:16 +0200 Subject: [PATCH 084/165] HDD fix --- os/kernel/src/drivers/harddisk/ata/harddisk_ata.c | 6 +----- .../src/filesystems/partitions/hdd_wrapper/hdd_wrapper.c | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c index cacdde9e..b7d6c3bb 100644 --- a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c +++ b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c @@ -179,7 +179,7 @@ int8_t __harddisk_ata_poll(uint16_t control_port) for(;;) { result.value = io_in_byte(control_port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET); - if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1) + if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1 || result.fields.overlapped_mode_service_request == 1) { return 1; } @@ -187,10 +187,6 @@ int8_t __harddisk_ata_poll(uint16_t control_port) { return -1; } - if(result.value == 0x50) - { - return 0; - } } } diff --git a/os/kernel/src/filesystems/partitions/hdd_wrapper/hdd_wrapper.c b/os/kernel/src/filesystems/partitions/hdd_wrapper/hdd_wrapper.c index 05e9f24d..b4fbea37 100644 --- a/os/kernel/src/filesystems/partitions/hdd_wrapper/hdd_wrapper.c +++ b/os/kernel/src/filesystems/partitions/hdd_wrapper/hdd_wrapper.c @@ -53,6 +53,6 @@ void hdd_wrapper_write_sector(int device_number, int sector, uint8_t *content) case -2: logger_log_error("harddisk_read_sector returned -2 - parameters error"); break; } - uint32_t current_time = timer_get_system_clock(); - while(timer_get_system_clock() - current_time < 15); + //uint32_t current_time = timer_get_system_clock(); + //while(timer_get_system_clock() - current_time < 15); } \ No newline at end of file From eca47f4d96875e96db4d1933687478a917a70edd Mon Sep 17 00:00:00 2001 From: SzateX Date: Thu, 6 Aug 2020 15:01:52 +0200 Subject: [PATCH 085/165] [Fuck] - Divide by zero - and corrected some mistakes --- os/kernel/src/kernel.c | 20 ++++++++++++++----- os/kernel/src/v8086/mod_rm_parsing.c | 2 +- .../v8086/operations/arithmetic_operations.c | 13 ++++++++++++ .../operations/ascii_adjustments_operations.c | 1 + .../src/v8086/operations/jump_operations.c | 5 +++-- os/kernel/src/v8086/v8086.c | 20 +++++++++++++++---- os/kernel/src/v8086/v8086.h | 2 ++ 7 files changed, 51 insertions(+), 12 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 5ec4609c..52228017 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -399,14 +399,24 @@ int kmain() v8086* v8086 = v8086_create_machine(); v8086_set_386_instruction_set(v8086); - filesystem_create_file("B:/DUMP.BIN"); - bool dupa = filesystem_save_to_file("B:/DUMP.BIN", (char*) v8086->Memory, 0x100000); + //filesystem_create_file("A:/DUMP.BIN"); + //bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); + //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); v8086->regs.h.ah = 0x00; v8086->regs.h.al = 0x13; - int16_t status = v8086_call_int(v8086, 0x10); - /*char str[100] = ""; + //int16_t status = v8086_call_int(v8086, 0x10); + //__asm__ __volatile__( + //"mov %%dx, %%ax; pushfw;" + //: : "d" (v8086->regs.w.ax) + //); + int16_t temp_flags; + __asm__ __volatile__( + "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (v8086->regs.d.eax), "=d"(v8086->regs.d.edx) : "d" (0x5000), "c" (0xa) + ); + char str[100] = ""; vga_printstring("IP: "); uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); uint16_t CS = *(uint16_t*)(v8086->Memory + 0x10 * 4 + 2); @@ -423,7 +433,7 @@ int kmain() itoa(mem, str, 16); vga_printstring(str); vga_printstring(" "); - }*/ + } while (1); return 0; } diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index daecb4b8..bd949336 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -170,7 +170,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 return OK; case 6:{ *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + (machine->internal_state.IPOffset))); - machine->internal_state.IPOffset += 1; + machine->internal_state.IPOffset += 2; return OK; } case 7: diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 90141383..b4b05c01 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -426,16 +426,19 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 uint16_t temp_flags; if (signed_div) { if (width == 8) { + if(*((uint8_t *) source) == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movb %%dl, %%al; idiv %%cl; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); } else if (width == 16) { + if(*((uint16_t *) source) == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { + if(*((uint32_t *) source) == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) @@ -443,16 +446,20 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 } else return BAD_WIDTH; } else { if (width == 8) { + if(*((uint8_t *) source) == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); } else if (width == 16) { + if(*((uint16_t *) source) == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { + uint32_t temp = *((uint32_t *) source); + if(temp == 0) return DIVISION_BY_ZERO; __asm__ __volatile__( "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) @@ -706,6 +713,12 @@ int16_t execute_group_2(v8086 *machine, uint8_t opcode) { else width = 16; } void *dest = get_memory_from_mode(machine, mod_rm, width); + if((opcode & 0xf0u) == 0xc0u) + { + arg = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; + } if (dest == NULL) return UNABLE_GET_MEMORY; switch (get_reg(mod_rm)) { case 0: diff --git a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c index 0b41dfb5..17aeff35 100644 --- a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c +++ b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c @@ -63,6 +63,7 @@ int16_t adjust_after_mul_div(v8086* machine, bool div) uint8_t tempAH = machine->regs.h.ah; if(!div) { + if(immediate == 0) return DIVISION_BY_ZERO; machine->regs.h.ah = tempAL / immediate; machine->regs.h.al = tempAL % immediate; } diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c index d371ca24..32b35092 100644 --- a/os/kernel/src/v8086/operations/jump_operations.c +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -42,7 +42,7 @@ int16_t jump_long_relative(v8086* machine, uint8_t width) int16_t jump_near_relative(v8086* machine) { int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; + machine->internal_state.IPOffset += 2; machine->IP.w.ip += offset; return OK; } @@ -50,8 +50,9 @@ int16_t jump_near_relative(v8086* machine) int16_t jump_far(v8086* machine) { int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; + machine->internal_state.IPOffset += 2; int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 2; machine->sregs.cs = newCS; machine->IP.w.ip = newIP; machine->internal_state.IPOffset = 0; diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 860f8f44..5bb20a5c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -111,10 +111,10 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0xe9u, jmp_near); ASSIGN_OPCODE(0xeau, jmp_far); ASSIGN_OPCODE(0xebu, jmp_short); - ASSIGN_OPCODE(0xe4u, inb_dx); - ASSIGN_OPCODE(0xe5u, inw_dx); - ASSIGN_OPCODE(0xe6u, outb_dx); - ASSIGN_OPCODE(0xe7u, outw_dx); + ASSIGN_OPCODE(0xecu, inb_dx); + ASSIGN_OPCODE(0xedu, inw_dx); + ASSIGN_OPCODE(0xeeu, outb_dx); + ASSIGN_OPCODE(0xefu, outw_dx); //RESERVED FOR LOCK PREFIX ASSIGN_NULL(0xf0u); //NOT DEFINED IN 8086 @@ -159,6 +159,8 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_OPCODE(0x6du, ins); ASSIGN_OPCODE(0x6eu, outs8); ASSIGN_OPCODE(0x6fu, outs); + ASSIGN_OPCODE(0xc0u, group_2); + ASSIGN_OPCODE(0xc1u, group_2); ASSIGN_OPCODE(0xc8u, enter); ASSIGN_OPCODE(0xc9u, leave); @@ -269,6 +271,13 @@ int16_t v8086_call_int(v8086* machine, int16_t num) return num; } +uint32_t v8086_get_address_of_int(v8086* machine, int16_t num) +{ + uint32_t ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); + uint32_t cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + return cs * 0x10 + ip; +} + int16_t parse_and_execute_instruction(v8086* machine) { machine->internal_state.IPOffset = 0; @@ -284,6 +293,9 @@ int16_t parse_and_execute_instruction(v8086* machine) decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + if(machine->IP.w.ip == 0x0f04u) { + int x = 0; + } machine->internal_state.IPOffset += 1; //PREFIXES diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 2efba613..d0fe9b9c 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -51,6 +51,7 @@ typedef enum _machine_status { BAD_INT_NUMBER = -13, RELATIVE_JMP_OVERFLOW = -14, BOUND_ERROR = -15, + DIVISION_BY_ZERO = -16, UNKNOWN_ERROR = -69 } machine_status; @@ -158,4 +159,5 @@ v8086* v8086_create_machine(); int16_t v8086_call_int(v8086* machine, int16_t num); void v8086_set_8086_instruction_set(v8086* machine); void v8086_set_386_instruction_set(v8086* machine); +uint32_t v8086_get_address_of_int(v8086* machine, int16_t num); #endif \ No newline at end of file From fe359ada8431f460ecf50a804f3d3685287f6202 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 6 Aug 2020 18:37:47 +0200 Subject: [PATCH 086/165] Update kernel.c for debugging - error with enum names - needed refactor --- os/kernel/src/kernel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index d65e51d5..1b655ad9 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -35,6 +35,7 @@ #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" #include "v8086/v8086.h" +#include "gdb/gdb_stub.c" typedef struct _linesStruct { @@ -361,11 +362,21 @@ void clear_bss() memset(bss_start_addr, 0, bss_length); } +void turn_on_serial_debugging() +{ + serial_init(COM1_PORT, 1200, 8, 1, PARITY_NONE); + set_debug_traps(); + breakpoint(); +} + int kmain() { clear_bss(); startup(); + + turn_on_serial_debugging(); + logger_log_info("Hello, World!"); //startup_music_play(); logger_log_ok("READY."); From c944a07b5152119a138714ce47974835ce4c316c Mon Sep 17 00:00:00 2001 From: SzateX Date: Thu, 6 Aug 2020 19:04:34 +0200 Subject: [PATCH 087/165] Refactored v8086 enumes --- os/kernel/src/v8086/mod_rm_parsing.c | 154 +++++++-------- .../v8086/operations/arithmetic_operations.c | 182 +++++++++--------- .../operations/ascii_adjustments_operations.c | 8 +- .../src/v8086/operations/bit_operations.c | 50 ++--- .../v8086/operations/exchange_operations.c | 12 +- .../src/v8086/operations/io_operations.c | 36 ++-- .../src/v8086/operations/jump_operations.c | 22 +-- .../src/v8086/operations/misc_operations.c | 36 ++-- .../src/v8086/operations/mov_operations.c | 86 ++++----- os/kernel/src/v8086/operations/opcodes.c | 42 ++-- .../v8086/operations/procedure_operations.c | 16 +- .../src/v8086/operations/stack_operations.c | 32 +-- .../src/v8086/operations/string_operations.c | 86 ++++----- os/kernel/src/v8086/v8086.c | 34 ++-- os/kernel/src/v8086/v8086.h | 48 ++--- 15 files changed, 422 insertions(+), 422 deletions(-) diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index bd949336..c5663bcc 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -6,21 +6,21 @@ uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) { switch(reg_field) { - case AL: + case V8086_AL: return &(machine->regs.h.al); - case AH: + case V8086_AH: return &(machine->regs.h.ah); - case BL: + case V8086_BL: return &(machine->regs.h.bl); - case BH: + case V8086_BH: return &(machine->regs.h.bh); - case CL: + case V8086_CL: return &(machine->regs.h.cl); - case CH: + case V8086_CH: return &(machine->regs.h.ch); - case DL: + case V8086_DL: return &(machine->regs.h.dl); - case DH: + case V8086_DH: return &(machine->regs.h.dh); default: return NULL; @@ -32,21 +32,21 @@ uint16_t* get_word_register(v8086* machine, uint8_t reg_field) { switch(reg_field) { - case AX: + case V8086_AX: return &(machine->regs.x.ax); - case CX: + case V8086_CX: return &(machine->regs.x.cx); - case DX: + case V8086_DX: return &(machine->regs.x.dx); - case BX: + case V8086_BX: return &(machine->regs.x.bx); - case SP: + case V8086_SP: return &(machine->regs.x.sp); - case BP: + case V8086_BP: return &(machine->regs.x.bp); - case SI: + case V8086_SI: return &(machine->regs.x.si); - case DI: + case V8086_DI: return &(machine->regs.x.di); default: return NULL; @@ -58,21 +58,21 @@ uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) { switch(reg_field) { - case EAX: + case V8086_EAX: return &(machine->regs.d.eax); - case ECX: + case V8086_ECX: return &(machine->regs.d.ecx); - case EDX: + case V8086_EDX: return &(machine->regs.d.edx); - case EBX: + case V8086_EBX: return &(machine->regs.d.ebx); - case ESP: + case V8086_ESP: return &(machine->regs.d.esp); - case EBP: + case V8086_EBP: return &(machine->regs.d.ebp); - case ESI: + case V8086_ESI: return &(machine->regs.d.esi); - case EDI: + case V8086_EDI: return &(machine->regs.d.edi); default: return NULL; @@ -99,17 +99,17 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select { switch(select) { - case CS: + case V8086_CS: return &(machine->sregs.cs); - case DS: + case V8086_DS: return &(machine->sregs.ds); - case SS: + case V8086_SS: return &(machine->sregs.ss); - case ES: + case V8086_ES: return &(machine->sregs.es); - case FS: + case V8086_FS: return &(machine->sregs.fs); - case GS: + case V8086_GS: return &(machine->sregs.gs); default: return NULL; @@ -119,7 +119,7 @@ uint16_t* select_segment_register(v8086* machine, segment_register_select select int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset) { uint16_t* segment_register = NULL; - if(machine->internal_state.segment_reg_select != DEFAULT) + if(machine->internal_state.segment_reg_select != V8086_DEFAULT) segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); else { @@ -130,19 +130,19 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 case 4: case 5: case 7: - segment_register = select_segment_register(machine, DS); + segment_register = select_segment_register(machine, V8086_DS); break; case 6: - if((mod_rm >> 6u) == 0) segment_register = select_segment_register(machine, DS); - else segment_register = select_segment_register(machine, SS); + if((mod_rm >> 6u) == 0) segment_register = select_segment_register(machine, V8086_DS); + else segment_register = select_segment_register(machine, V8086_SS); break; default: - segment_register = select_segment_register(machine, SS); + segment_register = select_segment_register(machine, V8086_SS); break; } } - if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(segment_register == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; *segment = *segment_register; @@ -152,32 +152,32 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si; - return OK; + return V8086_OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di; - return OK; + return V8086_OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si; - return OK; + return V8086_OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di; - return OK; + return V8086_OK; case 4: *offset = machine->regs.x.si; - return OK; + return V8086_OK; case 5: *offset = machine->regs.x.di; - return OK; + return V8086_OK; case 6:{ *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + (machine->internal_state.IPOffset))); machine->internal_state.IPOffset += 2; - return OK; + return V8086_OK; } case 7: *offset = machine->regs.x.bx; - return OK; + return V8086_OK; default: - return BAD_RM; + return V8086_BAD_RM; } case 1:{ int8_t disp = (int8_t) read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); @@ -185,30 +185,30 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return OK; + return V8086_OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return OK; + return V8086_OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return OK; + return V8086_OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return OK; + return V8086_OK; case 4: *offset = machine->regs.x.si + disp; - return OK; + return V8086_OK; case 5: *offset = machine->regs.x.di + disp; - return OK; + return V8086_OK; case 6: *offset = machine->regs.x.bp + disp; - return OK; + return V8086_OK; case 7: *offset = machine->regs.x.bx + disp; - return OK; + return V8086_OK; default: - return BAD_RM; + return V8086_BAD_RM; } } case 2:{ @@ -217,36 +217,36 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 switch(mod_rm & 7u){ case 0: *offset = machine->regs.x.bx + machine->regs.x.si + disp; - return OK; + return V8086_OK; case 1: *offset = machine->regs.x.bx + machine->regs.x.di + disp; - return OK; + return V8086_OK; case 2: *offset = machine->regs.x.bp + machine->regs.x.si + disp; - return OK; + return V8086_OK; case 3: *offset = machine->regs.x.bp + machine->regs.x.di + disp; - return OK; + return V8086_OK; case 4: *offset = machine->regs.x.si + disp; - return OK; + return V8086_OK; case 5: *offset = machine->regs.x.di + disp; - return OK; + return V8086_OK; case 6: *offset = machine->regs.x.bp + disp; - return OK; + return V8086_OK; case 7: *offset = machine->regs.x.bx + disp; - return OK; + return V8086_OK; default: - return BAD_RM; + return V8086_BAD_RM; } } default: - return BAD_MOD; + return V8086_BAD_MOD; } - return UNKNOWN_ERROR; + return V8086_UNKNOWN_ERROR; } int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, uint32_t *offset) @@ -283,7 +283,7 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, *offset = machine->regs.d.edi; break; default: - return BAD_INDEX; + return V8086_BAD_INDEX; } *offset <<= scale; @@ -315,7 +315,7 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, else { *offset += machine->regs.d.ebp; - segment = select_segment_register(machine, SS); + segment = select_segment_register(machine, V8086_SS); } break; case 6: @@ -325,9 +325,9 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, *offset += machine->regs.d.edi; break; default: - return BAD_BASE; + return V8086_BAD_BASE; } - return OK; + return V8086_OK; } int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, uint16_t *segment, uint32_t *offset) { @@ -370,7 +370,7 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.edi; break; default: - return BAD_RM; + return V8086_BAD_RM; } break; case 1: @@ -396,7 +396,7 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui break; case 5:{ *offset = machine->regs.d.ebp + disp; - segment_register = select_segment_register(machine, SS); + segment_register = select_segment_register(machine, V8086_SS); break; } case 6: @@ -406,7 +406,7 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.edi + disp; break; default: - return BAD_RM; + return V8086_BAD_RM; } break; } @@ -432,7 +432,7 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui break; case 5:{ *offset = machine->regs.d.ebp + disp; - segment_register = select_segment_register(machine, SS); + segment_register = select_segment_register(machine, V8086_SS); break; } case 6: @@ -442,18 +442,18 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.edi + disp; break; default: - return BAD_RM; + return V8086_BAD_RM; } break; } default: - return BAD_MOD; + return V8086_BAD_MOD; } - if(machine->internal_state.segment_reg_select != DEFAULT) + if(machine->internal_state.segment_reg_select != V8086_DEFAULT) segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); else if(segment_register == NULL) - segment_register = select_segment_register(machine, DS); + segment_register = select_segment_register(machine, V8086_DS); *segment = *segment_register; return 0; diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index b4b05c01..d0e0f785 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -20,7 +20,7 @@ int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, } else if (width == 32) { dest_before = *((uint32_t *) dest); source_before = *((uint32_t *) source); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; result = dest_before + source_before + carry; bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG uint8_t parrity = result & 1u; @@ -35,8 +35,8 @@ int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -52,7 +52,7 @@ int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t wi } else if (width == 32) { dest_before = *((uint32_t *) dest); source_before = *((uint32_t *) source); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; result = dest_before - (source_before + carry); bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, @@ -67,8 +67,8 @@ int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t wi if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -79,7 +79,7 @@ int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint result = *((uint16_t *) dest) | *((uint16_t *) source); else if (width == 32) result = *((uint32_t *) dest) | *((uint32_t *) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; @@ -91,7 +91,7 @@ int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return OK; + return V8086_OK; } int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -102,7 +102,7 @@ int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uin result = *((uint16_t *) dest) & *((uint16_t *) source); else if (width == 32) result = *((uint32_t *) dest) & *((uint32_t *) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; @@ -114,7 +114,7 @@ int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uin if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return OK; + return V8086_OK; } int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -125,7 +125,7 @@ int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uin result = *((uint16_t *) dest) ^ *((uint16_t *) source); else if (width == 32) result = *((uint32_t *) dest) ^ *((uint32_t *) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG uint8_t parrity = result & 1u; @@ -137,7 +137,7 @@ int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uin if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return OK; + return V8086_OK; } int16_t perform_cmp(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -153,7 +153,7 @@ int16_t perform_cmp(v8086 *machine, void *dest, void *source, uint8_t width, uin } else if (width == 32) { dest_before = *((uint32_t *) dest); source_before = *((uint32_t *) source); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; result = dest_before - source_before; bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, @@ -165,28 +165,28 @@ int16_t perform_cmp(v8086 *machine, void *dest, void *source, uint8_t width, uin bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - return OK; + return V8086_OK; } int16_t perform_ror(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags = 0; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("rorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) __asm__ __volatile__("rorw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("rorl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_rol(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("rolb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) @@ -196,77 +196,77 @@ int16_t perform_rol(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_rcl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("rclb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) __asm__ __volatile__("rclw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("rcll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_rcr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("rcrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) __asm__ __volatile__("rcrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("rcrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_shl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("shlb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) __asm__ __volatile__("shlw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("shll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_shr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 8) __asm__ __volatile__("shrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); else if (width == 16) __asm__ __volatile__("shrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("shrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) @@ -290,36 +290,36 @@ int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) int16_t perform_shld(v8086 *machine, void *rm, void* reg, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 16) __asm__ __volatile__("shldw %%cl, %%dx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint16_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); else if (width == 32) __asm__ __volatile__("shld %%cl, %%edx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint32_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_shrd(v8086 *machine, void *rm, void* reg, uint8_t arg, uint8_t width) { uint16_t temp_flags; - if (arg == 0) return OK; + if (arg == 0) return V8086_OK; if (width == 16) __asm__ __volatile__("shrdw %%cl, %%dx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint16_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); else if (width == 32) __asm__ __volatile__("shrd %%cl, %%edx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) rm)), "=d" (*((uint16_t *) reg)) : "a" (*((uint32_t *) rm)), "d" (*((uint16_t *) reg)), "c" (arg)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_neg(v8086 *machine, void *source, uint8_t width) { @@ -330,7 +330,7 @@ int16_t perform_neg(v8086 *machine, void *source, uint8_t width) { __asm__ __volatile__("negw %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); else if (width == 32) __asm__ __volatile__("negl %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); @@ -338,7 +338,7 @@ int16_t perform_neg(v8086 *machine, void *source, uint8_t width) { bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, uint8_t width) { @@ -359,7 +359,7 @@ int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, "movl %%edx, %%eax; imul %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; } else { if (width == 8) { __asm__ __volatile__( @@ -376,11 +376,11 @@ int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, "movl %%edx, %%eax; mul %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; } bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t @@ -400,7 +400,7 @@ perform_multiplication_3_byte(v8086 *machine, void *dest, void *source, void *im "imul %%cx, %%dx; pushfw; pop %%bx;" : "=b" (temp_flags), "=d" (*((uint16_t *) dest)) : "d" (*((uint16_t *) source)), "c" (a_imm) ); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; } else if (width == 32) { if (second_width == 8) { int8_t a_imm = *((int8_t *) imm); @@ -414,59 +414,59 @@ perform_multiplication_3_byte(v8086 *machine, void *dest, void *source, void *im "imul %%cx, %%dx; pushfw; pop %%bx;" : "=b" (temp_flags), "=d" (*((uint32_t *) dest)) : "d" (*((uint32_t *) source)), "c" (a_imm) ); - } else return BAD_WIDTH; - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; + } else return V8086_BAD_WIDTH; bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); - return OK; + return V8086_OK; } int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8_t width) { uint16_t temp_flags; if (signed_div) { if (width == 8) { - if(*((uint8_t *) source) == 0) return DIVISION_BY_ZERO; + if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movb %%dl, %%al; idiv %%cl; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); } else if (width == 16) { - if(*((uint16_t *) source) == 0) return DIVISION_BY_ZERO; + if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { - if(*((uint32_t *) source) == 0) return DIVISION_BY_ZERO; + if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; } else { if (width == 8) { - if(*((uint8_t *) source) == 0) return DIVISION_BY_ZERO; + if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) ); } else if (width == 16) { - if(*((uint16_t *) source) == 0) return DIVISION_BY_ZERO; + if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { uint32_t temp = *((uint32_t *) source); - if(temp == 0) return DIVISION_BY_ZERO; + if(temp == 0) return V8086_DIVISION_BY_ZERO; __asm__ __volatile__( "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) ); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; } - return OK; + return V8086_OK; } int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { @@ -478,14 +478,14 @@ int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { result = *((uint16_t *) source) & *((uint16_t *) dest); else if (width == 32) result = *((uint32_t *) source) & *((uint32_t *) dest); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; uint8_t parrity = result & 1u; for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG - return OK; + return V8086_OK; } int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { @@ -495,7 +495,7 @@ int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { if (width == 8) dest_before = *((uint8_t *) dest); else if (width == 16) dest_before = *((uint16_t *) dest); else if (width == 32) dest_before = *((uint32_t *) dest); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; result = dest_before + 1; @@ -512,7 +512,7 @@ int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return OK; + return V8086_OK; } int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { @@ -522,7 +522,7 @@ int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { if (width == 8) dest_before = *((uint8_t *) dest); else if (width == 16) dest_before = *((uint16_t *) dest); else if (width == 32) dest_before = *((uint32_t *) dest); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; result = dest_before - 1; @@ -539,7 +539,7 @@ int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return OK; + return V8086_OK; } int16_t perform_artihmetic_or_logical_instruction(v8086 *machine, uint8_t recalculated_opcode, uint32_t carry, @@ -559,35 +559,35 @@ int16_t perform_artihmetic_or_logical_instruction(v8086 *machine, uint8_t recalc case 0: //OPERATION r/m8, r8 source = get_byte_register(machine, reg); dest = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if (source == NULL) return UNDEFINED_REGISTER; - if (dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return V8086_UNDEFINED_REGISTER; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; break; case 1: //OPERATION r/m32, r32 or OPERATION r/m16, r16 source = get_variable_length_register(machine, reg, width); dest = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if (source == NULL) return UNDEFINED_REGISTER; - if (dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return V8086_UNDEFINED_REGISTER; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; break; case 2: //OPERATION r8, r/m8 dest = get_byte_register(machine, reg); source = get_memory_from_mode(machine, mod_rm_or_immediate, 8); - if (dest == NULL) return UNDEFINED_REGISTER; - if (source == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return V8086_UNDEFINED_REGISTER; + if (source == NULL) return V8086_UNABLE_GET_MEMORY; break; case 3: //OPERATION r32, r/m32 or OPERATION r16, r/m16 dest = get_variable_length_register(machine, reg, width); source = get_memory_from_mode(machine, mod_rm_or_immediate, width); - if (dest == NULL) return UNDEFINED_REGISTER; - if (source == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return V8086_UNDEFINED_REGISTER; + if (source == NULL) return V8086_UNABLE_GET_MEMORY; break; case 4: //OPERATION AL, imm8 - dest = get_byte_register(machine, AL); + dest = get_byte_register(machine, V8086_AL); source = &(mod_rm_or_immediate); - if (dest == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return V8086_UNDEFINED_REGISTER; break; case 5: //OPERATION EAX, imm32 or OPERATION AX, imm16 - dest = get_variable_length_register(machine, AX, width); - if (dest == NULL) return UNDEFINED_REGISTER; + dest = get_variable_length_register(machine, V8086_AX, width); + if (dest == NULL) return V8086_UNDEFINED_REGISTER; if (width == 32) source = get_dword_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip - 1 + @@ -599,11 +599,11 @@ int16_t perform_artihmetic_or_logical_instruction(v8086 *machine, uint8_t recalc machine->internal_state.IPOffset += ((width / 8) - 1); break; default: - return UNDEFINED_RECALCULATED_OPCODE; + return V8086_UNDEFINED_RECALCULATED_OPCODE; } int16_t status = operation(machine, dest, source, width, carry); if (status) return status; - return OK; + return V8086_OK; } int16_t perform_arithmetic_or_logical_instruction_group(v8086 *machine, uint8_t recalculated_opcode, uint8_t mod_rm, @@ -650,14 +650,14 @@ int16_t perform_arithmetic_or_logical_instruction_group(v8086 *machine, uint8_t dest = get_memory_from_mode(machine, mod_rm, width); break; default: - return UNDEFINED_RECALCULATED_OPCODE; + return V8086_UNDEFINED_RECALCULATED_OPCODE; } - if (dest == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; int16_t status; if (recalculated_opcode == 3) status = operation(machine, dest, &signed_immediate, width, carry); else status = operation(machine, dest, &immediate, width, carry); if (status) return status; - return OK; + return V8086_OK; } int16_t perform_inc_dec(v8086 *machine, uint8_t opcode, bool dec) { @@ -665,7 +665,7 @@ int16_t perform_inc_dec(v8086 *machine, uint8_t opcode, bool dec) { void *dest = NULL; if (machine->internal_state.operand_32_bit) width = 32; dest = get_variable_length_register(machine, opcode & 7u, width); - if (dest == NULL) return UNDEFINED_REGISTER; + if (dest == NULL) return V8086_UNDEFINED_REGISTER; if (!dec) return perform_inc(machine, dest, width); @@ -683,8 +683,8 @@ int16_t execute_test(v8086 *machine, uint8_t opcode) { void *source = get_variable_length_register(machine, get_reg(mod_rm), width); void *dest = get_memory_from_mode(machine, mod_rm, width); - if (source == NULL) return UNDEFINED_REGISTER; - if (dest == NULL) return UNABLE_GET_MEMORY; + if (source == NULL) return V8086_UNDEFINED_REGISTER; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; return perform_test(machine, source, dest, width); } @@ -696,9 +696,9 @@ int16_t execute_test_immediate(v8086 *machine, uint8_t opcode) { machine->internal_state.IPOffset), width); machine->internal_state.IPOffset += width / 8; - void *reg = get_variable_length_register(machine, AX, width); - if (immediate == NULL) return UNABLE_GET_MEMORY; - if (reg == NULL) return UNDEFINED_REGISTER; + void *reg = get_variable_length_register(machine, V8086_AX, width); + if (immediate == NULL) return V8086_UNABLE_GET_MEMORY; + if (reg == NULL) return V8086_UNDEFINED_REGISTER; return perform_test(machine, immediate, reg, width); } @@ -719,7 +719,7 @@ int16_t execute_group_2(v8086 *machine, uint8_t opcode) { machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; } - if (dest == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; switch (get_reg(mod_rm)) { case 0: return perform_rol(machine, dest, arg, width); @@ -734,11 +734,11 @@ int16_t execute_group_2(v8086 *machine, uint8_t opcode) { case 5: return perform_shr(machine, dest, arg, width); case 6: - return UNDEFINED_OPCODE; + return V8086_UNDEFINED_OPCODE; case 7: return perform_sar(machine, dest, arg, width); default: - return BAD_REG; + return V8086_BAD_REG; } } @@ -754,7 +754,7 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { void *dest = get_memory_from_mode(machine, mod_rm, width); - if (dest == NULL) return UNABLE_GET_MEMORY; + if (dest == NULL) return V8086_UNABLE_GET_MEMORY; switch (get_reg(mod_rm)) { case 0: //TEST @@ -786,8 +786,8 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { *((uint16_t *) dest) = ~(*((uint16_t *) dest)); else if (width == 32) *((uint32_t *) dest) = ~(*((uint32_t *) dest)); - else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + return V8086_OK; break; case 3: //NEG return perform_neg(machine, dest, width); @@ -800,7 +800,7 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { case 7: //IDIV return perform_division(machine, dest, 1, width); default: - return BAD_REG; + return V8086_BAD_REG; } } diff --git a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c index 17aeff35..5c456b08 100644 --- a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c +++ b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c @@ -23,7 +23,7 @@ int16_t adjust_after_add_sub(v8086* machine, bool sub) bit_clear(machine->regs.w.flags, 1u <regs.h.al &= 0x0fu; - return OK; + return V8086_OK; } int16_t adjust_after_add_sub_packed(v8086* machine, bool sub) @@ -52,7 +52,7 @@ int16_t adjust_after_add_sub_packed(v8086* machine, bool sub) bit_write(machine->regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - return OK; + return V8086_OK; } int16_t adjust_after_mul_div(v8086* machine, bool div) @@ -63,7 +63,7 @@ int16_t adjust_after_mul_div(v8086* machine, bool div) uint8_t tempAH = machine->regs.h.ah; if(!div) { - if(immediate == 0) return DIVISION_BY_ZERO; + if(immediate == 0) return V8086_DIVISION_BY_ZERO; machine->regs.h.ah = tempAL / immediate; machine->regs.h.al = tempAL % immediate; } @@ -78,5 +78,5 @@ int16_t adjust_after_mul_div(v8086* machine, bool div) bit_write(machine-> regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG - return OK; + return V8086_OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/bit_operations.c b/os/kernel/src/v8086/operations/bit_operations.c index 0484eee2..1409b07f 100644 --- a/os/kernel/src/v8086/operations/bit_operations.c +++ b/os/kernel/src/v8086/operations/bit_operations.c @@ -22,8 +22,8 @@ int16_t bit_test(v8086* machine, uint8_t width) bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<internal_state.operand_32_bit) width = 32; - void* regA = get_variable_length_register(machine, EAX, width); + void* regA = get_variable_length_register(machine, V8086_EAX, width); void* regB = get_word_register(machine, opcode & 7u); - if((regA == NULL) || (regB == NULL)) return UNDEFINED_REGISTER; + if((regA == NULL) || (regB == NULL)) return V8086_UNDEFINED_REGISTER; return perform_exchange(regA, regB, width); } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/io_operations.c b/os/kernel/src/v8086/operations/io_operations.c index 3fe593f8..116b3e65 100644 --- a/os/kernel/src/v8086/operations/io_operations.c +++ b/os/kernel/src/v8086/operations/io_operations.c @@ -11,8 +11,8 @@ int16_t perform_in_imm(v8086* machine, uint8_t width) if(width == 8) machine->regs.h.al = io_in_byte(immediate); else if(width == 16) machine->regs.w.ax = io_in_word(immediate); else if(width == 32) machine->regs.d.eax = io_in_long(immediate); - else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_in_dx(v8086* machine, uint8_t width) @@ -20,8 +20,8 @@ int16_t perform_in_dx(v8086* machine, uint8_t width) if(width == 8) machine->regs.h.al = io_in_byte(machine->regs.x.dx); else if(width == 16) machine->regs.w.ax = io_in_word(machine->regs.x.dx); else if(width == 32) machine->regs.d.eax = io_in_long(machine->regs.x.dx); - else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_out_imm(v8086* machine, uint8_t width) @@ -32,9 +32,9 @@ int16_t perform_out_imm(v8086* machine, uint8_t width) if(width == 8) io_out_byte(immediate, machine->regs.h.al); else if(width == 16) io_out_word(immediate, machine->regs.w.ax); else if(width == 32) io_out_long(immediate, machine->regs.d.eax); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; - return OK; + return V8086_OK; } int16_t perform_out_dx(v8086* machine, uint8_t width) @@ -42,17 +42,17 @@ int16_t perform_out_dx(v8086* machine, uint8_t width) if(width == 8) io_out_byte(machine->regs.x.dx, machine->regs.h.al); else if(width == 16) io_out_word(machine->regs.x.dx, machine->regs.w.ax); else if(width == 32) io_out_long(machine->regs.x.dx, machine->regs.d.eax); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; - return OK; + return V8086_OK; } int16_t perform_ins_dx(v8086* machine, uint8_t width) { - uint16_t* dest_segment = select_segment_register(machine, ES); + uint16_t* dest_segment = select_segment_register(machine, V8086_ES); //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; do{ void* dest = NULL; @@ -64,23 +64,23 @@ int16_t perform_ins_dx(v8086* machine, uint8_t width) if(width == 8) *((uint8_t*)dest) = io_in_byte(machine->regs.x.dx); else if(width == 16) *((uint16_t*)dest) = io_in_word(machine->regs.x.dx); else if(width == 32) *((uint32_t*)dest)= io_in_long(machine->regs.x.dx); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; int8_t offset = width / 8; if(machine->internal_state.address_32_bit) machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; else machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - return OK; + return V8086_OK; } int16_t perform_outs_dx(v8086* machine, uint8_t width) { - uint16_t* dest_segment = select_segment_register(machine, ES); + uint16_t* dest_segment = select_segment_register(machine, V8086_ES); //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; do{ void* dest = NULL; @@ -92,13 +92,13 @@ int16_t perform_outs_dx(v8086* machine, uint8_t width) if(width == 8) io_out_byte(machine->regs.x.dx, *((uint8_t*)dest)); else if(width == 16) io_out_word(machine->regs.x.dx, *((uint16_t*)dest)); else if(width == 32) io_out_long(machine->regs.x.dx, *((uint32_t*)dest)); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; int8_t offset = width / 8; if(machine->internal_state.address_32_bit) machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; else machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - return OK; + return V8086_OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c index 32b35092..f8d5420f 100644 --- a/os/kernel/src/v8086/operations/jump_operations.c +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -9,9 +9,9 @@ int16_t jump_short_relative(v8086* machine) machine->internal_state.IPOffset += 1; uint32_t tempIP = machine->IP.w.ip; tempIP += offset; - if((tempIP > 0xFFFF)) return RELATIVE_JMP_OVERFLOW; + if((tempIP > 0xFFFF)) return V8086_RELATIVE_JMP_OVERFLOW; machine->IP.w.ip = tempIP; - return OK; + return V8086_OK; } int16_t jump_long_relative(v8086* machine, uint8_t width) @@ -27,16 +27,16 @@ int16_t jump_long_relative(v8086* machine, uint8_t width) offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; } - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; uint32_t tempIP = machine->IP.w.ip; tempIP += offset; if(width == 16) tempIP &= 0xffffu; - if((tempIP > 0xFFFF)) return RELATIVE_JMP_OVERFLOW; + if((tempIP > 0xFFFF)) return V8086_RELATIVE_JMP_OVERFLOW; machine->IP.w.ip = tempIP; - return OK; + return V8086_OK; } int16_t jump_near_relative(v8086* machine) @@ -44,7 +44,7 @@ int16_t jump_near_relative(v8086* machine) int16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; machine->IP.w.ip += offset; - return OK; + return V8086_OK; } int16_t jump_far(v8086* machine) @@ -56,7 +56,7 @@ int16_t jump_far(v8086* machine) machine->sregs.cs = newCS; machine->IP.w.ip = newIP; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t jump_on_condition(v8086* machine, uint8_t opcode, uint8_t width) @@ -123,7 +123,7 @@ int16_t jump_on_condition(v8086* machine, uint8_t opcode, uint8_t width) { machine->internal_state.IPOffset += width/8; } - return OK; + return V8086_OK; } int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) @@ -145,7 +145,7 @@ int16_t jump_short_relative_on_condition(v8086* machine, uint8_t opcode) { machine->internal_state.IPOffset += 1; } - return OK; + return V8086_OK; } int16_t perform_loop_loopne(v8086* machine, uint8_t opcode) @@ -181,11 +181,11 @@ int16_t perform_loop_loopne(v8086* machine, uint8_t opcode) if(machine->regs.w.cx) jump = 1; break; default: - return UNKNOWN_ERROR; + return V8086_UNKNOWN_ERROR; } if(jump) machine->IP.w.ip += offset; - return OK; + return V8086_OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index c6bea97a..830168ef 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -13,7 +13,7 @@ int16_t perform_group_4(v8086* machine) uint8_t width = 8; void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; + if(dest == NULL) return V8086_UNABLE_GET_MEMORY; switch(get_reg(mod_rm)) { case 0: //INC rm8 @@ -23,7 +23,7 @@ int16_t perform_group_4(v8086* machine) return perform_dec(machine, dest, width); break; default: - return UNDEFINED_OPCODE; + return V8086_UNDEFINED_OPCODE; } } @@ -35,7 +35,7 @@ int16_t perform_group_5(v8086* machine) if(machine->internal_state.operand_32_bit) width = 32; void* dest = get_memory_from_mode(machine, mod_rm, width); - if(dest == NULL) return UNABLE_GET_MEMORY; + if(dest == NULL) return V8086_UNABLE_GET_MEMORY; switch(get_reg(mod_rm)) { case 0: //INC rm8 @@ -47,9 +47,9 @@ int16_t perform_group_5(v8086* machine) push_word(machine, machine->IP.w.ip); if(width == 16) machine->IP.w.ip += *((uint16_t*) dest); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; case 3: // Far absolute indirect call machine->IP.w.ip += machine->internal_state.IPOffset; push_word(machine, machine->sregs.cs); @@ -57,26 +57,26 @@ int16_t perform_group_5(v8086* machine) machine->IP.w.ip = *((uint16_t*) dest); machine->sregs.cs = *(((uint16_t*)dest)+1); machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; case 4: //Near absolute indirect jmp if(width == 16) machine->IP.w.ip += *((uint16_t*) dest); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; case 5: //Far absolute indirect jmp machine->IP.w.ip = *((uint16_t*) dest); machine->sregs.cs = *(((uint16_t*)dest)+1); machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; case 6: if(width == 16) push_word(machine, *((uint16_t*)dest)); else push_dword(machine, *((uint32_t*)dest)); - return OK; + return V8086_OK; default: - return UNDEFINED_OPCODE; + return V8086_UNDEFINED_OPCODE; } - return UNKNOWN_ERROR; + return V8086_UNKNOWN_ERROR; } int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode) @@ -104,8 +104,8 @@ int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode) else if(opcode == 0xfd) bit_set(machine->regs.w.flags, 1u < *ub)) return BOUND_ERROR; + if((*i < *lb) || (*i > *ub)) return V8086_BOUND_ERROR; } else { @@ -132,9 +132,9 @@ int16_t check_bounds(v8086* machine) int32_t* lb = (int32_t*) bounds; int32_t* ub = ((int32_t*) bounds + 1); - if((*i < *lb) || (*i > *ub)) return BOUND_ERROR; + if((*i < *lb) || (*i > *ub)) return V8086_BOUND_ERROR; } - return OK; + return V8086_OK; } int16_t set_byte(v8086* machine, uint8_t opcode) @@ -196,5 +196,5 @@ int16_t set_byte(v8086* machine, uint8_t opcode) machine->internal_state.IPOffset += 1; uint8_t* memory = (uint8_t*) get_memory_from_mode(machine, mod_rm, 8); *memory = set_byte; - return OK; + return V8086_OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index 08c77d2c..0476676a 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -17,9 +17,9 @@ int16_t perform_mov(void* source, void* dest, uint8_t width) { *((uint32_t *) dest) = *((uint32_t *) source); break; default: - return BAD_WIDTH; + return V8086_BAD_WIDTH; } - return OK; + return V8086_OK; } int16_t perform_mov_rm(v8086* machine, uint8_t opcode) @@ -32,8 +32,8 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode) width = machine->internal_state.operand_32_bit ? 32 : 16; void* source = get_variable_length_register(machine, get_reg(mod_rm), width); void* dest = get_memory_from_mode(machine, mod_rm, width); - if(source == NULL) return UNDEFINED_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; + if(source == NULL) return V8086_UNDEFINED_REGISTER; + if(dest == NULL) return V8086_UNABLE_GET_MEMORY; switch (opcode) { case 0x88: @@ -43,7 +43,7 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode) case 0x8b: return perform_mov(dest, source, width); default: - return UNKNOWN_ERROR; + return V8086_UNKNOWN_ERROR; } } @@ -55,15 +55,15 @@ int16_t perform_movzx_variable_length(void* source, void* dest, uint8_t source_w *((uint16_t *) dest) = *((uint8_t *) source); else if(dest_width == 32) *((uint32_t *) dest) = *((uint8_t *) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; } else if(source_width == 16) { if(dest_width == 32) *((uint32_t *) dest) = *((uint16_t *) source); - else return BAD_WIDTH; - } else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + } else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_movsx_variable_length(void* source, void* dest, uint8_t source_width, uint8_t dest_width) @@ -74,15 +74,15 @@ int16_t perform_movsx_variable_length(void* source, void* dest, uint8_t source_w *((int16_t *) dest) = *((int8_t *) source); else if(dest_width == 32) *((int32_t *) dest) = *((int8_t *) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; } else if(source_width == 16) { if(dest_width == 32) *((int32_t *) dest) = *((int16_t *) source); - else return BAD_WIDTH; - } else return BAD_WIDTH; - return OK; + else return V8086_BAD_WIDTH; + } else return V8086_BAD_WIDTH; + return V8086_OK; } int16_t perform_movzx(v8086* machine, uint8_t opcode) @@ -104,7 +104,7 @@ int16_t perform_movzx(v8086* machine, uint8_t opcode) void* source = get_memory_from_mode(machine, mod_rm, 16); return perform_movzx_variable_length(source, dest, 16, width); } - else return UNKNOWN_ERROR; + else return V8086_UNKNOWN_ERROR; } int16_t perform_movsx(v8086* machine, uint8_t opcode) @@ -126,7 +126,7 @@ int16_t perform_movsx(v8086* machine, uint8_t opcode) void* source = get_memory_from_mode(machine, mod_rm, 16); return perform_movsx_variable_length(source, dest, 16, width); } - else return UNKNOWN_ERROR; + else return V8086_UNKNOWN_ERROR; } int16_t perform_mov_segment(v8086* machine, uint8_t opcode) @@ -135,14 +135,14 @@ int16_t perform_mov_segment(v8086* machine, uint8_t opcode) machine->internal_state.IPOffset += 1; uint16_t* source = select_segment_register(machine, get_reg(mod_rm)); uint16_t* dest = get_memory_from_mode(machine, mod_rm, 16); - if(source == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest == NULL) return UNABLE_GET_MEMORY; + if(source == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; + if(dest == NULL) return V8086_UNABLE_GET_MEMORY; if(opcode == 0x8c) return perform_mov(source, dest, 16); else if(opcode == 0x8e) return perform_mov(dest, source, 16); - else return UNKNOWN_ERROR; + else return V8086_UNKNOWN_ERROR; } uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode) @@ -150,10 +150,10 @@ uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode) uint8_t width; if(opcode >= 0xb0 && opcode <= 0xb7) width = 8; else if(opcode >= 0xb8 && opcode <= 0xbf) width = machine->internal_state.operand_32_bit ? 32 : 16; - else return UNKNOWN_ERROR; + else return V8086_UNKNOWN_ERROR; uint8_t reg_selector = (opcode >= 0xb8) ? (opcode - 0xb8u) & 0x7u : opcode & 0x7u; void* reg = get_variable_length_register(machine, reg_selector, width); - if(reg == NULL) return UNDEFINED_REGISTER; + if(reg == NULL) return V8086_UNDEFINED_REGISTER; void* imm = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); machine->internal_state.IPOffset += width / 8; return perform_mov(imm, reg, width); @@ -168,7 +168,7 @@ uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); - if(mem == NULL) return UNABLE_GET_MEMORY; + if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } else @@ -178,7 +178,7 @@ uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); - if(mem == NULL) return UNABLE_GET_MEMORY; + if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } else @@ -186,19 +186,19 @@ uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); - if(mem == NULL) return UNABLE_GET_MEMORY; + if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } } - return OK; + return V8086_OK; } int16_t perform_mov_moffset(v8086* machine, uint8_t opcode) { uint16_t offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - uint16_t* segment = machine->internal_state.segment_reg_select == DEFAULT ? select_segment_register(machine, DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + uint16_t* segment = machine->internal_state.segment_reg_select == V8086_DEFAULT ? select_segment_register(machine, V8086_DS) : select_segment_register(machine, machine->internal_state.segment_reg_select); + if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; switch (opcode) { case 0xa0: @@ -216,9 +216,9 @@ int16_t perform_mov_moffset(v8086* machine, uint8_t opcode) else write_word_to_pointer(machine->Memory, get_absolute_address(*segment, offset), machine->regs.x.ax); break; default: - return UNKNOWN_ERROR; + return V8086_UNKNOWN_ERROR; } - return OK; + return V8086_OK; } int16_t perform_lea(v8086* machine) @@ -229,7 +229,7 @@ int16_t perform_lea(v8086* machine) uint16_t segment; uint32_t offset; - if((mod_rm >> 6u) > 3) return BAD_MOD; + if((mod_rm >> 6u) > 3) return V8086_BAD_MOD; int16_t r; if(machine->internal_state.address_32_bit) @@ -242,16 +242,16 @@ int16_t perform_lea(v8086* machine) if(machine->internal_state.operand_32_bit) { uint32_t* reg = get_dword_register(machine, get_reg(mod_rm)); - if(reg == NULL) return UNDEFINED_REGISTER; + if(reg == NULL) return V8086_UNDEFINED_REGISTER; *reg = offset; } else { uint16_t* reg = get_word_register(machine, get_reg(mod_rm)); - if(reg == NULL) return UNDEFINED_REGISTER; + if(reg == NULL) return V8086_UNDEFINED_REGISTER; *reg = offset; } - return OK; + return V8086_OK; } int16_t convert_byte_to_word(v8086* machine) @@ -260,7 +260,7 @@ int16_t convert_byte_to_word(v8086* machine) machine->regs.d.eax = ((int32_t)(machine->regs.w.ax)); else machine->regs.w.ax = ((int16_t)(machine->regs.h.al)); - return OK; + return V8086_OK; } int16_t convert_word_to_double(v8086* machine) @@ -273,7 +273,7 @@ int16_t convert_word_to_double(v8086* machine) int32_t t = machine->regs.w.ax; machine->regs.w.dx = ((uint32_t)t >> 16u); } - return OK; + return V8086_OK; } int16_t store_flags(v8086* machine) @@ -281,13 +281,13 @@ int16_t store_flags(v8086* machine) for(uint8_t i = 0; i < 8; i++) if(i != 1 && i != 3 && i != 5) bit_write(machine->regs.w.flags, 1u <regs.h.ah, 1u <regs.h.ah = machine->regs.w.flags & 0xFFu; - return OK; + return V8086_OK; } int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment_op) @@ -297,9 +297,9 @@ int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment uint16_t* segment_register; segment_register = select_segment_register(machine, segment_op); - if(segment_register == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(segment_register == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; uint16_t* source = get_memory_from_mode(machine, mod_rm, 16); - if(source == NULL) return UNABLE_GET_MEMORY; + if(source == NULL) return V8086_UNABLE_GET_MEMORY; if(machine->internal_state.operand_32_bit) { @@ -313,18 +313,18 @@ int16_t perform_load_far_pointer(v8086* machine, segment_register_select segment *dest = *source; *segment_register = *(source+1); } - return OK; + return V8086_OK; } int16_t perform_xlat(v8086* machine) { uint8_t tempAL = machine->regs.h.al; uint16_t* segment; - if(machine->internal_state.segment_reg_select != DEFAULT) + if(machine->internal_state.segment_reg_select != V8086_DEFAULT) segment = select_segment_register(machine, machine->internal_state.segment_reg_select); else - segment = select_segment_register(machine, DS); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + segment = select_segment_register(machine, V8086_DS); + if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; machine->regs.h.al = read_byte_from_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.bx + tempAL)); - return OK; + return V8086_OK; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 551869a7..b8145fbf 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -27,13 +27,13 @@ OPCODE_PROTO(add) OPCODE_PROTO(push_es) { push_word(machine, machine->sregs.es); - return OK; + return V8086_OK; } OPCODE_PROTO(pop_es) { machine->sregs.es = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(or) @@ -44,7 +44,7 @@ OPCODE_PROTO(or) OPCODE_PROTO(push_cs) { push_word(machine, machine->sregs.cs); - return OK; + return V8086_OK; } OPCODE_PROTO(adc) @@ -55,13 +55,13 @@ OPCODE_PROTO(adc) OPCODE_PROTO(push_ss) { push_word(machine, machine->sregs.ss); - return OK; + return V8086_OK; } OPCODE_PROTO(pop_ss) { machine->sregs.ss = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(sbb) @@ -72,13 +72,13 @@ OPCODE_PROTO(sbb) OPCODE_PROTO(push_ds) { push_word(machine, machine->sregs.ds); - return OK; + return V8086_OK; } OPCODE_PROTO(pop_ds) { machine->sregs.ds = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(and) @@ -174,7 +174,7 @@ OPCODE_PROTO(group1) case 7: //CMP return perform_arithmetic_or_logical_instruction_group(machine, recalculated_opcode, mod_rm, NO_CARRY, perform_cmp); default: - return BAD_REG; + return V8086_BAD_REG; } } @@ -231,13 +231,13 @@ OPCODE_PROTO(far_call) OPCODE_PROTO(pushf) { push_word(machine, machine->regs.w.flags); - return OK; + return V8086_OK; } OPCODE_PROTO(popf) { machine->regs.w.flags = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(sahf) @@ -316,12 +316,12 @@ OPCODE_PROTO(retn_imm) OPCODE_PROTO(les) { - return perform_load_far_pointer(machine, ES); + return perform_load_far_pointer(machine, V8086_ES); } OPCODE_PROTO(lds) { - return perform_load_far_pointer(machine, DS); + return perform_load_far_pointer(machine, V8086_DS); } OPCODE_PROTO(mov_rm_imm) @@ -349,7 +349,7 @@ OPCODE_PROTO(interrupt) } else if(opcode == 0xce) //INTO { - if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) return OK; + if(!bit_get(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT)) return V8086_OK; interrupt_number = 4; } @@ -557,7 +557,7 @@ OPCODE_PROTO(two_byte_0fh){ secondary_opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - if(machine->operations_0fh[secondary_opcode] == NULL) return UNDEFINED_OPCODE; + if(machine->operations_0fh[secondary_opcode] == NULL) return V8086_UNDEFINED_OPCODE; return machine->operations_0fh[secondary_opcode](machine, secondary_opcode); } @@ -575,25 +575,25 @@ OPCODE_PROTO(setcc) OPCODE_PROTO(push_fs) { push_word(machine, machine->sregs.fs); - return OK; + return V8086_OK; } OPCODE_PROTO(pop_fs) { machine->sregs.fs = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(push_gs) { push_word(machine, machine->sregs.gs); - return OK; + return V8086_OK; } OPCODE_PROTO(pop_gs) { machine->sregs.gs = pop_word(machine); - return OK; + return V8086_OK; } OPCODE_PROTO(bt) @@ -654,17 +654,17 @@ OPCODE_PROTO(imul_2_byte) OPCODE_PROTO(lss) { - return perform_load_far_pointer(machine, SS); + return perform_load_far_pointer(machine, V8086_SS); } OPCODE_PROTO(lfs) { - return perform_load_far_pointer(machine, FS); + return perform_load_far_pointer(machine, V8086_FS); } OPCODE_PROTO(lgs) { - return perform_load_far_pointer(machine, GS); + return perform_load_far_pointer(machine, V8086_GS); } OPCODE_PROTO(movzx) diff --git a/os/kernel/src/v8086/operations/procedure_operations.c b/os/kernel/src/v8086/operations/procedure_operations.c index e6b46c16..2ddb8273 100644 --- a/os/kernel/src/v8086/operations/procedure_operations.c +++ b/os/kernel/src/v8086/operations/procedure_operations.c @@ -11,7 +11,7 @@ int16_t near_relative_call(v8086* machine) push_word(machine, machine->IP.w.ip); machine->IP.w.ip += immediate; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t far_call(v8086 *machine){ @@ -37,14 +37,14 @@ int16_t far_call(v8086 *machine){ machine->IP.w.ip = newIP; machine->sregs.cs = newCS; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t near_ret(v8086* machine) { machine->IP.w.ip = pop_word(machine); machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t near_ret_imm(v8086* machine) @@ -54,7 +54,7 @@ int16_t near_ret_imm(v8086* machine) machine->IP.w.ip = pop_word(machine); machine->regs.w.sp += immediate; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t far_ret(v8086* machine) @@ -62,7 +62,7 @@ int16_t far_ret(v8086* machine) machine->IP.w.ip = pop_word(machine); machine->sregs.cs = pop_word(machine); machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t far_ret_imm(v8086* machine) @@ -73,7 +73,7 @@ int16_t far_ret_imm(v8086* machine) machine->sregs.cs = pop_word(machine); machine->regs.w.sp += immediate; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number) @@ -89,7 +89,7 @@ int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number) machine->sregs.cs = newCS; machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } int16_t perform_iret(v8086* machine) @@ -99,5 +99,5 @@ int16_t perform_iret(v8086* machine) machine->regs.w.flags = pop_word(machine); machine->internal_state.IPOffset = 0; - return OK; + return V8086_OK; } diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index 6fef673c..e503b4a7 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -11,10 +11,10 @@ int16_t push_gpr(v8086* machine, uint8_t opcode) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 32; reg = get_variable_length_register(machine, opcode & 7u, width); - if(reg == NULL) return UNDEFINED_REGISTER; + if(reg == NULL) return V8086_UNDEFINED_REGISTER; if(width==16) push_word(machine, *((uint16_t*)reg)); else push_dword(machine, *((uint32_t*)reg)); - return OK; + return V8086_OK; } int16_t pop_gpr(v8086* machine, uint8_t opcode) @@ -23,10 +23,10 @@ int16_t pop_gpr(v8086* machine, uint8_t opcode) void* reg = NULL; if(machine->internal_state.operand_32_bit) width = 32; reg = get_variable_length_register(machine, opcode & 7u, width); - if(reg == NULL) return UNDEFINED_REGISTER; + if(reg == NULL) return V8086_UNDEFINED_REGISTER; if(width==16) *((uint16_t*)reg) = pop_word(machine); else *((uint32_t*)reg) = pop_dword(machine); - return OK; + return V8086_OK; } int16_t pop_rm(v8086* machine) @@ -41,7 +41,7 @@ int16_t pop_rm(v8086* machine) *((uint16_t*)dest) = pop_word(machine); else *((uint32_t*)dest) = pop_dword(machine); - return OK; + return V8086_OK; } int16_t push_all(v8086* machine) @@ -69,7 +69,7 @@ int16_t push_all(v8086* machine) push_dword(machine, machine->regs.d.esi); push_dword(machine, machine->regs.d.edi); } - return OK; + return V8086_OK; } int16_t pop_all(v8086* machine) @@ -98,7 +98,7 @@ int16_t pop_all(v8086* machine) machine->regs.d.ecx = pop_dword(machine); machine->regs.d.eax = pop_dword(machine); } - return OK; + return V8086_OK; } int16_t push_immediate(v8086* machine, uint8_t width) @@ -108,23 +108,23 @@ int16_t push_immediate(v8086* machine, uint8_t width) uint8_t imm = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; push_byte(machine, imm); - return OK; + return V8086_OK; } if(width == 16) { uint16_t imm = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; push_word(machine, imm); - return OK; + return V8086_OK; } if(width == 32) { uint32_t imm = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; push_dword(machine, imm); - return OK; + return V8086_OK; } - return BAD_WIDTH; + return V8086_BAD_WIDTH; } int16_t enter(v8086* machine, uint8_t width) @@ -149,7 +149,7 @@ int16_t enter(v8086* machine, uint8_t width) push_word(machine, machine->regs.w.bp); temp_ebp = machine->regs.w.sp; } - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if(nesting_level > 0) { @@ -180,7 +180,7 @@ int16_t enter(v8086* machine, uint8_t width) machine->regs.w.sp -= alloc_size; } - return OK; + return V8086_OK; } int16_t leave(v8086* machine, uint8_t width) @@ -188,12 +188,12 @@ int16_t leave(v8086* machine, uint8_t width) if(width == 32) { machine->regs.d.esp = machine->regs.d.ebp; machine->regs.d.ebp = pop_dword(machine); - return OK; + return V8086_OK; } if(width == 16){ machine -> regs.w.sp = machine->regs.w.sp; machine->regs.w.bp = pop_word(machine); - return OK; + return V8086_OK; } - return BAD_WIDTH; + return V8086_BAD_WIDTH; } \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index ae1638f6..305049c9 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -5,14 +5,14 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { uint16_t* source_segment; - uint16_t* dest_segment = select_segment_register(machine, ES); - if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + uint16_t* dest_segment = select_segment_register(machine, V8086_ES); + if(machine->internal_state.segment_reg_select == V8086_DEFAULT) source_segment = select_segment_register(machine, V8086_DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(source_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; do{ void* source = NULL; @@ -32,7 +32,7 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { else if(width == 32) *((uint32_t*)dest) = *((uint32_t*) source); else - return BAD_WIDTH; + return V8086_BAD_WIDTH; int8_t offset = width / 8; if(machine->internal_state.address_32_bit){ machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; @@ -42,27 +42,27 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; } - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - return OK; + return V8086_OK; } uint16_t perform_stos(v8086* machine, uint8_t width) { - uint16_t* segment = select_segment_register(machine, ES); + uint16_t* segment = select_segment_register(machine, V8086_ES); void* source; void* dest; - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; do{ if(machine->internal_state.address_32_bit) dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); else dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); - source = get_variable_length_register(machine, AL, width); - if(source == NULL) return UNDEFINED_REGISTER; + source = get_variable_length_register(machine, V8086_AL, width); + if(source == NULL) return V8086_UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); @@ -72,27 +72,27 @@ uint16_t perform_stos(v8086* machine, uint8_t width) machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); else machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - } while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); + } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - return OK; + return V8086_OK; } uint16_t perform_cmps(v8086* machine, uint8_t width) { uint16_t* source_segment; - uint16_t* dest_segment = select_segment_register(machine, ES); + uint16_t* dest_segment = select_segment_register(machine, V8086_ES); void* source; void* dest; uint32_t dest_before; //for overflow flag checking uint32_t source_before; uint64_t result; - if(machine->internal_state.segment_reg_select == DEFAULT) source_segment = select_segment_register(machine, DS); + if(machine->internal_state.segment_reg_select == V8086_DEFAULT) source_segment = select_segment_register(machine, V8086_DS); else source_segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; - if(dest_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(source_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; + if(dest_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix != V8086_NONE_REPEAT && machine->regs.w.cx == 0) return V8086_OK; do{ if(machine->internal_state.address_32_bit) @@ -112,7 +112,7 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) } else if(width == 32){ dest_before = *((uint32_t*)dest); source_before = *((uint32_t*)source); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; result = dest_before - source_before; bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG @@ -133,11 +133,11 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); } - if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || - (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; - } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); + if((machine->internal_state.rep_prefix == V8086_REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || + (machine->internal_state.rep_prefix == V8086_REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; + } while(machine->internal_state.rep_prefix != V8086_NONE_REPEAT && --(machine->regs.w.cx)); - return OK; + return V8086_OK; } uint16_t perform_lods(v8086* machine, uint8_t width) @@ -146,52 +146,52 @@ uint16_t perform_lods(v8086* machine, uint8_t width) void* source; void* dest; - if(machine->internal_state.segment_reg_select == DEFAULT) segment = select_segment_register(machine, DS); + if(machine->internal_state.segment_reg_select == V8086_DEFAULT) segment = select_segment_register(machine, V8086_DS); else segment = select_segment_register(machine, machine->internal_state.segment_reg_select); - if(segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == REP_REPE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; do{ if(machine->internal_state.address_32_bit) source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.esi), width); else source = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.si), width); - dest = get_variable_length_register(machine, AL, width); - if(dest == NULL) return UNDEFINED_REGISTER; + dest = get_variable_length_register(machine, V8086_AL, width); + if(dest == NULL) return V8086_UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); - else return BAD_WIDTH; + else return V8086_BAD_WIDTH; if(machine->internal_state.address_32_bit) machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); else machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - }while(machine->internal_state.rep_prefix == REP_REPE && --(machine->regs.w.cx)); - return OK; + }while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); + return V8086_OK; } uint16_t perform_scas(v8086* machine, uint8_t width) { - uint16_t* source_segment = select_segment_register(machine, ES); + uint16_t* source_segment = select_segment_register(machine, V8086_ES); void* source; void* dest; uint32_t dest_before; //for overflow flag checking uint32_t source_before; uint64_t result; - if(source_segment == NULL) return UNDEFINED_SEGMENT_REGISTER; + if(source_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix != NONE && machine->regs.w.cx == 0) return OK; + if(machine->internal_state.rep_prefix != V8086_NONE_REPEAT && machine->regs.w.cx == 0) return V8086_OK; do{ - dest = get_variable_length_register(machine, AX, width); + dest = get_variable_length_register(machine, V8086_AX, width); if(machine->internal_state.address_32_bit) source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.edi), width); else source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); - if(dest == NULL) return UNDEFINED_REGISTER; + if(dest == NULL) return V8086_UNDEFINED_REGISTER; if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); @@ -201,7 +201,7 @@ uint16_t perform_scas(v8086* machine, uint8_t width) } else if(width == 32){ dest_before = *((uint32_t*)dest); source_before = *((uint32_t*)source); - } else return BAD_WIDTH; + } else return V8086_BAD_WIDTH; result = dest_before - source_before; bit_write(machine->regs.d.eflags, 1u <> width) ? 1 : 0); // CARRY FLAG @@ -218,9 +218,9 @@ uint16_t perform_scas(v8086* machine, uint8_t width) else machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - if((machine->internal_state.rep_prefix == REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || - (machine->internal_state.rep_prefix == REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; + if((machine->internal_state.rep_prefix == V8086_REP_REPE && !bit_get(machine->regs.w.flags, ZERO_FLAG_BIT)) || + (machine->internal_state.rep_prefix == V8086_REPNE && bit_get(machine->regs.w.flags, ZERO_FLAG_BIT))) break; - } while(machine->internal_state.rep_prefix != NONE && --(machine->regs.w.cx)); - return OK; + } while(machine->internal_state.rep_prefix != V8086_NONE_REPEAT && --(machine->regs.w.cx)); + return V8086_OK; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 5bb20a5c..88522d04 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -27,11 +27,11 @@ void v8086_set_8086_instruction_set(v8086* machine) ASSIGN_OPCODE(0x1eu, push_ds); ASSIGN_OPCODE(0x1fu, pop_ds); GROUP_OF_OPCODES(0x20u, 0x25u, and); - //RESERVED TO SEG=ES PREFIX + //RESERVED TO SEG=V8086_ES PREFIX ASSIGN_NULL(0x26u); ASSIGN_OPCODE(0x27u, daa); GROUP_OF_OPCODES(0x28u, 0x2du, sub); - //RESERVED TO SEG=CS PREFIX + //RESERVED TO SEG=V8086_CS PREFIX ASSIGN_NULL(0x2eu); ASSIGN_OPCODE(0x2fu, das); GROUP_OF_OPCODES(0x30u, 0x35u, xor); @@ -136,7 +136,7 @@ void v8086_set_8086_instruction_set(v8086* machine) machine->operations_0fh[i] = NULL; } - machine->is_compatibility = IS8086; + machine->is_compatibility = V8086_IS8086; } void v8086_set_386_instruction_set(v8086* machine) @@ -232,7 +232,7 @@ void v8086_set_386_instruction_set(v8086* machine) ASSIGN_0FH_OPCODE(0xbeu, movsx); // BYTE MOVSX ASSIGN_0FH_OPCODE(0xbfu, movsx); //BYTE MOVSX - machine->is_compatibility = IS386; + machine->is_compatibility = V8086_IS386; } v8086* v8086_create_machine() @@ -253,21 +253,21 @@ int16_t v8086_call_function(v8086* machine) while(!(machine->IP.w.ip == 0xFFFF && machine->sregs.cs == 0xFFFF)) { int16_t status = parse_and_execute_instruction(machine); - if(status != OK) return status; + if(status != V8086_OK) return status; } - return OK; + return V8086_OK; } int16_t v8086_call_int(v8086* machine, int16_t num) { - if ((num < 0) || (num > 0xFF)) return BAD_INT_NUMBER; + if ((num < 0) || (num > 0xFF)) return V8086_BAD_INT_NUMBER; machine -> IP.w.ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); machine -> sregs.cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); push_word(machine, machine->regs.w.flags); push_word(machine, 0xFFFF); push_word(machine, 0xFFFF); int16_t x = v8086_call_function(machine); - if(x != OK) return x; + if(x != V8086_OK) return x; return num; } @@ -283,10 +283,10 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset = 0; machine->internal_state.operand_32_bit = 0; machine->internal_state.address_32_bit = 0; - machine->internal_state.segment_reg_select = DEFAULT; - machine->internal_state.rep_prefix = NONE; + machine->internal_state.segment_reg_select = V8086_DEFAULT; + machine->internal_state.rep_prefix = V8086_NONE_REPEAT; - int16_t status = OK; + int16_t status = V8086_OK; //Maybe opcode, an be also prefix uint8_t opcode; @@ -299,7 +299,7 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.IPOffset += 1; //PREFIXES - //Segment Prefix CS DS ES SS + //Segment Prefix V8086_CS DS V8086_ES SS if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment { machine->internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; @@ -308,13 +308,13 @@ int16_t parse_and_execute_instruction(v8086* machine) //Segment Prefix FS else if(opcode == 0x64) { - machine->internal_state.segment_reg_select = FS; + machine->internal_state.segment_reg_select = V8086_FS; goto decode; //continue parsing opcode; } //Segment Prefix GS else if(opcode == 0x65) { - machine->internal_state.segment_reg_select = GS; + machine->internal_state.segment_reg_select = V8086_GS; goto decode; //continue parsing opcode; } //Operand Size Prefix @@ -332,13 +332,13 @@ int16_t parse_and_execute_instruction(v8086* machine) //REPNE Prefix else if(opcode == 0xF2) { - machine->internal_state.rep_prefix = REPNE; + machine->internal_state.rep_prefix = V8086_REPNE; goto decode; //continue parsing opcode; } //REP/REPE Prefix else if(opcode == 0xF3) { - machine->internal_state.rep_prefix = REP_REPE; + machine->internal_state.rep_prefix = V8086_REP_REPE; goto decode; //continue parsing opcode; } //LOCK Prefix @@ -350,7 +350,7 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->operations[opcode] != NULL) status = machine->operations[opcode](machine, opcode); else - return UNDEFINED_OPCODE; + return V8086_UNDEFINED_OPCODE; machine->IP.w.ip += machine->internal_state.IPOffset; return status; diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index d0fe9b9c..f5cca108 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -19,40 +19,40 @@ #define OVERFLOW_FLAG_BIT 11u typedef enum _segment_register_select { - ES, CS, SS, DS, FS, GS, DEFAULT + V8086_ES, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT } segment_register_select; typedef enum _repeat_prefix { - NONE, REPNE, REP_REPE + V8086_NONE_REPEAT, V8086_REPNE, V8086_REP_REPE } repeat_prefix; enum instruction_set_compatibility{ - IS8086, IS386 + V8086_IS8086, V8086_IS386 }; -enum BYTE_REGISTERS {AL=0, CL, DL, BL, AH, CH, DH, BH}; -enum WORD_REGISTERS {AX=0, CX, DX, BX, SP, BP, SI, DI}; -enum DWORD_REGISTERS {EAX=0, ECX, EDX, EBX, ESP, EBP, ESI, EDI}; +enum BYTE_REGISTERS {V8086_AL=0, V8086_CL, V8086_DL, V8086_BL, V8086_AH, V8086_CH, V8086_DH, V8086_BH}; +enum WORD_REGISTERS {V8086_AX=0, V8086_CX, V8086_DX, V8086_BX, V8086_SP, V8086_BP, V8086_SI, V8086_DI}; +enum DWORD_REGISTERS {V8086_EAX=0, V8086_ECX, V8086_EDX, V8086_EBX, V8086_ESP, V8086_EBP, V8086_ESI, V8086_EDI}; typedef enum _machine_status { - OK = 0, - UNDEFINED_OPCODE = -1, - UNDEFINED_REGISTER = -2, - UNDEFINED_SEGMENT_REGISTER = -3, - UNABLE_GET_MEMORY = -4, - BAD_MOD_RM = -5, - BAD_RM = -6, - BAD_MOD = -7, - BAD_REG = -8, - BAD_WIDTH = -9, - BAD_INDEX = -10, - BAD_BASE = -11, - UNDEFINED_RECALCULATED_OPCODE = -12, - BAD_INT_NUMBER = -13, - RELATIVE_JMP_OVERFLOW = -14, - BOUND_ERROR = -15, - DIVISION_BY_ZERO = -16, - UNKNOWN_ERROR = -69 + V8086_OK = 0, + V8086_UNDEFINED_OPCODE = -1, + V8086_UNDEFINED_REGISTER = -2, + V8086_UNDEFINED_SEGMENT_REGISTER = -3, + V8086_UNABLE_GET_MEMORY = -4, + V8086_BAD_MOD_RM = -5, + V8086_BAD_RM = -6, + V8086_BAD_MOD = -7, + V8086_BAD_REG = -8, + V8086_BAD_WIDTH = -9, + V8086_BAD_INDEX = -10, + V8086_BAD_BASE = -11, + V8086_UNDEFINED_RECALCULATED_OPCODE = -12, + V8086_BAD_INT_NUMBER = -13, + V8086_RELATIVE_JMP_OVERFLOW = -14, + V8086_BOUND_ERROR = -15, + V8086_DIVISION_BY_ZERO = -16, + V8086_UNKNOWN_ERROR = -69 } machine_status; struct DWORDREGS { From 9d61ebcfb8d91a8cfd6ff724dcd3ee545d5558a7 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 7 Aug 2020 14:10:47 +0200 Subject: [PATCH 088/165] Some testing things. --- os/kernel/src/kernel.c | 36 ++++++++++++++++++++++++------------ os/kernel/src/v8086/v8086.c | 13 +++++++++---- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 1b655ad9..85d97804 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -35,7 +35,6 @@ #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" #include "v8086/v8086.h" -#include "gdb/gdb_stub.c" typedef struct _linesStruct { @@ -374,10 +373,9 @@ int kmain() clear_bss(); startup(); - - turn_on_serial_debugging(); - + logger_log_info("Hello, World!"); + //startup_music_play(); logger_log_ok("READY."); @@ -387,7 +385,6 @@ int kmain() // create_terminal(&d); // create_terminal(&d); - uint32_t d = 0; for (int i = 0; i < 4; i++) { @@ -402,27 +399,42 @@ int kmain() attach_process_to_terminal(ts[i].terminal_id, process_manager_get_process(p)); } + vga_clear_screen(); + switch_active_terminal(0); - - //process_manager_run(); + + //sprocess_manager_run(); + + uint32_t eax = 0; + uint32_t edx = 0; + int16_t temp_flags; + __asm__ __volatile__( + "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" + : "=b" (temp_flags), "=a" (eax), "=d"(edx) : "d" (0x5000), "c" (0xa) + ); v8086* v8086 = v8086_create_machine(); - v8086_set_386_instruction_set(v8086); + logger_log_info("Wyszedłem z funkcji"); + char str[100] = ""; + itoa(v8086, str, 16); + vga_printstring(str); + /*turn_on_serial_debugging(); + v8086_set_386_instruction_set(v8086);*/ //filesystem_create_file("A:/DUMP.BIN"); //bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); - v8086->regs.h.ah = 0x00; - v8086->regs.h.al = 0x13; + /*v8086->regs.h.ah = 0x00; + v8086->regs.h.al = 0x13;*/ //int16_t status = v8086_call_int(v8086, 0x10); //__asm__ __volatile__( //"mov %%dx, %%ax; pushfw;" //: : "d" (v8086->regs.w.ax) //); - int16_t temp_flags; + /*int16_t temp_flags; __asm__ __volatile__( "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (v8086->regs.d.eax), "=d"(v8086->regs.d.edx) : "d" (0x5000), "c" (0xa) @@ -444,7 +456,7 @@ int kmain() itoa(mem, str, 16); vga_printstring(str); vga_printstring(" "); - } + }*/ while (1); return 0; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 88522d04..f5227d86 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -239,13 +239,18 @@ v8086* v8086_create_machine() { v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); if(machine == NULL) return NULL; - memset(machine, 0, sizeof(v8086)); - machine->regs.x.flags = 0x2; + if(heap_kernel_verify_integrity()) + return 1; + else + return 0; + //*machine = zz; + //memset(machine, 0, sizeof(v8086)); + /*machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; machine->IP.w.ip = 0xfff0; memcpy(machine->Memory, (void*)0xc0000000, 0x100000); - v8086_set_8086_instruction_set(machine); - return machine; + v8086_set_8086_instruction_set(machine);*/ + //return machine; } int16_t v8086_call_function(v8086* machine) From 51b3b695eac19e96bd90b642bd0aba268714191a Mon Sep 17 00:00:00 2001 From: SzateX Date: Sat, 8 Aug 2020 14:47:11 +0200 Subject: [PATCH 089/165] Next testing things --- os/kernel/src/kernel.c | 43 +++++--------- .../v8086/operations/arithmetic_operations.c | 57 ++++++++++--------- os/kernel/src/v8086/v8086.c | 22 ++++--- os/kernel/src/v8086/v8086.h | 2 + 4 files changed, 60 insertions(+), 64 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 85d97804..de261947 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -404,41 +404,28 @@ int kmain() switch_active_terminal(0); - //sprocess_manager_run(); - - uint32_t eax = 0; - uint32_t edx = 0; - int16_t temp_flags; - __asm__ __volatile__( - "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (eax), "=d"(edx) : "d" (0x5000), "c" (0xa) - ); + //process_manager_run(); v8086* v8086 = v8086_create_machine(); - logger_log_info("Wyszedłem z funkcji"); - char str[100] = ""; - itoa(v8086, str, 16); - vga_printstring(str); - /*turn_on_serial_debugging(); - v8086_set_386_instruction_set(v8086);*/ + v8086_set_386_instruction_set(v8086); //filesystem_create_file("A:/DUMP.BIN"); //bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); + if(filesystem_is_file("A:/DUMP.BIN")) + filesystem_delete_file("A:/DUMP.BIN"); + + if(filesystem_is_file("A:/CSIP.BIN")) { + filesystem_delete_file("A:/CSIP.BIN"); + } + + filesystem_create_file("A:/CSIP.BIN"); //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); - /*v8086->regs.h.ah = 0x00; - v8086->regs.h.al = 0x13;*/ - //int16_t status = v8086_call_int(v8086, 0x10); - //__asm__ __volatile__( - //"mov %%dx, %%ax; pushfw;" - //: : "d" (v8086->regs.w.ax) - //); - /*int16_t temp_flags; - __asm__ __volatile__( - "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (v8086->regs.d.eax), "=d"(v8086->regs.d.edx) : "d" (0x5000), "c" (0xa) - ); + v8086->regs.h.ah = 0x00; + v8086->regs.h.al = 0x13; + int16_t status = v8086_call_int(v8086, 0x10); + char str[100] = ""; vga_printstring("IP: "); uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); @@ -456,7 +443,7 @@ int kmain() itoa(mem, str, 16); vga_printstring(str); vga_printstring(" "); - }*/ + } while (1); return 0; } diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index d0e0f785..080bf935 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -426,44 +426,47 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 uint16_t temp_flags; if (signed_div) { if (width == 8) { - if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movb %%dl, %%al; idiv %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) - ); + if(*((int8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + int16_t temp = (int16_t) machine->regs.w.ax / *((int8_t *) source); + if((temp > (int8_t)0x7f) || (temp < (int8_t)0x80)) return V8086_DIVISION_OVERFLOW; + machine->regs.h.al = temp; + machine->regs.h.ah = (int16_t) machine->regs.w.ax % *((int8_t *) source); } else if (width == 16) { if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movw %%dx, %%ax; idiv %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) - ); + int32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; + int32_t temp = dividend / *((int16_t *) source); + if((temp > (int16_t)0x7fff) || (temp < (int16_t)0x8000)) return V8086_DIVISION_OVERFLOW; + machine->regs.x.ax = temp; + machine->regs.x.dx = dividend % *((int16_t *) source); } else if (width == 32) { if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movl %%edx, %%eax; idiv %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) - ); + int64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; + int64_t temp = dividend / *((int32_t *) source); + if((temp > (int32_t)0x7fffffff) || (temp < (int32_t)0x80000000)) return V8086_DIVISION_OVERFLOW; + machine->regs.d.eax = temp; + machine->regs.d.edx = dividend % *((int32_t *) source); } else return V8086_BAD_WIDTH; } else { if (width == 8) { if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movb %%dl, %%al; div %%cl; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.w.ax) : "d" (machine->regs.h.al), "c" (*((uint8_t *) source)) - ); + uint16_t temp = machine->regs.w.ax / *((uint8_t *) source); + if(temp > 0xff) return V8086_DIVISION_OVERFLOW; + machine->regs.h.al = temp; + machine->regs.h.ah = machine->regs.w.ax % *((uint8_t *) source); } else if (width == 16) { if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movw %%dx, %%ax; div %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) - ); + uint32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; + uint32_t temp = dividend / *((uint16_t *) source); + if(temp > 0xffff) return V8086_DIVISION_OVERFLOW; + machine->regs.x.ax = temp; + machine->regs.x.dx = dividend % *((uint16_t *) source); } else if (width == 32) { - uint32_t temp = *((uint32_t *) source); - if(temp == 0) return V8086_DIVISION_BY_ZERO; - __asm__ __volatile__( - "movl %%edx, %%eax; div %%ecx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax), "=d"(machine->regs.d.edx) : "d" (machine->regs.d.eax), "c" (*((uint32_t *) source)) - ); + if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + uint64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; + uint64_t temp = dividend / *((uint32_t *) source); + if(temp > 0xffffffff) return V8086_DIVISION_OVERFLOW; + machine->regs.d.eax = temp; + machine->regs.d.edx = dividend % *((uint32_t *) source); } else return V8086_BAD_WIDTH; } return V8086_OK; diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f5227d86..c6263492 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -1,6 +1,7 @@ #include "v8086.h" #include "../memory/heap/heap.h" #include +#include #include "../assembly/io.h" #include "./memory_operations.h" #include "./stack.h" @@ -239,18 +240,13 @@ v8086* v8086_create_machine() { v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); if(machine == NULL) return NULL; - if(heap_kernel_verify_integrity()) - return 1; - else - return 0; - //*machine = zz; - //memset(machine, 0, sizeof(v8086)); - /*machine->regs.x.flags = 0x2; + memset(machine, 0, sizeof(v8086)); + machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; machine->IP.w.ip = 0xfff0; memcpy(machine->Memory, (void*)0xc0000000, 0x100000); - v8086_set_8086_instruction_set(machine);*/ - //return machine; + v8086_set_8086_instruction_set(machine); + return machine; } int16_t v8086_call_function(v8086* machine) @@ -302,6 +298,14 @@ int16_t parse_and_execute_instruction(v8086* machine) int x = 0; } machine->internal_state.IPOffset += 1; + char str[5] = ""; + itoa(machine->sregs.cs, str, 16); + bool s; + s = filesystem_append_to_file("A:/CSIP.BIN", str, 4); + if(!s) return V8086_DEBUG_FILE_OVERFLOW; + itoa(machine->IP.w.ip, str, 16); + s = filesystem_append_to_file("A:/CSIP.BIN", str, 4); + if(!s) return V8086_DEBUG_FILE_OVERFLOW; //PREFIXES //Segment Prefix V8086_CS DS V8086_ES SS diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index f5cca108..a026b165 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -52,6 +52,8 @@ typedef enum _machine_status { V8086_RELATIVE_JMP_OVERFLOW = -14, V8086_BOUND_ERROR = -15, V8086_DIVISION_BY_ZERO = -16, + V8086_DIVISION_OVERFLOW = -17, + V8086_DEBUG_FILE_OVERFLOW = -99, V8086_UNKNOWN_ERROR = -69 } machine_status; From 99e875e588ae9d95e0cab23b4617235a544b9510 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 8 Aug 2020 16:30:39 +0200 Subject: [PATCH 090/165] other new testing things --- os/kernel/src/kernel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index de261947..47b98457 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -430,11 +430,14 @@ int kmain() vga_printstring("IP: "); uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); uint16_t CS = *(uint16_t*)(v8086->Memory + 0x10 * 4 + 2); - itoa(IP, str, 10); + itoa(status, str, 16); + vga_printstring(str); + vga_newline(); + itoa(IP, str, 16); vga_printstring(str); vga_newline(); vga_printstring("CS: "); - itoa(CS, str, 10); + itoa(CS, str, 16); vga_printstring(str); vga_newline(); for(uint32_t i = CS * 16 + IP; i < (CS * 16 + IP + 16); i++) From 151af531dc4f894a78bb0c23fb3d83771fd6b4b3 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 13 Aug 2020 01:35:34 +0200 Subject: [PATCH 091/165] trying to add more descriptive debug for v8086 - stuck on implementing kernel version of sprintf --- .../src/debug_helpers/library/kernel_stdio.h | 59 +++++++++++++++++ .../library/stdio/kernel_setvbuf.c | 24 +++++++ .../library/stdio/kernel_sprintf.c | 19 ++++++ .../library/stdio/kernel_stdio.c | 15 +++++ os/kernel/src/kernel.c | 26 ++++++-- os/kernel/src/v8086/v8086.c | 66 +++++++++++++++++-- os/kernel/src/v8086/v8086.h | 2 + 7 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 os/kernel/src/debug_helpers/library/kernel_stdio.h create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_stdio.c diff --git a/os/kernel/src/debug_helpers/library/kernel_stdio.h b/os/kernel/src/debug_helpers/library/kernel_stdio.h new file mode 100644 index 00000000..19b1eace --- /dev/null +++ b/os/kernel/src/debug_helpers/library/kernel_stdio.h @@ -0,0 +1,59 @@ +#ifndef STDIO_H +#define STDIO_H + +#include + +//! Size of the stream buffer +#define BUFSIZ 1024 * 32 + +//! Value returned when internal stream position has reached the end of file +#define EOF -1 + +//! Maximum length of file names +#define FILENAME_MAX 255 + +//! Potential limit of simultaneous open streams +#define FOPEN_MAX INT32_MAX + +//! Minimum length for temporary file name +#define L_tmpnam 0 + +//! Maximum number of temporary files +#define TMP_MAX 0 + +//! Seek-Set mode (position is absolute) +#define SEEK_SET 0 + +//! Seek-Current mode (relative to the current position) +#define SEEK_CUR 1 + +//! Seek-End mode (relative to the end of the file) +#define SEEK_END 2 + +//! No Buffering mode +#define _IONBF 0 + +//! Line Buffering mode +#define _IOLBF 1 + +//! Full Buffering mode +#define _IOFBF 2 + +#include +#include +#include "stdlib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int kernel_setvbuf(FILE *stream, char *buffer, int mode, size_t size); +int kernel_sprintf(char *str, const char *format, ...); + +FILE *__kernel_stdio_create_stream(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c b/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c new file mode 100644 index 00000000..22bd0573 --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c @@ -0,0 +1,24 @@ +#include "../../../memory/heap/heap.h" +#include + +int kernel_setvbuf(FILE *stream, char *buffer, int mode, size_t size) +{ + if (mode < 0 || mode > 2) + { + return -1; + } + + heap_kernel_dealloc(stream->buffer); + + if (buffer == NULL) + { + buffer = heap_kernel_alloc(size, 0); + } + else + { + stream->buffer = buffer; + } + + stream->buffering_mode = mode; + return 0; +} \ No newline at end of file diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c b/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c new file mode 100644 index 00000000..6fecfe1b --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c @@ -0,0 +1,19 @@ +#include "stdio.h" +#include "library/src/stdio.h" + +int kernel_sprintf(char *str, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + + FILE *stream = __kernel_stdio_create_stream(); + kernel_setvbuf(stream, str, _IOFBF, 0); + + int ret = vfprintf(stream, format, arg) + 1; + + str[ret] = '\0'; + + va_end(arg); + + return ret; +} \ No newline at end of file diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_stdio.c b/os/kernel/src/debug_helpers/library/stdio/kernel_stdio.c new file mode 100644 index 00000000..615d0b07 --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_stdio.c @@ -0,0 +1,15 @@ +#include "memory/heap/heap.h" +#include + +FILE *__kernel_stdio_create_stream() +{ + FILE *stream = heap_kernel_alloc(sizeof(FILE), 0); + stream->buffer = heap_kernel_alloc(BUFSIZ, 0); + stream->base = 0; + stream->pos = 0; + stream->size = 0; + stream->limit = 0; + stream->buffering_mode = file_buffering_mode_line; + + return stream; +} \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 47b98457..538525a7 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -414,11 +414,29 @@ int kmain() if(filesystem_is_file("A:/DUMP.BIN")) filesystem_delete_file("A:/DUMP.BIN"); - if(filesystem_is_file("A:/CSIP.BIN")) { - filesystem_delete_file("A:/CSIP.BIN"); - } + //if(filesystem_is_file("A:/SEG0x40.BIN")) + // filesystem_delete_file("A:/SEG0x40.BIN"); + + filesystem_create_file("A:/DUMP.BIN"); + bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); + + //filesystem_create_file("A:/SEG0x40.BIN"); + //dupa = filesystem_save_to_file("A:/SEG0x40.BIN", (char*) v8086->Memory + 0x400, 64*1024); + + serial_init(COM1_PORT, 9600, 8, 1, PARITY_NONE); + keyboard_scan_ascii_pair kb; + vga_printstring("Press key to continue... (Sending Debug Informations via serial)"); + while(!keyboard_get_key_from_buffer(&kb)); + /*for(long long i = 0; i < 1024*1024; i++) + { + serial_send(COM1_PORT, *((char*) v8086->Memory + i)); + }*/ + + //if(filesystem_is_file("A:/CSIP.BIN")) { + //filesystem_delete_file("A:/CSIP.BIN"); + //} - filesystem_create_file("A:/CSIP.BIN"); + //filesystem_create_file("A:/CSIP.BIN"); //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index c6263492..d8afa974 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -9,6 +9,12 @@ #include "./operations/internal_funcs.h" #include "./operations/arithmetic_operations.h" #include "./operations/opcodes.h" +#include +#include "../debug_helpers/library/kernel_stdio.h" + +#ifdef DEBUG_V8086 + #include "../drivers/serial/serial.h" +#endif int16_t parse_and_execute_instruction(v8086* machine); @@ -244,6 +250,9 @@ v8086* v8086_create_machine() machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; machine->IP.w.ip = 0xfff0; + machine->sregs.ss = 0x0; + machine->regs.d.ebp = 0x7bff; + machine->regs.d.esp = 0x7bff; memcpy(machine->Memory, (void*)0xc0000000, 0x100000); v8086_set_8086_instruction_set(machine); return machine; @@ -289,23 +298,67 @@ int16_t parse_and_execute_instruction(v8086* machine) int16_t status = V8086_OK; + #ifdef DEBUG_V8086 + serial_send_string(COM1_PORT, "REGS:\n"); + char str[100] = ""; + kernel_sprintf(str, "AL:%02X AH:%02X AX:%04X eAX:%08X\n", machine->regs.h.al, machine->regs.h.ah, machine->regs.x.ax, machine->regs.d.eax); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "BL:%02X BH:%02X BX:%04X eBX:%08X\n", machine->regs.h.bl, machine->regs.h.bh, machine->regs.x.bx, machine->regs.d.ebx); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "CL:%02X CH:%02X CX:%04X eCX:%08X\n", machine->regs.h.cl, machine->regs.h.ch, machine->regs.x.cx, machine->regs.d.ecx); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "DL:%02X DH:%02X DX:%04X eDX:%08X\n", machine->regs.h.dl, machine->regs.h.dh, machine->regs.x.dx, machine->regs.d.edx); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "DI:%04X eDI:%04X\n", machine->regs.h.di, machine->regs.d.edi); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "SI:%04X eSI:%04X\n", machine->regs.h.si, machine->regs.d.esi); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "FLAGS:%04X\n", machine->regs.w.flags); + serial_send_string(COM1_PORT, str); + serial_send_string(COM1_PORT, "SREGS:\n"); + kernel_sprintf(str, "DS:%04X ES:%04X\n", machine->sregs.ds, machine->sregs.es); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "FS:%04X GS:%04X\n", machine->sregs.fs, machine->sregs.gs); + serial_send_string(COM1_PORT, str); + serial_send_string(COM1_PORT, "STACK:\n"); + kernel_sprintf(str, "BP:%04X eBP:%08X\n", machine->regs.h.bp, machine->regs.d.ebp); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "SP:%04X eSP:%08X\n", machine->regs.h.sp, machine->regs.d.esp); + serial_send_string(COM1_PORT, str); + kernel_sprintf(str, "SS:%04X\n", machine->sregs.ss); + serial_send_string(COM1_PORT, str); + if((machine->regs.d.esp > 0x7bff) || (machine->sregs.ss != 0x0)) + serial_send_string(COM1_PORT, "WEIRD STACK ADDRESS!\n"); + else{ + serial_send_string(COM1_PORT, "---\n"); + for(uint32_t i=0x7bff; i <=machine->regs.d.esp; i-=2) + { + kernel_sprintf(str, "%02X %02X", read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.d.esp)), read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.d.esp - 1))); + serial_send_string(COM1_PORT, str); + } + serial_send_string(COM1_PORT, "---\n"); + } + serial_send_string(COM1_PORT, "INSTRUCTION ADDRESS:\n"); + kernel_sprintf(str, "CS:%04X\n IP:%04X", machine->IP.w.ip); + serial_send_string(COM1_PORT, str); + #endif + //Maybe opcode, an be also prefix uint8_t opcode; decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - if(machine->IP.w.ip == 0x0f04u) { - int x = 0; - } machine->internal_state.IPOffset += 1; - char str[5] = ""; + + + /*char str[5] = ""; itoa(machine->sregs.cs, str, 16); bool s; s = filesystem_append_to_file("A:/CSIP.BIN", str, 4); if(!s) return V8086_DEBUG_FILE_OVERFLOW; itoa(machine->IP.w.ip, str, 16); s = filesystem_append_to_file("A:/CSIP.BIN", str, 4); - if(!s) return V8086_DEBUG_FILE_OVERFLOW; + if(!s) return V8086_DEBUG_FILE_OVERFLOW;*/ //PREFIXES //Segment Prefix V8086_CS DS V8086_ES SS @@ -362,5 +415,8 @@ int16_t parse_and_execute_instruction(v8086* machine) return V8086_UNDEFINED_OPCODE; machine->IP.w.ip += machine->internal_state.IPOffset; + #ifdef DEBUG_V8086 + serial_send_string(COM1_PORT, "------------------------------------------\n"); + #endif return status; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index a026b165..5273989c 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -18,6 +18,8 @@ #define DIRECTION_FLAG_BIT 10u #define OVERFLOW_FLAG_BIT 11u +#define DEBUG_V8086 + typedef enum _segment_register_select { V8086_ES, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT } segment_register_select; From 94afb2bd5bca34f02d53871e15c337a894189c3e Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 13 Aug 2020 02:24:31 +0200 Subject: [PATCH 092/165] Added more stdlib in kernel_version --- .../src/debug_helpers/library/kernel_stdio.h | 10 +- .../library/stdio/kernel_fflush.c | 19 + .../library/stdio/kernel_fputc.c | 12 + .../library/stdio/kernel_fwrite.c | 65 ++ .../library/stdio/kernel_setvbuf.c | 2 +- .../library/stdio/kernel_sprintf.c | 5 +- .../library/stdio/kernel_vfprintf.c | 950 ++++++++++++++++++ 7 files changed, 1057 insertions(+), 6 deletions(-) create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_fflush.c create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_fputc.c create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_fwrite.c create mode 100644 os/kernel/src/debug_helpers/library/stdio/kernel_vfprintf.c diff --git a/os/kernel/src/debug_helpers/library/kernel_stdio.h b/os/kernel/src/debug_helpers/library/kernel_stdio.h index 19b1eace..8991f622 100644 --- a/os/kernel/src/debug_helpers/library/kernel_stdio.h +++ b/os/kernel/src/debug_helpers/library/kernel_stdio.h @@ -1,7 +1,7 @@ -#ifndef STDIO_H -#define STDIO_H +#ifndef KERNEL_STDIO_H +#define KERNEL_STDIO_H -#include +#include "stdio.h" //! Size of the stream buffer #define BUFSIZ 1024 * 32 @@ -49,6 +49,10 @@ extern "C" { int kernel_setvbuf(FILE *stream, char *buffer, int mode, size_t size); int kernel_sprintf(char *str, const char *format, ...); +int kernel_vfprintf(FILE *stream, const char *format, va_list arg); +int kernel_fputc(int character, FILE *stream); +size_t kernel_fwrite(const void *ptr, size_t size, size_t count, FILE *stream); +int kernel_fflush(FILE *stream); FILE *__kernel_stdio_create_stream(); diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_fflush.c b/os/kernel/src/debug_helpers/library/stdio/kernel_fflush.c new file mode 100644 index 00000000..5ce73d00 --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_fflush.c @@ -0,0 +1,19 @@ +#include "../kernel_stdio.h" +#include "stdio.h" + +int kernel_fflush(FILE *stream) +{ + if (stream == NULL) + { + return kernel_fflush(stdin) | kernel_fflush(stdout) | kernel_fflush(stderr); + } + else + { + stream->flush(stream); + stream->pos = 0; + stream->size = 0; + stream->base = 0; + } + + return 0; +} \ No newline at end of file diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_fputc.c b/os/kernel/src/debug_helpers/library/stdio/kernel_fputc.c new file mode 100644 index 00000000..dd6dcada --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_fputc.c @@ -0,0 +1,12 @@ +#include "../kernel_stdio.h" + +int kernel_fputc(int character, FILE *stream) +{ + if (kernel_fwrite(&character, 1, 1, stream) != 1) + { + stream->error = 1; + return EOF; + } + + return character; +} \ No newline at end of file diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_fwrite.c b/os/kernel/src/debug_helpers/library/stdio/kernel_fwrite.c new file mode 100644 index 00000000..8d776507 --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_fwrite.c @@ -0,0 +1,65 @@ +#include "../kernel_stdio.h" + +size_t kernel_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) +{ + uint32_t total_size = size * count; + + if (stream->pos + total_size > BUFSIZ) + { + kernel_fflush(stream); + } + + switch (stream->buffering_mode) + { + case file_buffering_mode_none: + { + memcpy(stream->buffer + (stream->pos - stream->base), ptr, total_size); + stream->pos += total_size; + stream->size += total_size; + + kernel_fflush(stream); + + break; + } + + case file_buffering_mode_line: + { + uint32_t origin = 0; + for (uint32_t i = origin; i < total_size; i++) + { + char c = ((const char *)ptr)[i]; + if (c == '\n') + { + uint32_t bytes_to_copy = i - origin + 1; + + memcpy(stream->buffer + (stream->pos - stream->base), ptr + origin, bytes_to_copy); + kernel_fflush(stream); + + origin = i + 1; + } + } + + if (origin != total_size) + { + uint32_t bytes_to_copy = total_size - origin - 1; + + memcpy(stream->buffer + (stream->pos - stream->base), ptr + origin, bytes_to_copy); + stream->pos += bytes_to_copy; + stream->size += bytes_to_copy; + } + + break; + } + + case file_buffering_mode_full: + { + memcpy(stream->buffer + (stream->pos - stream->base), ptr, total_size); + stream->pos += total_size; + stream->size += total_size; + + break; + } + } + + return total_size; +} \ No newline at end of file diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c b/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c index 22bd0573..aaa82b4c 100644 --- a/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_setvbuf.c @@ -1,5 +1,5 @@ #include "../../../memory/heap/heap.h" -#include +#include "stdio.h" int kernel_setvbuf(FILE *stream, char *buffer, int mode, size_t size) { diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c b/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c index 6fecfe1b..7d1dfe60 100644 --- a/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_sprintf.c @@ -1,5 +1,6 @@ #include "stdio.h" -#include "library/src/stdio.h" +#include "stdarg.h" +#include "../kernel_stdio.h" int kernel_sprintf(char *str, const char *format, ...) { @@ -9,7 +10,7 @@ int kernel_sprintf(char *str, const char *format, ...) FILE *stream = __kernel_stdio_create_stream(); kernel_setvbuf(stream, str, _IOFBF, 0); - int ret = vfprintf(stream, format, arg) + 1; + int ret = kernel_vfprintf(stream, format, arg) + 1; str[ret] = '\0'; diff --git a/os/kernel/src/debug_helpers/library/stdio/kernel_vfprintf.c b/os/kernel/src/debug_helpers/library/stdio/kernel_vfprintf.c new file mode 100644 index 00000000..ed481e93 --- /dev/null +++ b/os/kernel/src/debug_helpers/library/stdio/kernel_vfprintf.c @@ -0,0 +1,950 @@ +#include +#include "stdlib.h" +#include "string.h" +#include "math.h" +#include "stdio.h" +#include "stdbool.h" +#include "stdint.h" +#include "../../../memory/heap/heap.h" + +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_LONG_DOUBLE (1U << 11U) + +typedef long long int i64; +typedef unsigned long long int u64; + +// HELPER FUNCTIONS +bool _kernel_is_digit(char c) +{ + return c >= '0' && c <= '9'; +} + +int _kernel_max(int a, int b) +{ + return a > b ? a : b; +} + +unsigned int _kernel_unsigned_number_len(u64 n, int base) +{ + unsigned int res = 1; + + while (n >= (unsigned int)base) + { + res++; + n /= base; + } + + return res; +} + +unsigned int _kernel_fnumber_len(long double n) +{ + if (n == 0) + return 1; + return floor(log10(fabs(n))) + 1; +} + +char *_kernel_itoa(u64 number, char *buffer, int base, bool uppercase, int size) +{ + int idx = size - 1; + static const char lowercase_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + static const char uppercase_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + do + { + int digit = (number % base); + buffer[idx--] = uppercase ? (uppercase_table[digit]) : (lowercase_table[digit]); + + number /= base; + } while (number); + buffer[size] = '\0'; + + return buffer; +} + +char *_kernel_ftoa(long double number, char *buffer, unsigned short flags, int precision) +{ + + float whole = floor(number); + float frac = number - whole; + + // change frac value so it has no significant zeros + // they will be printed later + int num_zeros = 0; + while (frac < 0.1) + { + frac *= 10; + num_zeros++; + } + + frac = floor(pow(10, precision - num_zeros) * frac); + + int whole_size = _kernel_fnumber_len(whole); + int frac_size = precision; + + int idx = whole_size; + + while (idx) + { + buffer[idx - 1] = (char)fmod(whole, 10) + '0'; + whole /= 10; + idx--; + } + + if (precision != 0 || flags & FLAGS_HASH) + { + buffer[whole_size] = '.'; + } + + idx = whole_size + frac_size; + buffer[idx + 1] = '\0'; + + while (frac >= 1) + { + buffer[idx--] = (char)fmod(frac, 10) + '0'; + frac /= 10; + } + + idx = whole_size + 1; + for (int i = 0; i < num_zeros; i++) + { + buffer[idx++] = '0'; + } + + return buffer; +} + +void _kernel_put_unsigned_integer(FILE *stream, unsigned int *put_idx, u64 number, unsigned short flags, int base, int width, int precision) +{ + int int_len = _kernel_unsigned_number_len(number, base); // length of the number + + char *number_buf = (char *)heap_kernel_alloc((int_len + 1) * sizeof(char), 0); + _kernel_itoa(number, number_buf, base, flags & FLAGS_UPPERCASE, int_len); + + // 0x and 0 + if (flags & FLAGS_HASH) + { + if (base == 8) + { + int_len += 1; + } + else if (base == 16) + { + int_len += 2; + } + } + + if (flags & FLAGS_PLUS || flags & FLAGS_SPACE) + { + int_len += 1; + } + + int zeros_count = precision - int_len; + int space_count = width - _kernel_max(precision, int_len); + + // Pre padding + char prepadding_character = flags & FLAGS_ZEROPAD ? '0' : ' '; + if (!(flags & FLAGS_LEFT)) + { + for (int i = space_count; i > 0; i--) + { + kernel_fputc(prepadding_character, stream); + (*put_idx)++; + } + } + + // Sign or Space + if (flags & FLAGS_PLUS) + { + kernel_fputc('+', stream); + (*put_idx)++; + } + else if (flags & FLAGS_SPACE) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + + // 0x and 0 + if (flags & FLAGS_HASH) + { + if (base == 8) + { + kernel_fputc('0', stream); + (*put_idx)++; + } + else if (base == 16) + { + kernel_fputc('0', stream); + (*put_idx)++; + + kernel_fputc(flags & FLAGS_UPPERCASE ? 'X' : 'x', stream); + (*put_idx)++; + } + } + + // Zeros + for (int i = zeros_count; i > 0; i--) + { + kernel_fputc('0', stream); + (*put_idx)++; + } + + // Actual number + for (int i = 0; number_buf[i] != '\0'; i++) + { + kernel_fputc(number_buf[i], stream); + (*put_idx)++; + } + + // Post padding + if (flags & FLAGS_LEFT) + { + for (int i = space_count; i > 0; i--) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + } + + heap_kernel_dealloc(number_buf); +} + +void _kernel_put_signed_integer(FILE *stream, unsigned int *put_idx, i64 number, unsigned short flags, int base, int width, int precision) +{ + bool negative = false; + if (number < 0) + { + number *= -1; + negative = true; + } + + int int_len = _kernel_unsigned_number_len(number, base); // length of the number + + char *number_buf = (char *)heap_kernel_alloc((int_len + 1) * sizeof(char), 0); + _kernel_itoa(number, number_buf, base, flags & FLAGS_UPPERCASE, int_len); + + if (flags & FLAGS_PLUS || flags & FLAGS_SPACE || negative) + { + int_len += 1; + } + + int zeros_count = precision - int_len; + int space_count = width - _kernel_max(precision, int_len); + + // Pre padding + char prepadding_character = flags & FLAGS_ZEROPAD ? '0' : ' '; + if (!(flags & FLAGS_LEFT)) + { + for (int i = space_count; i > 0; i--) + { + kernel_fputc(prepadding_character, stream); + (*put_idx)++; + } + } + + // Sign + if (negative) + { + kernel_fputc('-', stream); + (*put_idx)++; + } + else if (flags & FLAGS_PLUS) + { + kernel_fputc('+', stream); + (*put_idx)++; + } + else if (flags & FLAGS_SPACE) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + + // Zeros + for (int i = zeros_count; i > 0; i--) + { + kernel_fputc('0', stream); + (*put_idx)++; + } + + // Actual number + for (int i = 0; number_buf[i] != '\0'; i++) + { + kernel_fputc(number_buf[i], stream); + (*put_idx)++; + } + + // Post padding + if (flags & FLAGS_LEFT) + { + for (int i = space_count; i > 0; i--) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + } + + heap_kernel_dealloc(number_buf); +} + +void _kernel_put_float(FILE *stream, unsigned int *put_idx, long double number, unsigned short flags, int width, int precision) +{ + // Print NAN + if (isnan(number)) + { + kernel_fputc('n', stream); + kernel_fputc('a', stream); + kernel_fputc('n', stream); + (*put_idx) += 3; + return; + } + + // Print INF + if (isinf(number)) + { + char sign = number < 0 ? '-' : '+'; + kernel_fputc(sign, stream); + kernel_fputc('i', stream); + kernel_fputc('n', stream); + kernel_fputc('f', stream); + (*put_idx) += 4; + return; + } + + bool negative = number < 0; + if (negative) + { + number *= -1; + } + + if (!(flags & FLAGS_PRECISION)) + { + precision = 6; + } + + int whole_len = _kernel_fnumber_len(number); + if (whole_len < 0) + whole_len = 0; + int number_len = whole_len + precision + 2; // +2 because of '.' and '\0' + char *num_buff = (char *)heap_kernel_alloc(sizeof(char) * number_len, 0); + + int num_spaces = width - whole_len; + + num_buff = _kernel_ftoa(number, num_buff, flags, precision); + + if (negative || flags & FLAGS_PLUS || flags & FLAGS_SPACE) + { + num_spaces--; + } + + if (!(flags & FLAGS_LEFT)) + { + char pad_char = ((flags & FLAGS_ZEROPAD) ? '0' : ' '); + for (int i = 0; i < num_spaces; i++) + { + kernel_fputc(pad_char, stream); + (*put_idx)++; + } + } + + if (negative) + { + kernel_fputc('-', stream); + (*put_idx)++; + } + else if (flags & FLAGS_PLUS) + { + kernel_fputc('+', stream); + (*put_idx)++; + } + else if (flags & FLAGS_SPACE) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + + int idx = 0; + while (num_buff[idx] != '\0') + { + kernel_fputc(num_buff[idx++], stream); + (*put_idx)++; + } + + if (flags & FLAGS_LEFT) + { + for (int i = 0; i < num_spaces; i++) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + } + + heap_kernel_dealloc(num_buff); +} + +void _kernel_put_scientific_notation(FILE *stream, unsigned int *put_idx, long double number, unsigned short flags, int width, int precision) +{ + int exponent = 0; + + bool negative = number < 0; + if (negative) + { + number *= -1; + } + + if (!(flags & FLAGS_PRECISION)) + { + precision = 6; + } + + // scale number to fit <1, 10> range + // and specify its exponent + while (!(number >= 1 && number < 10)) + { + if (number < 1) + { + + number *= 10; + exponent--; + } + else + { + number /= 10; + exponent++; + } + } + int exponent_len = _kernel_unsigned_number_len(fabs(exponent), 10); + + int num_spaces = width - precision - 2; // -2 because of one digit before decimal point and decimal point itself + num_spaces -= 2; // e notation and exponent sign + num_spaces -= exponent_len; + + if (negative || flags & FLAGS_PLUS || flags & FLAGS_SPACE) + { + num_spaces--; + } + + // Pre Padding + if (!(flags & FLAGS_LEFT)) + { + char pad_char = ((flags & FLAGS_ZEROPAD) ? '0' : ' '); + for (int i = 0; i < num_spaces; i++) + { + kernel_fputc(pad_char, stream); + (*put_idx)++; + } + } + + // SIGN + if (negative) + { + kernel_fputc('-', stream); + (*put_idx)++; + } + else if (flags & FLAGS_PLUS) + { + kernel_fputc('+', stream); + (*put_idx)++; + } + else if (flags & FLAGS_SPACE) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + + // Actual number + // We know that number must have 1 digit before decimal point + // So we just cast it to int and make char from it + // kernel_fputc((int)number + '0', stream); + // (*put_idx)++; + + // if (precision != 0 || flags & FLAGS_HASH) + // { + // kernel_fputc('.', stream); + // (*put_idx)++; + // } + + // // Digits after decimal point + // double integer; + // double fract = modf(number, &integer); + + // fract *= pow(10, precision); + // char *num_buff = (char *)malloc(sizeof(char) * (precision + 1)); + // num_buff = _itoa(fract, num_buff, 10, false, precision); + + // int idx = 0; + // while (num_buff[idx] != '\0') + // { + // kernel_fputc(num_buff[idx++], stream); + // (*put_idx)++; + // } + + char *num_buff = (char *)heap_kernel_alloc(precision + 3, 0); + num_buff = _kernel_ftoa(number, num_buff, flags, precision); + int idx = 0; + while (num_buff[idx] != '\0') + { + kernel_fputc(num_buff[idx++], stream); + (*put_idx)++; + } + + // Exponent + kernel_fputc((flags & FLAGS_UPPERCASE ? 'E' : 'e'), stream); + (*put_idx)++; + + // Exponent sign + if (exponent < 0) + { + kernel_fputc('-', stream); + (*put_idx)++; + + exponent *= -1; + } + else + { + kernel_fputc('+', stream); + (*put_idx)++; + } + + num_buff = heap_kernel_realloc(num_buff, sizeof(char) * (exponent_len + 1), 0); + + _kernel_itoa(exponent, num_buff, 10, false, exponent_len); + idx = 0; + while (num_buff[idx] != '\0') + { + kernel_fputc(num_buff[idx++], stream); + (*put_idx)++; + } + + if (flags & FLAGS_LEFT) + { + for (int i = 0; i < num_spaces; i++) + { + kernel_fputc(' ', stream); + (*put_idx)++; + } + } + + heap_kernel_dealloc(num_buff); +} + +unsigned int _kernel_parse_number_field(const char **str) +{ + unsigned int ret = 0; + while (_kernel_is_digit(**str)) + { + ret = ret * 10 + (unsigned int)(**str - '0'); + (*str)++; + } + + return ret; +} + +int kernel_vfprintf(FILE *stream, const char *format, va_list arg) +{ + unsigned int put_index = 0; + + unsigned short flags = 0; + int width_field = 0; + int precision_field = 0; + + const char *traverse; + for (traverse = format; *traverse != '\0'; ++traverse) + { + + // if travese is '%' just put character to buffer + // else go to next character, check if it's not null + // and then parse arguments + + if (*traverse != '%') + { + kernel_fputc(*traverse, stream); + put_index++; + } + else + { + // Check next character + ++traverse; + if (*traverse == '\0') + { + // End of string, break loop + break; + } + + // Parse format string + // %[flags][width][.precision][length]specifier + + // evaluate flags + bool f = true; + do + { + switch (*traverse) + { + case '0': + flags |= FLAGS_ZEROPAD; + ++traverse; + break; + case '-': + flags |= FLAGS_LEFT; + ++traverse; + break; + case '+': + flags |= FLAGS_PLUS; + ++traverse; + break; + case ' ': + flags |= FLAGS_SPACE; + ++traverse; + break; + case '#': + flags |= FLAGS_HASH; + ++traverse; + break; + default: + f = false; + break; + } + } while (f); + + // evaluate width + if (_kernel_is_digit(*traverse)) + { + width_field = _kernel_parse_number_field(&traverse); + } + else if (*traverse == '*') + { + int w = va_arg(arg, int); + if (w < 0) + { + flags |= FLAGS_LEFT; + width_field = -w; + } + else + { + width_field = w; + } + ++traverse; + } + + // evaluate precision + if (*traverse == '.') + { + flags |= FLAGS_PRECISION; + ++traverse; + if (_kernel_is_digit(*traverse)) + { + precision_field = _kernel_parse_number_field(&traverse); + } + else if (*traverse == '*') + { + int prec = va_arg(arg, int); + precision_field = prec > 0 ? prec : 0; + ++traverse; + } + } + + // evaluate length field + switch (*traverse) + { + case 'l': + flags |= FLAGS_LONG; + ++traverse; + if (*traverse == 'l') + { + flags |= FLAGS_LONG_LONG; + ++traverse; + } + break; + case 'h': + flags |= FLAGS_SHORT; + ++traverse; + if (*traverse == 'h') + { + flags |= FLAGS_CHAR; + ++traverse; + } + break; + case 'L': + flags |= FLAGS_LONG_DOUBLE; + ++traverse; + break; + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ++traverse; + break; + + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ++traverse; + break; + + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ++traverse; + break; + } + + // Parse arguments + switch (*traverse) + { + case 'c': // CHARACTER + { + + // Right padding + if (!(flags & FLAGS_LEFT)) + { + for (int i = width_field - 1; i > 0; i--) + { + kernel_fputc(' ', stream); + put_index++; + } + } + + // @INCOMPLETE: wide characters support when it will be ready + int char_arg = va_arg(arg, int); + kernel_fputc(char_arg, stream); + + put_index++; + + // Left padding + if (flags & FLAGS_LEFT) + { + for (int i = width_field - 1; i > 0; i--) + { + kernel_fputc(' ', stream); + put_index++; + } + } + break; + } + + case 'd': // INTEGER + case 'i': + { + i64 int_arg; + if (flags & FLAGS_LONG) + { + int_arg = va_arg(arg, long int); + } + else if (flags & FLAGS_LONG_LONG) + { + int_arg = va_arg(arg, i64); + } + else + { + int_arg = va_arg(arg, int); + } + + _kernel_put_signed_integer(stream, &put_index, int_arg, flags, 10, width_field, precision_field); + } + break; + + case 'o': // OCTAL INTEGER + { + u64 int_arg; + if (flags & FLAGS_LONG) + { + int_arg = va_arg(arg, unsigned long int); + } + else if (flags & FLAGS_LONG_LONG) + { + int_arg = va_arg(arg, u64); + } + else + { + int_arg = va_arg(arg, unsigned int); + } + _kernel_put_unsigned_integer(stream, &put_index, int_arg, flags, 8, width_field, precision_field); + break; + } + + case 's': // STRING + { + char *str_arg = va_arg(arg, char *); + int str_len = strlen(str_arg); + + // Check maximum number of characters (precision field) + if (flags & FLAGS_PRECISION) + { + str_len = str_len > precision_field ? precision_field : str_len; + } + + // Right padding + if (!(flags & FLAGS_LEFT)) + { + for (int i = (width_field - str_len); i > 0; i--) + { + kernel_fputc(' ', stream); + put_index++; + } + } + + // put arg to buffer + for (int i = 0; i < str_len; i++) + { + kernel_fputc(str_arg[i], stream); + put_index++; + } + + // Left Padding + if (flags & FLAGS_LEFT) + { + for (int i = (width_field - str_len); i > 0; i--) + { + kernel_fputc(' ', stream); + put_index++; + } + } + } + break; + + case 'X': + flags |= FLAGS_UPPERCASE; // Uppercase X + case 'x': // HEX INTEGER + { + u64 int_arg; + if (flags & FLAGS_LONG) + { + int_arg = va_arg(arg, unsigned long int); + } + else if (flags & FLAGS_LONG_LONG) + { + int_arg = va_arg(arg, u64); + } + else + { + int_arg = va_arg(arg, unsigned int); + } + _kernel_put_unsigned_integer(stream, &put_index, int_arg, flags, 16, width_field, precision_field); + break; + } + + case 'F': + case 'f': + { + long double d_arg; + if (flags & FLAGS_LONG_DOUBLE) + { + d_arg = va_arg(arg, long double); + } + else + { + d_arg = va_arg(arg, double); + } + + _kernel_put_float(stream, &put_index, d_arg, flags, width_field, precision_field); + + break; + } + + case 'u': + { + u64 int_arg; + if (flags & FLAGS_LONG) + { + int_arg = va_arg(arg, unsigned long int); + } + else if (flags & FLAGS_LONG_LONG) + { + int_arg = va_arg(arg, u64); + } + else + { + int_arg = va_arg(arg, unsigned int); + } + _kernel_put_unsigned_integer(stream, &put_index, int_arg, flags, 10, width_field, precision_field); + break; + } + + case 'E': + flags |= FLAGS_UPPERCASE; + case 'e': + { + long double d_arg; + if (flags & FLAGS_LONG_DOUBLE) + { + d_arg = va_arg(arg, long double); + } + else + { + d_arg = va_arg(arg, double); + } + _kernel_put_scientific_notation(stream, &put_index, d_arg, flags, width_field, precision_field); + break; + } + + case 'G': + flags |= FLAGS_UPPERCASE; + case 'g': + { + long double d_arg; + if (flags & FLAGS_LONG_DOUBLE) + { + d_arg = va_arg(arg, long double); + } + else + { + d_arg = va_arg(arg, double); + } + + // if numer have 5 or more digits in the whole part + // using scientific notation will be shorter as they share + // precision value + if (d_arg >= 10000.0) + { + _kernel_put_scientific_notation(stream, &put_index, d_arg, flags, width_field, precision_field); + } + else + { + _kernel_put_float(stream, &put_index, d_arg, flags, width_field, precision_field); + } + } + break; + + case 'p': + { + void *ptr = va_arg(arg, void *); + flags |= FLAGS_UPPERCASE; + // Ignore those flags + flags &= ~(FLAGS_ZEROPAD | FLAGS_HASH | FLAGS_PLUS | FLAGS_SPACE); + + precision_field = sizeof(void *) * 2; + _kernel_put_unsigned_integer(stream, &put_index, (unsigned int)ptr, flags, 16, width_field, precision_field); + break; + } + + case 'n': + { + int *ptr = va_arg(arg, int *); + + (*ptr) = put_index; + break; + } + + case '%': + kernel_fputc('%', stream); + put_index++; + + break; + + default: + kernel_fputc(*traverse, stream); + put_index++; + + break; + } + } + } + + return put_index - 1; +} \ No newline at end of file From 6e4f4557fcc5e2a13900beedf07878ea1830645e Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 13 Aug 2020 02:47:15 +0200 Subject: [PATCH 093/165] Corrected DEBUG informations --- os/kernel/src/v8086/v8086.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index d8afa974..7bf56940 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -323,7 +323,7 @@ int16_t parse_and_execute_instruction(v8086* machine) serial_send_string(COM1_PORT, "STACK:\n"); kernel_sprintf(str, "BP:%04X eBP:%08X\n", machine->regs.h.bp, machine->regs.d.ebp); serial_send_string(COM1_PORT, str); - kernel_sprintf(str, "SP:%04X eSP:%08X\n", machine->regs.h.sp, machine->regs.d.esp); + kernel_sprintf(str, "SP:%04X eSP:%08X\n", machine->regs.w.sp, machine->regs.d.esp); serial_send_string(COM1_PORT, str); kernel_sprintf(str, "SS:%04X\n", machine->sregs.ss); serial_send_string(COM1_PORT, str); @@ -331,15 +331,15 @@ int16_t parse_and_execute_instruction(v8086* machine) serial_send_string(COM1_PORT, "WEIRD STACK ADDRESS!\n"); else{ serial_send_string(COM1_PORT, "---\n"); - for(uint32_t i=0x7bff; i <=machine->regs.d.esp; i-=2) + for(uint32_t i=0x7bff; i >= machine->regs.d.esp; i-=2) { - kernel_sprintf(str, "%02X %02X", read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.d.esp)), read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.d.esp - 1))); + kernel_sprintf(str, "%02X %02X\n", read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i)), read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i-1))); serial_send_string(COM1_PORT, str); } serial_send_string(COM1_PORT, "---\n"); } serial_send_string(COM1_PORT, "INSTRUCTION ADDRESS:\n"); - kernel_sprintf(str, "CS:%04X\n IP:%04X", machine->IP.w.ip); + kernel_sprintf(str, "CS:%04X IP:%04X\n", machine->sregs.cs, machine->IP.w.ip); serial_send_string(COM1_PORT, str); #endif From 56c94cf46af79aae8b001bc05e0064294a7cc13d Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 14 Aug 2020 01:51:47 +0200 Subject: [PATCH 094/165] Corrected pop dword --- .../v8086/operations/arithmetic_operations.c | 2 ++ os/kernel/src/v8086/stack.h | 2 +- os/kernel/src/v8086/v8086.c | 28 ++++++++++++++----- os/kernel/src/v8086/v8086.h | 10 +++---- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 080bf935..76a8469e 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -488,6 +488,8 @@ int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_clear(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT); + bit_clear(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT); return V8086_OK; } diff --git a/os/kernel/src/v8086/stack.h b/os/kernel/src/v8086/stack.h index ddfa3fe8..18856d5c 100644 --- a/os/kernel/src/v8086/stack.h +++ b/os/kernel/src/v8086/stack.h @@ -35,7 +35,7 @@ static inline uint16_t pop_word(v8086* machine) static inline uint32_t pop_dword(v8086* machine) { - uint16_t v = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); + uint32_t v = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp)); machine->regs.w.sp += 4; return v; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 7bf56940..d58d1548 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -309,9 +309,9 @@ int16_t parse_and_execute_instruction(v8086* machine) serial_send_string(COM1_PORT, str); kernel_sprintf(str, "DL:%02X DH:%02X DX:%04X eDX:%08X\n", machine->regs.h.dl, machine->regs.h.dh, machine->regs.x.dx, machine->regs.d.edx); serial_send_string(COM1_PORT, str); - kernel_sprintf(str, "DI:%04X eDI:%04X\n", machine->regs.h.di, machine->regs.d.edi); + kernel_sprintf(str, "DI:%04X eDI:%08X\n", machine->regs.h.di, machine->regs.d.edi); serial_send_string(COM1_PORT, str); - kernel_sprintf(str, "SI:%04X eSI:%04X\n", machine->regs.h.si, machine->regs.d.esi); + kernel_sprintf(str, "SI:%04X eSI:%08X\n", machine->regs.h.si, machine->regs.d.esi); serial_send_string(COM1_PORT, str); kernel_sprintf(str, "FLAGS:%04X\n", machine->regs.w.flags); serial_send_string(COM1_PORT, str); @@ -327,17 +327,31 @@ int16_t parse_and_execute_instruction(v8086* machine) serial_send_string(COM1_PORT, str); kernel_sprintf(str, "SS:%04X\n", machine->sregs.ss); serial_send_string(COM1_PORT, str); - if((machine->regs.d.esp > 0x7bff) || (machine->sregs.ss != 0x0)) - serial_send_string(COM1_PORT, "WEIRD STACK ADDRESS!\n"); - else{ + if((machine->regs.d.esp < 0x7bff) && (machine->sregs.ss == 0x0)){ serial_send_string(COM1_PORT, "---\n"); - for(uint32_t i=0x7bff; i >= machine->regs.d.esp; i-=2) + for(uint32_t i=0x7bff - 1; i >= machine->regs.d.esp; i-=1) { - kernel_sprintf(str, "%02X %02X\n", read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i)), read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i-1))); + kernel_sprintf(str, "%02X ",read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i))); serial_send_string(COM1_PORT, str); + if(!((0x7bff - i) % 2)) serial_send_string(COM1_PORT, "\n"); + else if(i - 1 < machine->regs.d.esp) serial_send_string(COM1_PORT, "\n"); } serial_send_string(COM1_PORT, "---\n"); } + else if((machine->regs.d.esp < 0x200) && (machine->sregs.ss == 0xeb62)){ + serial_send_string(COM1_PORT, "---\n"); + for(uint32_t i=0x200 - 1; i >= machine->regs.d.esp; i-=1) + { + kernel_sprintf(str, "%02X ",read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i))); + serial_send_string(COM1_PORT, str); + if(!((0x200 - i) % 2)) serial_send_string(COM1_PORT, "\n"); + else if(i - 1 < machine->regs.d.esp) serial_send_string(COM1_PORT, "\n"); + } + serial_send_string(COM1_PORT, "---\n"); + } + else{ + serial_send_string(COM1_PORT, "WEIRD STACK ADDRESS!\n"); + } serial_send_string(COM1_PORT, "INSTRUCTION ADDRESS:\n"); kernel_sprintf(str, "CS:%04X IP:%04X\n", machine->sregs.cs, machine->IP.w.ip); serial_send_string(COM1_PORT, str); diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 5273989c..264cbcf1 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -70,7 +70,7 @@ struct DWORDREGS { uint32_t eax; uint16_t eflags; uint32_t esp; -}; +} __attribute__((packed)); struct WORDREGS { uint16_t di, _upper_di; @@ -83,7 +83,7 @@ struct WORDREGS { uint16_t ax, _upper_ax; uint16_t flags; uint16_t sp, _upper_sp; -}; +} __attribute__((packed)); struct BYTEREGS { uint16_t di, _upper_di; @@ -104,7 +104,7 @@ struct BYTEREGS { uint16_t _upper_ax; uint16_t flags; uint16_t sp, _upper_sp; -}; +} __attribute__((packed)); union REGS { /* Compatible with DPMI structure, except cflag */ struct DWORDREGS d; @@ -124,12 +124,12 @@ struct SREGS { struct DWORDIP{ uint32_t eip; -}; +} __attribute__((packed)); struct WORDIP { uint16_t ip; uint16_t _upper_ip; -}; +} __attribute__((packed)); union IP { struct DWORDIP d; From f09084e7c0dc87d1553e2b6d8570deca6e1b3422 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 15 Aug 2020 19:55:29 +0200 Subject: [PATCH 095/165] Corrected CMP, MOV, and ADD --- .../v8086/operations/arithmetic_operations.c | 115 +++++++++--------- .../src/v8086/operations/mov_operations.c | 6 +- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 76a8469e..37b82c57 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -29,7 +29,7 @@ int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, (((dest_before & 0xfu) + (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG if (width == 8) *((uint8_t *) dest) = result & 0xFFu; @@ -61,7 +61,7 @@ int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t wi for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG if (width == 8) *((uint8_t *) dest) = result & 0xFFu; @@ -72,30 +72,39 @@ int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t wi } int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint32_t result = 0; + uint16_t temp_flags = 0; if (width == 8) - result = *((uint8_t *) dest) | *((uint8_t *) source); + __asm__ __volatile__("orb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); else if (width == 16) - result = *((uint16_t *) dest) | *((uint16_t *) source); + __asm__ __volatile__("orw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); else if (width == 32) - result = *((uint32_t *) dest) | *((uint32_t *) source); + __asm__ __volatile__("orl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); else return V8086_BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if (width == 8) *((uint8_t *) dest) = result & 0xFFu; - else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; - else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return V8086_OK; } int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint32_t result = 0; + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("andb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); + else if (width == 16) + __asm__ __volatile__("andw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); + else if (width == 32) + __asm__ __volatile__("andl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + return V8086_OK; + + /*uint32_t result = 0; if (width == 8) result = *((uint8_t *) dest) & *((uint8_t *) source); else if (width == 16) @@ -109,12 +118,12 @@ int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uin for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return V8086_OK; + return V8086_OK;*/ } int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { @@ -132,7 +141,7 @@ int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uin for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; @@ -141,30 +150,20 @@ int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uin } int16_t perform_cmp(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if (width == 8) { - dest_before = *((uint8_t *) dest); - source_before = *((uint8_t *) source); - } else if (width == 16) { - dest_before = *((uint16_t *) dest); - source_before = *((uint16_t *) source); - } else if (width == 32) { - dest_before = *((uint32_t *) dest); - source_before = *((uint32_t *) source); - } else return V8086_BAD_WIDTH; - result = dest_before - source_before; - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, - (((dest_before & 0xfu) - (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, - ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("cmpb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); + else if (width == 16) + __asm__ __volatile__("cmpw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); + else if (width == 32) + __asm__ __volatile__("cmpl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return V8086_OK; } @@ -473,23 +472,19 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 } int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { - uint32_t result; - + uint16_t temp_flags = 0; if (width == 8) - result = *((uint8_t *) source) & *((uint8_t *) dest); + __asm__ __volatile__("testb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); else if (width == 16) - result = *((uint16_t *) source) & *((uint16_t *) dest); + __asm__ __volatile__("testw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); else if (width == 32) - result = *((uint32_t *) source) & *((uint32_t *) dest); + __asm__ __volatile__("testl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); else return V8086_BAD_WIDTH; - - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG - bit_clear(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT); - bit_clear(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT); + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return V8086_OK; } @@ -510,7 +505,7 @@ int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, (((dest_before & 0xfu) + 1u) >> 4u) ? 1 : 0); //AUX CARRY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG @@ -537,7 +532,7 @@ int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, (((dest_before & 0xfu) - 1u) >> 4u) ? 1 : 0); //AUX CARRY FLAG bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, result >> (width - 1u)); //SIGN FLAG + bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index 0476676a..dccbe0bd 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -165,9 +165,9 @@ uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) machine->internal_state.IPOffset += 1; if(opcode == 0xc6) { + uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); uint8_t immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - uint8_t* mem = get_memory_from_mode(machine, mod_rm, 8); if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } @@ -175,17 +175,17 @@ uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) { if(machine->internal_state.operand_32_bit) { + uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); uint32_t immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; - uint32_t* mem = get_memory_from_mode(machine, mod_rm, 32); if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } else { + uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); uint16_t immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; - uint16_t* mem = get_memory_from_mode(machine, mod_rm, 16); if(mem == NULL) return V8086_UNABLE_GET_MEMORY; *mem = immediate; } From f12c615f8f60591bd84f7e80c997a88ed98f5ae4 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 15 Aug 2020 20:51:38 +0200 Subject: [PATCH 096/165] Refatored SBB i SUB into inline asm --- .../v8086/operations/arithmetic_operations.c | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 37b82c57..1f42c5aa 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -40,34 +40,20 @@ int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, } int16_t perform_subtracting(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if (width == 8) { - dest_before = *((uint8_t *) dest); - source_before = *((uint8_t *) source); - } else if (width == 16) { - dest_before = *((uint16_t *) dest); - source_before = *((uint16_t *) source); - } else if (width == 32) { - dest_before = *((uint32_t *) dest); - source_before = *((uint32_t *) source); - } else return V8086_BAD_WIDTH; - result = dest_before - (source_before + carry); - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, - (((dest_before & 0xfu) - (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, - ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if (width == 8) *((uint8_t *) dest) = result & 0xFFu; - else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; - else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:sbbb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source)), "d" (carry)); + else if (width == 16) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:sbbw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source)), "d" (carry)); + else if (width == 32) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:sbbl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source)), "d" (carry)); else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } From 091ceb5b3c0271c9f429c8bd85f76c084f492476 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 15 Aug 2020 20:52:52 +0200 Subject: [PATCH 097/165] refactored ADC and ADD into inline asm --- .../v8086/operations/arithmetic_operations.c | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 1f42c5aa..751c9c01 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -8,34 +8,20 @@ #include "internal_funcs.h" int16_t perform_adding(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint64_t result = 0; - uint32_t dest_before; //for overflow flag checking - uint32_t source_before; - if (width == 8) { - dest_before = *((uint8_t *) dest); - source_before = *((uint8_t *) source); - } else if (width == 16) { - dest_before = *((uint16_t *) dest); - source_before = *((uint16_t *) source); - } else if (width == 32) { - dest_before = *((uint32_t *) dest); - source_before = *((uint32_t *) source); - } else return V8086_BAD_WIDTH; - result = dest_before + source_before + carry; - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, (result >> width) ? 1 : 0); // CARRY FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << AUX_CARRY_FLAG_BIT, - (((dest_before & 0xfu) + (source_before & 0xfu)) >> 4u) ? 1 : 0); //AUX CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, - ((result >> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG - if (width == 8) *((uint8_t *) dest) = result & 0xFFu; - else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; - else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:adcb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source)), "d" (carry)); + else if (width == 16) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:adcw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source)), "d" (carry)); + else if (width == 32) + __asm__ __volatile__("clc; test %%edx, %%edx; jz calculate%=; stc; calculate%=:adcl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source)), "d" (carry)); else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } From 9dc8f7ad2ec8fabe8d5f0aa58915aadb95847454 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 15 Aug 2020 20:53:15 +0200 Subject: [PATCH 098/165] cleaned unused code --- .../v8086/operations/arithmetic_operations.c | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 751c9c01..c325ed65 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -75,27 +75,6 @@ int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uin bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); return V8086_OK; - - /*uint32_t result = 0; - if (width == 8) - result = *((uint8_t *) dest) & *((uint8_t *) source); - else if (width == 16) - result = *((uint16_t *) dest) & *((uint16_t *) source); - else if (width == 32) - result = *((uint32_t *) dest) & *((uint32_t *) source); - else return V8086_BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if (width == 8) *((uint8_t *) dest) = result & 0xFFu; - else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; - else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return V8086_OK;*/ } int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { From 45a4faddb6364382d526431191e8b2920723b85d Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sun, 16 Aug 2020 00:08:29 +0200 Subject: [PATCH 099/165] Added SP into stack values representation --- os/kernel/src/v8086/v8086.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index d58d1548..f884d218 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -333,7 +333,10 @@ int16_t parse_and_execute_instruction(v8086* machine) { kernel_sprintf(str, "%02X ",read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i))); serial_send_string(COM1_PORT, str); - if(!((0x7bff - i) % 2)) serial_send_string(COM1_PORT, "\n"); + if(!((0x7bff - i) % 2)){ + kernel_sprintf(str, ":%02X\n", i); + serial_send_string(COM1_PORT, str); + } else if(i - 1 < machine->regs.d.esp) serial_send_string(COM1_PORT, "\n"); } serial_send_string(COM1_PORT, "---\n"); @@ -344,7 +347,10 @@ int16_t parse_and_execute_instruction(v8086* machine) { kernel_sprintf(str, "%02X ",read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, i))); serial_send_string(COM1_PORT, str); - if(!((0x200 - i) % 2)) serial_send_string(COM1_PORT, "\n"); + if(!((0x200 - i) % 2)){ + kernel_sprintf(str, ":%02X\n", i); + serial_send_string(COM1_PORT, str); + } else if(i - 1 < machine->regs.d.esp) serial_send_string(COM1_PORT, "\n"); } serial_send_string(COM1_PORT, "---\n"); From 2ff6777949a118293f29000f02a28d35b3c62237 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 18 Aug 2020 02:19:33 +0200 Subject: [PATCH 100/165] Corrected mistake (swaped opcodes functions) --- os/kernel/src/v8086/v8086.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f884d218..e6f8a3f8 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -90,8 +90,8 @@ void v8086_set_8086_instruction_set(v8086* machine) //NOT DEFINED IN 8086 processor ASSIGN_NULL(0xc0u); ASSIGN_NULL(0xc1u); - ASSIGN_OPCODE(0xc2u, retn); - ASSIGN_OPCODE(0xc3u, retn_imm); + ASSIGN_OPCODE(0xc2u, retn_imm); + ASSIGN_OPCODE(0xc3u, retn); ASSIGN_OPCODE(0xc4u, les); ASSIGN_OPCODE(0xc5u, lds); GROUP_OF_OPCODES(0xc6u, 0xc7u, mov_rm_imm); From 42ccf9d0deaaf35ea9a737496c756b100bc220b3 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 26 Aug 2020 00:40:50 +0200 Subject: [PATCH 101/165] int 10h works! --- library/src/string/strstr.c | 31 ++- os/kernel/src/drivers/vga/vga_gmode.c | 67 +++--- os/kernel/src/drivers/vga/vga_gmode.h | 4 +- os/kernel/src/kernel.c | 43 ++-- .../v8086/operations/arithmetic_operations.c | 28 ++- .../src/v8086/operations/mov_operations.c | 20 +- os/kernel/src/v8086/operations/opcodes.c | 2 +- os/kernel/src/v8086/tests/tests.c | 102 +++++++++ os/kernel/src/v8086/tests/tests.h | 12 + os/kernel/src/v8086/v8086.c | 215 ++++++++++++++---- os/kernel/src/v8086/v8086.h | 23 +- resources/lena.bmp | Bin 0 -> 65146 bytes 12 files changed, 428 insertions(+), 119 deletions(-) create mode 100644 os/kernel/src/v8086/tests/tests.c create mode 100644 os/kernel/src/v8086/tests/tests.h create mode 100644 resources/lena.bmp diff --git a/library/src/string/strstr.c b/library/src/string/strstr.c index b565f2cc..6ce9795e 100644 --- a/library/src/string/strstr.c +++ b/library/src/string/strstr.c @@ -1,6 +1,6 @@ #include "../string.h" -char *strstr(const char *str1, const char *str2) +/*char *strstr(const char *str1, const char *str2) { const char *ret = str2; int i; @@ -16,4 +16,31 @@ char *strstr(const char *str1, const char *str2) str1++; } return 0; -} \ No newline at end of file +} */ + +int compare(const char *X, const char *Y) +{ + while (*X && *Y) + { + if (*X != *Y) + return 0; + + X++; + Y++; + } + + return (*Y == '\0'); +} + +// Function to implement strstr() function +char* strstr(const char* str1, const char* str2) +{ + while (*str1 != '\0') + { + if ((*str1 == *str2) && compare(str1, str2)) + return str1; + str1++; + } + + return NULL; +} \ No newline at end of file diff --git a/os/kernel/src/drivers/vga/vga_gmode.c b/os/kernel/src/drivers/vga/vga_gmode.c index 77eed270..4cd15cf9 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.c +++ b/os/kernel/src/drivers/vga/vga_gmode.c @@ -3,6 +3,7 @@ #include #include "vga.h" #include "filesystems/filesystem.h" +#include "modes/mode_13h/mode_13h.h" #define peekb(S, O) *(unsigned char *)(16uL * (S) + (O)) #define pokeb(S, O, V) *(unsigned char *)(16uL * (S) + (O)) = (V) @@ -19,38 +20,38 @@ static char mode = 3; -//typedef struct _Os2BmpFileHeader -//{ -// uint16_t FileType; /* File type identifier */ -// uint32_t FileSize; /* Size of the file in bytes */ -// uint16_t XHotSpot; /* X coordinate of hotspot */ -// uint16_t YHotSpot; /* Y coordinate of hotspot */ -// uint32_t BitmapOffset; /* Starting position of image data in bytes */ -//} __attribute__((packed)) OS2BMPFILEHEADER; - -//typedef struct _Os21xBitmapHeader -//{ -// uint32_t Size; /* Size of this header in bytes */ -// uint32_t Width; /* Image width in pixels */ -// uint32_t Height; /* Image height in pixels */ -// uint16_t NumPlanes; /* Number of color planes */ -// uint16_t BitsPerPixel; /* Number of bits per pixel */ -//} __attribute__((packed)) OS21XBITMAPHEADER; - -//typedef struct _Os21xPaletteElement -//{ -// uint8_t Blue; /* Blue component */ -// uint8_t Green; /* Green component */ -// uint8_t Red; /* Red component */ -//} __attribute__((packed)) OS21XPALETTEELEMENT; - -/*void drawMicrOSLogoIn13H() +typedef struct _Os2BmpFileHeader +{ + uint16_t FileType; /* File type identifier */ + uint32_t FileSize; /* Size of the file in bytes */ + uint16_t XHotSpot; /* X coordinate of hotspot */ + uint16_t YHotSpot; /* Y coordinate of hotspot */ + uint32_t BitmapOffset; /* Starting position of image data in bytes */ +} __attribute__((packed)) OS2BMPFILEHEADER; + +typedef struct _Os21xBitmapHeader +{ + uint32_t Size; /* Size of this header in bytes */ + uint32_t Width; /* Image width in pixels */ + uint32_t Height; /* Image height in pixels */ + uint16_t NumPlanes; /* Number of color planes */ + uint16_t BitsPerPixel; /* Number of bits per pixel */ +} __attribute__((packed)) OS21XBITMAPHEADER; + +typedef struct _Os21xPaletteElement +{ + uint8_t Blue; /* Blue component */ + uint8_t Green; /* Green component */ + uint8_t Red; /* Red component */ +} __attribute__((packed)) OS21XPALETTEELEMENT; + +void drawMicrOSLogoIn13H() { filesystem_file_info info; - filesystem_get_file_info("/ENV/LOGO.BMP", &info); + filesystem_get_file_info("A:/LOGO.BMP", &info); uint8_t *buffer = heap_kernel_alloc(info.size, 0); - filesystem_read_file("/ENV/LOGO.BMP", buffer, 0, info.size); + filesystem_read_file("A:/LOGO.BMP", buffer, 0, info.size); OS2BMPFILEHEADER fh; memcpy(&fh, buffer, sizeof(OS2BMPFILEHEADER)); @@ -60,7 +61,7 @@ static char mode = 3; for(int x = 0; x < bh.Width; x++) for(int y = 0; y < bh.Height; y++) - pixel_13H(buffer[fh.BitmapOffset + (bh.Height * bh.Width - bh.Width - y*bh.Width) + x],x,y); + mode13h_draw_pixel(buffer[fh.BitmapOffset + (bh.Height * bh.Width - bh.Width - y*bh.Width) + x],x,y); heap_kernel_dealloc(buffer); } @@ -69,10 +70,10 @@ static char mode = 3; void drawLenaIn13H() { filesystem_file_info info; - filesystem_get_file_info("/ENV/LENA.BMP", &info); + filesystem_get_file_info("A:/LENA.BMP", &info); uint8_t *buffer = heap_kernel_alloc(info.size, 0); - filesystem_read_file("/ENV/LENA.BMP", buffer, 0, info.size); + filesystem_read_file("A:/LENA.BMP", buffer, 0, info.size); OS2BMPFILEHEADER fh; memcpy(&fh, buffer, sizeof(OS2BMPFILEHEADER)); @@ -82,10 +83,10 @@ void drawLenaIn13H() for(int x = 0; x < bh.Width; x++) for(int y = 0; y < bh.Height; y++) - pixel_13H(buffer[fh.BitmapOffset + (bh.Height * bh.Width - bh.Width - y*bh.Width) + x],x,y); + mode13h_draw_pixel(buffer[fh.BitmapOffset + (bh.Height * bh.Width - bh.Width - y*bh.Width) + x],x,y); heap_kernel_dealloc(buffer); -}*/ +} char vga_gmode_get_mode() { diff --git a/os/kernel/src/drivers/vga/vga_gmode.h b/os/kernel/src/drivers/vga/vga_gmode.h index f78fc3d0..3ca832ff 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.h +++ b/os/kernel/src/drivers/vga/vga_gmode.h @@ -3,8 +3,8 @@ #include -/*void drawMicrOSLogoIn13H(); -void drawLenaIn13H();*/ +void drawMicrOSLogoIn13H(); +void drawLenaIn13H(); char vga_gmode_get_mode(); diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 538525a7..5061433b 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -24,6 +24,8 @@ #include "cpu/tss/tss.h" #include "drivers/dal/videocard/videocard.h" #include "drivers/vga/genericvga.h" +#include "drivers/vga/modes/mode_13h/mode_13h.h" +#include "drivers/vga/vga_gmode.h" #include "cpu/dma/dma.h" #include "drivers/harddisk/harddisk.h" #include "drivers/harddisk/ata/harddisk_ata.h" @@ -36,6 +38,10 @@ #include "cpu/cpuid/cpuid.h" #include "v8086/v8086.h" +#ifdef TEST_V8086 +#include "v8086/tests/tests.h" +#endif + typedef struct _linesStruct { uint16_t ax; @@ -406,8 +412,8 @@ int kmain() //process_manager_run(); - v8086* v8086 = v8086_create_machine(); - v8086_set_386_instruction_set(v8086); + union test_v8086* v8086 = v8086_create_machine(); + v8086_set_386_instruction_set(&(v8086->machine)); //filesystem_create_file("A:/DUMP.BIN"); //bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); @@ -418,14 +424,14 @@ int kmain() // filesystem_delete_file("A:/SEG0x40.BIN"); filesystem_create_file("A:/DUMP.BIN"); - bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); + bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->machine.Memory + 0xC0000, 64*1024); //filesystem_create_file("A:/SEG0x40.BIN"); //dupa = filesystem_save_to_file("A:/SEG0x40.BIN", (char*) v8086->Memory + 0x400, 64*1024); - serial_init(COM1_PORT, 9600, 8, 1, PARITY_NONE); + serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); keyboard_scan_ascii_pair kb; - vga_printstring("Press key to continue... (Sending Debug Informations via serial)"); + vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); while(!keyboard_get_key_from_buffer(&kb)); /*for(long long i = 0; i < 1024*1024; i++) { @@ -440,17 +446,26 @@ int kmain() //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); - v8086->regs.h.ah = 0x00; - v8086->regs.h.al = 0x13; + #ifdef TEST_V8086 + test_mod_16(); + #endif + + v8086->machine.regs.h.ah = 0x00; + v8086->machine.regs.h.al = 0x13; int16_t status = v8086_call_int(v8086, 0x10); - char str[100] = ""; - vga_printstring("IP: "); - uint16_t IP = *(uint16_t*)(v8086->Memory + 0x10 * 4); - uint16_t CS = *(uint16_t*)(v8086->Memory + 0x10 * 4 + 2); + //mode13h_set_mode(); + mode13h_clear_screen(); + drawLenaIn13H(); + + /*char str[100] = ""; itoa(status, str, 16); vga_printstring(str); vga_newline(); + vga_printstring("IP: "); + uint16_t IP = *(uint16_t*)(v8086->machine.Memory + 0x10 * 4); + uint16_t CS = *(uint16_t*)(v8086->machine.Memory + 0x10 * 4 + 2); + vga_newline(); itoa(IP, str, 16); vga_printstring(str); vga_newline(); @@ -460,11 +475,13 @@ int kmain() vga_newline(); for(uint32_t i = CS * 16 + IP; i < (CS * 16 + IP + 16); i++) { - uint8_t mem = v8086->Memory[i]; + uint8_t mem = v8086->machine.Memory[i]; itoa(mem, str, 16); vga_printstring(str); vga_printstring(" "); - } + }*/ + + while (1); return 0; } diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index c325ed65..fde7f670 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -57,6 +57,7 @@ int16_t perform_or(v8086 *machine, void *dest, void *source, uint8_t width, uint bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } @@ -74,29 +75,25 @@ int16_t perform_and(v8086 *machine, void *dest, void *source, uint8_t width, uin bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } int16_t perform_xor(v8086 *machine, void *dest, void *source, uint8_t width, uint32_t carry) { - uint32_t result = 0; + uint16_t temp_flags = 0; if (width == 8) - result = *((uint8_t *) dest) ^ *((uint8_t *) source); + __asm__ __volatile__("xorb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); else if (width == 16) - result = *((uint16_t *) dest) ^ *((uint16_t *) source); + __asm__ __volatile__("xorw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); else if (width == 32) - result = *((uint32_t *) dest) ^ *((uint32_t *) source); + __asm__ __volatile__("xorl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); else return V8086_BAD_WIDTH; - bit_write(machine->regs.d.eflags, 1u << CARRY_FLAG_BIT, 0); // CARRY FLAG - bit_write(machine->regs.d.eflags, 1u << OVERFLOW_FLAG_BIT, 0); // OVERFLOW FLAG - uint8_t parrity = result & 1u; - for (uint8_t i = 1; i < 8; i++) parrity ^= (result >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, (parrity) ? 1 : 0); //PARRITY FLAG - bit_write(machine->regs.d.eflags, 1u << ZERO_FLAG_BIT, result == 0); //ZERO FLAG - bit_write(machine->regs.d.eflags, 1u << SIGN_FLAG_BIT, (result >> (width - 1u)) & 1u); //SIGN FLAG - //AUX MARKED AS UNDEFINED IN INTEL DOCUMENTATION - if (width == 8) *((uint8_t *) dest) = result & 0xFFu; - else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; - else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } @@ -436,6 +433,7 @@ int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); return V8086_OK; } diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index dccbe0bd..8004d0cb 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -5,7 +5,7 @@ #include "mov_operations.h" #include "internal_funcs.h" -int16_t perform_mov(void* source, void* dest, uint8_t width) { +int16_t perform_mov(v8086* machine, void* source, void* dest, uint8_t width) { switch (width) { case 8: *((uint8_t *) dest) = *((uint8_t *) source); @@ -19,6 +19,14 @@ int16_t perform_mov(void* source, void* dest, uint8_t width) { default: return V8086_BAD_WIDTH; } + + bit_clear(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << CARRY_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << SIGN_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << ZERO_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << PARITY_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT); + return V8086_OK; } @@ -38,10 +46,10 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode) { case 0x88: case 0x89: - return perform_mov(source, dest, width); + return perform_mov(machine, source, dest, width); case 0x8a: case 0x8b: - return perform_mov(dest, source, width); + return perform_mov(machine, dest, source, width); default: return V8086_UNKNOWN_ERROR; } @@ -139,9 +147,9 @@ int16_t perform_mov_segment(v8086* machine, uint8_t opcode) if(dest == NULL) return V8086_UNABLE_GET_MEMORY; if(opcode == 0x8c) - return perform_mov(source, dest, 16); + return perform_mov(machine, source, dest, 16); else if(opcode == 0x8e) - return perform_mov(dest, source, 16); + return perform_mov(machine, dest, source, 16); else return V8086_UNKNOWN_ERROR; } @@ -156,7 +164,7 @@ uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode) if(reg == NULL) return V8086_UNDEFINED_REGISTER; void* imm = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); machine->internal_state.IPOffset += width / 8; - return perform_mov(imm, reg, width); + return perform_mov(machine, imm, reg, width); } uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index b8145fbf..719fa4d1 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -448,7 +448,7 @@ OPCODE_PROTO(outb_dx) OPCODE_PROTO(outw_dx) { - return perform_in_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); + return perform_out_dx(machine, machine->internal_state.operand_32_bit ? 32 : 16); } OPCODE_PROTO(set_flag) diff --git a/os/kernel/src/v8086/tests/tests.c b/os/kernel/src/v8086/tests/tests.c new file mode 100644 index 00000000..e1fd734e --- /dev/null +++ b/os/kernel/src/v8086/tests/tests.c @@ -0,0 +1,102 @@ +#include "tests.h" + +#ifdef TEST_V8086 +#include "stdint.h" +#include "../mod_rm_parsing.h" +#include "../drivers/serial/serial.h" +#include "string.h" +#include "../../debug_helpers/library/kernel_stdio.h" + +char* effective_addresses[3][8] = { + {"[BX+SI]", "[BX+DI]", "[BP+SI]", "[BP+DI]", "[SI]", "[DI]", "disp16", "[BX]"}, + {"[BX+SI]+disp8", "[BX+DI]+disp8", "[BP+SI]+disp8", "[BP+DI]+disp8", "[SI]+disp8", "[DI]+disp8", "[BP]+disp8", "[BX]+disp8"}, + {"[BX+SI]+disp16", "[BX+DI]+disp16", "[BP+SI]+disp16", "[BP+DI]+disp16", "[SI]+disp16", "[DI]+disp16", "[BP]+disp16", "[BX]+disp16"} +}; + +#define test_mod_16_func(width) void test_mod_16_width_##width(v8086* machine){\ + uint##width##_t* memory_##width;\ + uint##width##_t* expected_memory_##width;\ + machine->IP.w.ip = 0; \ + machine->sregs.cs = 0; \ + machine->regs.x.bx = 0; \ + machine->regs.x.bp = 0; \ + machine->regs.x.si = 0; \ + machine->regs.x.di = 0; \ + char str[100] = ""; \ + for(uint16_t mod_rm=0; mod_rm < 192; mod_rm++) \ + { \ + char* effective_address = effective_addresses[mod_rm >> 6][mod_rm & 7]; \ + uint16_t cumulative_offset = 0; \ + uint8_t bp_on_road = 0; \ + if(strstr(effective_address, "BX") != NULL) \ + { \ + uint16_t offset = 98; \ + machine->regs.x.bx = offset; \ + cumulative_offset += offset; \ + } \ + if(strstr(effective_address, "BP") != NULL) \ + { \ + uint16_t offset = 56; \ + machine->regs.x.bp = offset; \ + cumulative_offset += offset; \ + bp_on_road = 1; \ + } \ + if(strstr(effective_address, "SI") != NULL) \ + { \ + uint16_t offset = 15; \ + machine->regs.x.si = offset; \ + cumulative_offset += offset; \ + } \ + if(strstr(effective_address, "DI") != NULL) \ + { \ + uint16_t offset = 32; \ + machine->regs.x.di = offset; \ + cumulative_offset += offset; \ + } \ + if(strstr(effective_address, "disp8") != NULL) \ + { \ + int16_t offset = 69; \ + machine->Memory[0] = offset; \ + cumulative_offset += offset; \ + } \ + if(strstr(effective_address, "disp16") != NULL) \ + { \ + uint16_t offset = 1520; \ + machine->Memory[0] = offset & 0xff; \ + machine->Memory[1] = offset >> 8; \ + cumulative_offset += offset; \ + } \ + memory_##width = (uint##width##_t*)get_memory_from_mode(machine, mod_rm, width); \ + expected_memory_##width = (uint##width##_t*)(machine->Memory + cumulative_offset + (bp_on_road ? machine->sregs.ss:machine->sregs.ds) * 0x10);\ + machine->internal_state.IPOffset = 0; \ + machine->regs.x.bx = 0; \ + machine->regs.x.bp = 0; \ + machine->regs.x.si = 0; \ + machine->regs.x.di = 0; \ + if(memory_##width != expected_memory_##width){ \ + kernel_sprintf(str, "ERROR for mode %x and width %d\n", mod_rm, width); \ + serial_send_string(COM1_PORT, str); \ + } \ + else{ \ + kernel_sprintf(str, "OK for mode %x and width %d\n", mod_rm, width); \ + serial_send_string(COM1_PORT, str); \ + } \ + } \ +} + +test_mod_16_func(8) +test_mod_16_func(16) +test_mod_16_func(32) + +void test_mod_16() +{ + v8086* machine = v8086_create_machine(); + + test_mod_16_width_8(machine); + test_mod_16_width_16(machine); + test_mod_16_width_32(machine); + + v8086_destroy_machine(machine); +} + +#endif \ No newline at end of file diff --git a/os/kernel/src/v8086/tests/tests.h b/os/kernel/src/v8086/tests/tests.h new file mode 100644 index 00000000..e8308b22 --- /dev/null +++ b/os/kernel/src/v8086/tests/tests.h @@ -0,0 +1,12 @@ +#ifndef TESTS_H +#define TESTS_H + +#include "../v8086.h" + +#ifdef TEST_V8086 + +void test_mod_16(); + +#endif + +#endif \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index e6f8a3f8..103e5132 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -14,9 +14,52 @@ #ifdef DEBUG_V8086 #include "../drivers/serial/serial.h" + #include "../drivers/vga/vga.h" + //#define DEBUG_V8086_TEXT + //#define DEBUG_V8086_BIN + #define DEBUG_V8086_INTERACTIVE #endif -int16_t parse_and_execute_instruction(v8086* machine); +int16_t parse_and_execute_instruction(union test_v8086* machine); + +#ifdef DEBUG_V8086 +void send_reg_32(uint32_t reg) +{ + for(int i = 0; i < 4; i++) + serial_send(COM1_PORT, ((reg) >> (i*8)) & 0xff); +} + +void send_reg_16(uint16_t reg) +{ + for(int i = 0; i < 2; i++) + serial_send(COM1_PORT, ((reg) >> (i*8)) & 0xff); +} + +void send_regs(union test_v8086* machine) +{ + send_reg_32(machine->machine.regs.d.edi); + send_reg_32(machine->machine.regs.d.esi); + send_reg_32(machine->machine.regs.d.ebp); + send_reg_32(machine->machine.regs.d.cflag); + send_reg_32(machine->machine.regs.d.ebx); + send_reg_32(machine->machine.regs.d.edx); + send_reg_32(machine->machine.regs.d.ecx); + send_reg_32(machine->machine.regs.d.eax); + send_reg_16(machine->machine.regs.d.eflags); + send_reg_32(machine->machine.regs.d.esp); +} + +void send_sregs(union test_v8086* machine) +{ + send_reg_16(machine->machine.sregs.es); + send_reg_16(machine->machine.sregs.ds); + send_reg_16(machine->machine.sregs.fs); + send_reg_16(machine->machine.sregs.gs); + send_reg_16(machine->machine.sregs.cs); + send_reg_16(machine->machine.sregs.ss); +} + +#endif void v8086_set_8086_instruction_set(v8086* machine) { @@ -242,25 +285,30 @@ void v8086_set_386_instruction_set(v8086* machine) machine->is_compatibility = V8086_IS386; } -v8086* v8086_create_machine() +union test_v8086* v8086_create_machine() { - v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); + union test_v8086* machine = (union test_v8086*) heap_kernel_alloc(sizeof(union test_v8086), 0); if(machine == NULL) return NULL; - memset(machine, 0, sizeof(v8086)); - machine->regs.x.flags = 0x2; - machine->sregs.cs = 0xf000; - machine->IP.w.ip = 0xfff0; - machine->sregs.ss = 0x0; - machine->regs.d.ebp = 0x7bff; - machine->regs.d.esp = 0x7bff; - memcpy(machine->Memory, (void*)0xc0000000, 0x100000); + memset(machine, 0, sizeof(union test_v8086)); + machine->machine.regs.x.flags = 0x2; + machine->machine.sregs.cs = 0xf000; + machine->machine.IP.w.ip = 0xfff0; + machine->machine.sregs.ss = 0x0; + machine->machine.regs.d.ebp = 0x7bff; + machine->machine.regs.d.esp = 0x7bff; + memcpy(machine->machine.Memory, (void*)0xc0000000, 0x100000); v8086_set_8086_instruction_set(machine); return machine; } -int16_t v8086_call_function(v8086* machine) +void v8086_destroy_machine(union test_v8086* machine) +{ + heap_kernel_dealloc(machine); +} + +int16_t v8086_call_function(union test_v8086* machine) { - while(!(machine->IP.w.ip == 0xFFFF && machine->sregs.cs == 0xFFFF)) + while(!(machine->machine.IP.w.ip == 0xFFFF && machine->machine.sregs.cs == 0xFFFF)) { int16_t status = parse_and_execute_instruction(machine); if(status != V8086_OK) return status; @@ -268,12 +316,12 @@ int16_t v8086_call_function(v8086* machine) return V8086_OK; } -int16_t v8086_call_int(v8086* machine, int16_t num) +int16_t v8086_call_int(union test_v8086* machine, int16_t num) { if ((num < 0) || (num > 0xFF)) return V8086_BAD_INT_NUMBER; - machine -> IP.w.ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); - machine -> sregs.cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); - push_word(machine, machine->regs.w.flags); + machine -> machine. IP.w.ip = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4)); + machine -> machine. sregs.cs = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4 + 2)); + push_word(machine, machine->machine.regs.w.flags); push_word(machine, 0xFFFF); push_word(machine, 0xFFFF); int16_t x = v8086_call_function(machine); @@ -281,24 +329,25 @@ int16_t v8086_call_int(v8086* machine, int16_t num) return num; } -uint32_t v8086_get_address_of_int(v8086* machine, int16_t num) +uint32_t v8086_get_address_of_int(union test_v8086* machine, int16_t num) { - uint32_t ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); - uint32_t cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + uint32_t ip = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4)); + uint32_t cs = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4 + 2)); return cs * 0x10 + ip; } -int16_t parse_and_execute_instruction(v8086* machine) +int16_t parse_and_execute_instruction(union test_v8086* machine) { - machine->internal_state.IPOffset = 0; - machine->internal_state.operand_32_bit = 0; - machine->internal_state.address_32_bit = 0; - machine->internal_state.segment_reg_select = V8086_DEFAULT; - machine->internal_state.rep_prefix = V8086_NONE_REPEAT; + machine->machine.internal_state.IPOffset = 0; + machine->machine.internal_state.operand_32_bit = 0; + machine->machine.internal_state.address_32_bit = 0; + machine->machine.internal_state.segment_reg_select = V8086_DEFAULT; + machine->machine.internal_state.rep_prefix = V8086_NONE_REPEAT; int16_t status = V8086_OK; #ifdef DEBUG_V8086 + #ifdef DEBUG_V8086_TEXT serial_send_string(COM1_PORT, "REGS:\n"); char str[100] = ""; kernel_sprintf(str, "AL:%02X AH:%02X AX:%04X eAX:%08X\n", machine->regs.h.al, machine->regs.h.ah, machine->regs.x.ax, machine->regs.d.eax); @@ -361,14 +410,98 @@ int16_t parse_and_execute_instruction(v8086* machine) serial_send_string(COM1_PORT, "INSTRUCTION ADDRESS:\n"); kernel_sprintf(str, "CS:%04X IP:%04X\n", machine->sregs.cs, machine->IP.w.ip); serial_send_string(COM1_PORT, str); + #endif + + #ifdef DEBUG_V8086_BIN + for(uint32_t i = 0; i < sizeof(union test_v8086); i++) + { + serial_send(COM1_PORT, machine->bytes[i]); + } + #endif + + #ifdef DEBUG_V8086_INTERACTIVE + while(true) + { + char d[100]; + vga_printstring("Waiting for commands!\n"); + char debug_operation = serial_receive(COM1_PORT); + vga_printstring("Recived Byte: \n"); + vga_printchar(debug_operation); + vga_printchar(' '); + itoa(debug_operation, d, 10); + vga_printstring(d); + vga_newline(); + if(debug_operation == 0) + break; + else if(debug_operation == 1) + send_regs(machine); + else if(debug_operation == 2) + send_sregs(machine); + else if(debug_operation == 3) + { + uint16_t seg; + uint16_t off; + seg = (uint16_t)serial_receive(COM1_PORT) << 8; + seg |= serial_receive(COM1_PORT); + off = (uint16_t)serial_receive(COM1_PORT) << 8; + off |= serial_receive(COM1_PORT); + uint8_t mem = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + serial_send(COM1_PORT, mem); + } + else if(debug_operation == 4) + { + uint16_t seg; + uint16_t off; + seg = (uint16_t)serial_receive(COM1_PORT) << 8; + seg |= serial_receive(COM1_PORT); + off = (uint16_t)serial_receive(COM1_PORT) << 8; + off |= serial_receive(COM1_PORT); + uint16_t mem = read_word_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + send_reg_16(mem); + } + else if(debug_operation == 5) + { + uint16_t seg; + uint16_t off; + seg = (uint16_t)serial_receive(COM1_PORT) << 8; + seg |= serial_receive(COM1_PORT); + off = (uint16_t)serial_receive(COM1_PORT) << 8; + off |= serial_receive(COM1_PORT); + uint32_t mem = read_dword_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + send_reg_32(mem); + } + else if(debug_operation == 6) + { + send_reg_16(machine->machine.IP.w.ip); + } + else if(debug_operation == 7) + { + for(int i = 0; i < 0x100000; i++) + serial_send(COM1_PORT,machine->machine.Memory[i]); + } + else if(debug_operation == 8) + { + uint16_t seg; + seg = (uint16_t)serial_receive(COM1_PORT) << 8; + seg |= serial_receive(COM1_PORT); + for(int i = 0; i < 64 * 1024; i++) + serial_send(COM1_PORT,machine->machine.Memory[seg * 0x10 + i]); + } + else{ + vga_printstring("Unknown byte: "); + vga_printchar(debug_operation); + vga_newline(); + } + } + #endif #endif //Maybe opcode, an be also prefix uint8_t opcode; - decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); - uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - machine->internal_state.IPOffset += 1; + decode: opcode = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset)); + uint32_t temp = get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset); + uint8_t* ptr_to_opcode = get_byte_pointer(machine->machine.Memory, get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset)); + machine->machine.internal_state.IPOffset += 1; /*char str[5] = ""; @@ -384,43 +517,43 @@ int16_t parse_and_execute_instruction(v8086* machine) //Segment Prefix V8086_CS DS V8086_ES SS if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment { - machine->internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; + machine->machine.internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; goto decode; //continue parsing opcode; } //Segment Prefix FS else if(opcode == 0x64) { - machine->internal_state.segment_reg_select = V8086_FS; + machine->machine.internal_state.segment_reg_select = V8086_FS; goto decode; //continue parsing opcode; } //Segment Prefix GS else if(opcode == 0x65) { - machine->internal_state.segment_reg_select = V8086_GS; + machine->machine.internal_state.segment_reg_select = V8086_GS; goto decode; //continue parsing opcode; } //Operand Size Prefix else if(opcode == 0x66) { - machine->internal_state.operand_32_bit = 1; + machine->machine.internal_state.operand_32_bit = 1; goto decode; //continue parsing opcode; } //Address Szie Prefix else if(opcode == 0x67) { - machine->internal_state.address_32_bit = 1; + machine->machine.internal_state.address_32_bit = 1; goto decode; } //REPNE Prefix else if(opcode == 0xF2) { - machine->internal_state.rep_prefix = V8086_REPNE; + machine->machine.internal_state.rep_prefix = V8086_REPNE; goto decode; //continue parsing opcode; } //REP/REPE Prefix else if(opcode == 0xF3) { - machine->internal_state.rep_prefix = V8086_REP_REPE; + machine->machine.internal_state.rep_prefix = V8086_REP_REPE; goto decode; //continue parsing opcode; } //LOCK Prefix @@ -429,14 +562,16 @@ int16_t parse_and_execute_instruction(v8086* machine) goto decode; //ommit prefix, contniue parsinf opcode; } - if(machine->operations[opcode] != NULL) - status = machine->operations[opcode](machine, opcode); + if(machine->machine.operations[opcode] != NULL) + status = machine->machine.operations[opcode](&(machine->machine), opcode); else return V8086_UNDEFINED_OPCODE; - machine->IP.w.ip += machine->internal_state.IPOffset; + machine->machine.IP.w.ip += machine->machine.internal_state.IPOffset; #ifdef DEBUG_V8086 + #ifdef DEBUG_V8086_TEXT serial_send_string(COM1_PORT, "------------------------------------------\n"); + #endif #endif return status; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 264cbcf1..a7088e51 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -18,7 +18,8 @@ #define DIRECTION_FLAG_BIT 10u #define OVERFLOW_FLAG_BIT 11u -#define DEBUG_V8086 +//#define DEBUG_V8086 +//#define TEST_V8086 typedef enum _segment_register_select { V8086_ES, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT @@ -120,7 +121,7 @@ struct SREGS { uint16_t gs; uint16_t cs; uint16_t ss; -}; +} __attribute__((packed)); struct DWORDIP{ uint32_t eip; @@ -143,7 +144,7 @@ typedef struct _is{ segment_register_select segment_reg_select; repeat_prefix rep_prefix; uint16_t IPOffset; -} _internal_state; +}__attribute__((packed)) _internal_state; typedef struct _v8086 { @@ -156,12 +157,20 @@ typedef struct _v8086 int16_t (*operations[256]) (struct _v8086*, uint8_t); int16_t (*operations_0fh[256]) (struct _v8086*, uint8_t); -} v8086; +}__attribute__((packed)) v8086; + + +union test_v8086 +{ + struct _v8086 machine; + uint8_t bytes[sizeof(struct _v8086)]; +}; -v8086* v8086_create_machine(); -int16_t v8086_call_int(v8086* machine, int16_t num); +union test_v8086* v8086_create_machine(); +void v8086_destroy_machine(union test_v8086* machine); +int16_t v8086_call_int(union test_v8086* machine, int16_t num); void v8086_set_8086_instruction_set(v8086* machine); void v8086_set_386_instruction_set(v8086* machine); -uint32_t v8086_get_address_of_int(v8086* machine, int16_t num); +uint32_t v8086_get_address_of_int(union test_v8086* machine, int16_t num); #endif \ No newline at end of file diff --git a/resources/lena.bmp b/resources/lena.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c8ae0e6825c33e066286d18c5cf09637702c022d GIT binary patch literal 65146 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 literal 0 HcmV?d00001 From 673b66cbf4e6a6cb5ca5b271ced4ffa2ed6b8b89 Mon Sep 17 00:00:00 2001 From: SzateX Date: Tue, 3 Nov 2020 01:09:57 +0100 Subject: [PATCH 102/165] Added main MakeFile, corrected from $(PWD) to $(CURDIR) in internal makefiles --- Makefile | 43 +++++++++++++++++++++++++++++++++++ environment/cat/makefile | 4 ++-- environment/help/makefile | 4 ++-- environment/ls/makefile | 4 ++-- environment/mkdir/makefile | 4 ++-- environment/reboot/makefile | 4 ++-- environment/rename/makefile | 4 ++-- environment/rm/makefile | 4 ++-- environment/shell/makefile | 4 ++-- environment/shutdown/makefile | 4 ++-- environment/snake/makefile | 4 ++-- environment/space/makefile | 4 ++-- environment/tasks/makefile | 4 ++-- environment/time/makefile | 4 ++-- environment/touch/makefile | 4 ++-- library/makefile | 4 ++-- os/kernel/makefile | 4 ++-- 17 files changed, 75 insertions(+), 32 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..49fe5ce2 --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +THREADS_COUNT := 1 +WORKSPACE_DIR := ${CURDIR} + +.PHONY: all +all: + # Delete old ELF and BIN files + find build -iname "*.elf" -type f -delete + find build -iname "*.bin" -type f -delete + + find environment -iname "*.elf" -type f -delete + find library -iname "*.elf" -type f -delete + find os -iname "*.elf" -type f -delete + + $(MAKE) -C os/bootloader + + $(MAKE) -C library + + for d in $(sort $(dir $(wildcard ./environment/*/))) ; do \ + $(MAKE) -C $${d}; \ + done + + $(MAKE) -C os/kernel + + +.PHONY: clean +clean: + # Delete old ELF and BIN files + find build -iname "*.elf" -type f -delete + find build -iname "*.bin" -type f -delete + + find environment -iname "*.elf" -type f -delete + find library -iname "*.elf" -type f -delete + find os -iname "*.elf" -type f -delete + + $(MAKE) -C os/bootloader clean + + $(MAKE) -C library clean + + for d in $(sort $(dir $(wildcard ./environment/*/))) ; do \ + $(MAKE) -C $${d} clean; \ + done + + $(MAKE) -C os/kernel clean \ No newline at end of file diff --git a/environment/cat/makefile b/environment/cat/makefile index 08c5c896..ae571610 100644 --- a/environment/cat/makefile +++ b/environment/cat/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/help/makefile b/environment/help/makefile index 3706db23..3f6a5d5b 100644 --- a/environment/help/makefile +++ b/environment/help/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/ls/makefile b/environment/ls/makefile index dcd628fc..1868d10d 100644 --- a/environment/ls/makefile +++ b/environment/ls/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/mkdir/makefile b/environment/mkdir/makefile index 248d556c..fb25bdff 100644 --- a/environment/mkdir/makefile +++ b/environment/mkdir/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/reboot/makefile b/environment/reboot/makefile index cfd14da3..4b7b9234 100644 --- a/environment/reboot/makefile +++ b/environment/reboot/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/rename/makefile b/environment/rename/makefile index beb15b05..5df77476 100644 --- a/environment/rename/makefile +++ b/environment/rename/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/rm/makefile b/environment/rm/makefile index d5c3d5e4..bf3ba488 100644 --- a/environment/rm/makefile +++ b/environment/rm/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/shell/makefile b/environment/shell/makefile index f68f2ced..ddd1a00b 100644 --- a/environment/shell/makefile +++ b/environment/shell/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/shutdown/makefile b/environment/shutdown/makefile index e835b447..f2227b24 100644 --- a/environment/shutdown/makefile +++ b/environment/shutdown/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/snake/makefile b/environment/snake/makefile index d7cebd73..b139fc9c 100644 --- a/environment/snake/makefile +++ b/environment/snake/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/space/makefile b/environment/space/makefile index 68563eef..dd67fd53 100644 --- a/environment/space/makefile +++ b/environment/space/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/tasks/makefile b/environment/tasks/makefile index 3da2ef39..dd12ae11 100644 --- a/environment/tasks/makefile +++ b/environment/tasks/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/time/makefile b/environment/time/makefile index 19316c4d..f770acd5 100644 --- a/environment/time/makefile +++ b/environment/time/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/environment/touch/makefile b/environment/touch/makefile index d878f53c..9965a544 100644 --- a/environment/touch/makefile +++ b/environment/touch/makefile @@ -32,12 +32,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/library/makefile b/library/makefile index c8f8427f..942b18b1 100644 --- a/library/makefile +++ b/library/makefile @@ -33,12 +33,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) diff --git a/os/kernel/makefile b/os/kernel/makefile index 697a99d6..e9b9a5dc 100644 --- a/os/kernel/makefile +++ b/os/kernel/makefile @@ -37,12 +37,12 @@ $(OUTPUT_FILE): $(C_OBJECTS) $(ASM_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @echo "=== Compiling C file $< into object $@ ===" @mkdir -p '$(@D)' - @$(GCC) -c $(PWD)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) + @$(GCC) -c $(CURDIR)/$< -o $@ -MMD -MF $(@:.o=.d) $(GCC_COMPILE_FLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.asm @echo "=== Compiling asm file $< into object $@ ===" @mkdir -p '$(@D)' - @$(NASM) $(PWD)/$< -f elf32 -o $@ + @$(NASM) $(CURDIR)/$< -f elf32 -o $@ -include $(DEPS) From 81ddea8eb6259aa1b8a1464c3be86a3445b72f2f Mon Sep 17 00:00:00 2001 From: SzateX Date: Tue, 3 Nov 2020 01:12:42 +0100 Subject: [PATCH 103/165] Some CLion stuff ignored --- .gitignore | 5 ++++- .idea/.gitignore | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .idea/.gitignore diff --git a/.gitignore b/.gitignore index 28b3c6af..3d832840 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,7 @@ scripts docs cloc.exe -cloc.bat \ No newline at end of file +cloc.bat +.idea/vcs.xml +.idea/MicrOS.iml +.idea/misc.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..73f69e09 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ From 253b98a099c4fc864071ba525c090e48edadb594 Mon Sep 17 00:00:00 2001 From: Tearth Date: Wed, 23 Dec 2020 15:41:36 +0100 Subject: [PATCH 104/165] Adjust makefiles to the new GCC version --- environment/cat/makefile | 2 +- environment/help/makefile | 2 +- environment/ls/makefile | 2 +- environment/mkdir/makefile | 2 +- environment/reboot/makefile | 2 +- environment/rename/makefile | 2 +- environment/rm/makefile | 2 +- environment/shell/makefile | 2 +- environment/shutdown/makefile | 2 +- environment/snake/makefile | 2 +- environment/space/makefile | 2 +- environment/tasks/makefile | 2 +- environment/time/makefile | 2 +- environment/touch/makefile | 2 +- library/makefile | 4 ++-- os/bootloader-hdd/makefile | 2 +- os/bootloader/makefile | 2 +- os/kernel/makefile | 4 ++-- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/environment/cat/makefile b/environment/cat/makefile index 08c5c896..03eaac8f 100644 --- a/environment/cat/makefile +++ b/environment/cat/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/help/makefile b/environment/help/makefile index 3706db23..557603aa 100644 --- a/environment/help/makefile +++ b/environment/help/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/ls/makefile b/environment/ls/makefile index dcd628fc..0e69e891 100644 --- a/environment/ls/makefile +++ b/environment/ls/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/mkdir/makefile b/environment/mkdir/makefile index 248d556c..77226465 100644 --- a/environment/mkdir/makefile +++ b/environment/mkdir/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/reboot/makefile b/environment/reboot/makefile index cfd14da3..2c2c663a 100644 --- a/environment/reboot/makefile +++ b/environment/reboot/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/rename/makefile b/environment/rename/makefile index beb15b05..14a770dc 100644 --- a/environment/rename/makefile +++ b/environment/rename/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/rm/makefile b/environment/rm/makefile index d5c3d5e4..d54f8615 100644 --- a/environment/rm/makefile +++ b/environment/rm/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/shell/makefile b/environment/shell/makefile index f68f2ced..84f2ab03 100644 --- a/environment/shell/makefile +++ b/environment/shell/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/shutdown/makefile b/environment/shutdown/makefile index e835b447..74eda187 100644 --- a/environment/shutdown/makefile +++ b/environment/shutdown/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/snake/makefile b/environment/snake/makefile index d7cebd73..ebac13c6 100644 --- a/environment/snake/makefile +++ b/environment/snake/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/space/makefile b/environment/space/makefile index 68563eef..d333b16a 100644 --- a/environment/space/makefile +++ b/environment/space/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/tasks/makefile b/environment/tasks/makefile index 3da2ef39..97fb2261 100644 --- a/environment/tasks/makefile +++ b/environment/tasks/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/time/makefile b/environment/time/makefile index 19316c4d..6d928fc3 100644 --- a/environment/time/makefile +++ b/environment/time/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/touch/makefile b/environment/touch/makefile index d878f53c..ef028acc 100644 --- a/environment/touch/makefile +++ b/environment/touch/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/library/makefile b/library/makefile index c8f8427f..6e007bcd 100644 --- a/library/makefile +++ b/library/makefile @@ -1,5 +1,5 @@ -GCC := /opt/cross/bin/i386-elf-gcc -AR := /opt/cross/bin/i386-elf-ar +GCC := /opt/cross/bin/i686-elf-gcc +AR := /opt/cross/bin/i686-elf-ar NASM := "../tools/nasm" SRC_DIR := src diff --git a/os/bootloader-hdd/makefile b/os/bootloader-hdd/makefile index d676e57c..178f3146 100644 --- a/os/bootloader-hdd/makefile +++ b/os/bootloader-hdd/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc NASM := "../../Tools/nasm" SRC_DIR := src diff --git a/os/bootloader/makefile b/os/bootloader/makefile index abc2358f..7ea25b3b 100644 --- a/os/bootloader/makefile +++ b/os/bootloader/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i386-elf-gcc +GCC := /opt/cross/bin/i686-elf-gcc NASM := "../../tools/nasm" SRC_DIR := src diff --git a/os/kernel/makefile b/os/kernel/makefile index 697a99d6..ba05cc5e 100644 --- a/os/kernel/makefile +++ b/os/kernel/makefile @@ -1,5 +1,5 @@ -GCC := /opt/cross/bin/i386-elf-gcc -OBJCOPY := /opt/cross/i386-elf/bin/objcopy +GCC := /opt/cross/bin/i686-elf-gcc +OBJCOPY := /opt/cross/i686-elf/bin/objcopy NASM := "../../tools/nasm" SRC_DIR := src From 835c762450195552c32f0ad1cc44c33e3a61c78a Mon Sep 17 00:00:00 2001 From: Tearth Date: Wed, 23 Dec 2020 21:23:37 +0100 Subject: [PATCH 105/165] Fix GCC 10 errors --- library/src/locale.h | 4 ++-- library/src/locale/locale.c | 3 +++ library/src/signal/__signal_init.c | 2 -- library/src/signal/raise.c | 2 -- library/src/signal/signal.c | 2 +- library/src/stdio.h | 6 +++--- library/src/stdio/stdio.c | 4 ++++ library/src/stdlib.h | 2 +- library/src/stdlib/stdlib.c | 3 +++ library/src/time.h | 2 +- library/src/time/time.c | 2 ++ 11 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 library/src/stdlib/stdlib.c diff --git a/library/src/locale.h b/library/src/locale.h index 1c6a3ceb..953e6345 100644 --- a/library/src/locale.h +++ b/library/src/locale.h @@ -100,10 +100,10 @@ typedef struct lconv } lconv; //! Current locale state. -lconv *locale_state; +extern lconv *locale_state; //! Current locale name. -char *locale_name; +extern char *locale_name; #ifdef __cplusplus extern "C" { diff --git a/library/src/locale/locale.c b/library/src/locale/locale.c index be488277..11d9ce1c 100644 --- a/library/src/locale/locale.c +++ b/library/src/locale/locale.c @@ -1,5 +1,8 @@ #include "../locale.h" +lconv *locale_state; +char *locale_name; + void __locale_delete_char_field_value(char *field) { if (field != NULL) diff --git a/library/src/signal/__signal_init.c b/library/src/signal/__signal_init.c index 745375a3..2a73fbe7 100644 --- a/library/src/signal/__signal_init.c +++ b/library/src/signal/__signal_init.c @@ -1,7 +1,5 @@ #include "../signal.h" -void (*signal_handlers[6])(int); - void __signal_init() { signal_handlers[0] = default_sigabrt_handler; diff --git a/library/src/signal/raise.c b/library/src/signal/raise.c index 9747e2e1..f48fe959 100644 --- a/library/src/signal/raise.c +++ b/library/src/signal/raise.c @@ -1,7 +1,5 @@ #include "../signal.h" -void (*signal_handlers[6])(int); - int raise(int sig) { return raise_with_param(sig, 0); diff --git a/library/src/signal/signal.c b/library/src/signal/signal.c index 02af63a7..87470f3c 100644 --- a/library/src/signal/signal.c +++ b/library/src/signal/signal.c @@ -1,6 +1,6 @@ #include "../signal.h" -void (*signal_handlers[6])(int); +signal_func signal_handlers[6]; void (*signal(int sig, signal_func func))(int) { diff --git a/library/src/stdio.h b/library/src/stdio.h index 901982c9..43a34cae 100644 --- a/library/src/stdio.h +++ b/library/src/stdio.h @@ -109,13 +109,13 @@ typedef struct file } FILE; //! Standard input (default is keyboard). -FILE *stdin; +extern FILE *stdin; //! Standard output (default is console). -FILE *stdout; +extern FILE *stdout; //! Standard error output (default is console). -FILE *stderr; +extern FILE *stderr; #ifdef __cplusplus extern "C" { diff --git a/library/src/stdio/stdio.c b/library/src/stdio/stdio.c index 508bb92c..56189f7b 100644 --- a/library/src/stdio/stdio.c +++ b/library/src/stdio/stdio.c @@ -1,5 +1,9 @@ #include "../stdio.h" +FILE *stdin; +FILE *stdout; +FILE *stderr; + FILE *__stdio_create_stream() { FILE *stream = malloc(sizeof(FILE)); diff --git a/library/src/stdlib.h b/library/src/stdlib.h index b3b99dda..d1cadcc1 100644 --- a/library/src/stdlib.h +++ b/library/src/stdlib.h @@ -6,7 +6,7 @@ #include "time.h" #include "micros.h" -unsigned int seed; +extern unsigned int seed; //! Maximum value returned by rand #define RAND_MAX INT32_MAX diff --git a/library/src/stdlib/stdlib.c b/library/src/stdlib/stdlib.c new file mode 100644 index 00000000..6f90ec09 --- /dev/null +++ b/library/src/stdlib/stdlib.c @@ -0,0 +1,3 @@ +#include "../stdlib.h" + +unsigned int seed; \ No newline at end of file diff --git a/library/src/time.h b/library/src/time.h index 522089ba..96204772 100644 --- a/library/src/time.h +++ b/library/src/time.h @@ -45,7 +45,7 @@ typedef struct tm } tm; //! Internal variable used during time conversions -tm converted_time; +extern tm converted_time; #ifdef __cplusplus extern "C" { diff --git a/library/src/time/time.c b/library/src/time/time.c index 9b660eaa..e3f1c92e 100644 --- a/library/src/time/time.c +++ b/library/src/time/time.c @@ -1,5 +1,7 @@ #include "../time.h" +tm converted_time; + time_t time(time_t* timer) { micros_rtc_time rtc_time; From 34bbe7c37155585c4fd7b8c890b58b5517bc238b Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Fri, 25 Dec 2020 12:31:40 +0100 Subject: [PATCH 106/165] Going back to i386 --- environment/cat/makefile | 2 +- environment/help/makefile | 2 +- environment/ls/makefile | 2 +- environment/mkdir/makefile | 2 +- environment/reboot/makefile | 2 +- environment/rename/makefile | 2 +- environment/rm/makefile | 2 +- environment/shell/makefile | 2 +- environment/shutdown/makefile | 2 +- environment/snake/makefile | 2 +- environment/space/makefile | 2 +- environment/tasks/makefile | 2 +- environment/time/makefile | 2 +- environment/touch/makefile | 2 +- library/makefile | 4 ++-- os/bootloader-hdd/makefile | 2 +- os/bootloader/makefile | 2 +- os/kernel/makefile | 4 ++-- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/environment/cat/makefile b/environment/cat/makefile index 03eaac8f..08c5c896 100644 --- a/environment/cat/makefile +++ b/environment/cat/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/help/makefile b/environment/help/makefile index 557603aa..3706db23 100644 --- a/environment/help/makefile +++ b/environment/help/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/ls/makefile b/environment/ls/makefile index 0e69e891..dcd628fc 100644 --- a/environment/ls/makefile +++ b/environment/ls/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/mkdir/makefile b/environment/mkdir/makefile index 77226465..248d556c 100644 --- a/environment/mkdir/makefile +++ b/environment/mkdir/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/reboot/makefile b/environment/reboot/makefile index 2c2c663a..cfd14da3 100644 --- a/environment/reboot/makefile +++ b/environment/reboot/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/rename/makefile b/environment/rename/makefile index 14a770dc..beb15b05 100644 --- a/environment/rename/makefile +++ b/environment/rename/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/rm/makefile b/environment/rm/makefile index d54f8615..d5c3d5e4 100644 --- a/environment/rm/makefile +++ b/environment/rm/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/shell/makefile b/environment/shell/makefile index 84f2ab03..f68f2ced 100644 --- a/environment/shell/makefile +++ b/environment/shell/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/shutdown/makefile b/environment/shutdown/makefile index 74eda187..e835b447 100644 --- a/environment/shutdown/makefile +++ b/environment/shutdown/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/snake/makefile b/environment/snake/makefile index ebac13c6..d7cebd73 100644 --- a/environment/snake/makefile +++ b/environment/snake/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/space/makefile b/environment/space/makefile index d333b16a..68563eef 100644 --- a/environment/space/makefile +++ b/environment/space/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/tasks/makefile b/environment/tasks/makefile index 97fb2261..3da2ef39 100644 --- a/environment/tasks/makefile +++ b/environment/tasks/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/time/makefile b/environment/time/makefile index 6d928fc3..19316c4d 100644 --- a/environment/time/makefile +++ b/environment/time/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/environment/touch/makefile b/environment/touch/makefile index ef028acc..d878f53c 100644 --- a/environment/touch/makefile +++ b/environment/touch/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc SRC_DIR := src OBJ_DIR := obj diff --git a/library/makefile b/library/makefile index 6e007bcd..c8f8427f 100644 --- a/library/makefile +++ b/library/makefile @@ -1,5 +1,5 @@ -GCC := /opt/cross/bin/i686-elf-gcc -AR := /opt/cross/bin/i686-elf-ar +GCC := /opt/cross/bin/i386-elf-gcc +AR := /opt/cross/bin/i386-elf-ar NASM := "../tools/nasm" SRC_DIR := src diff --git a/os/bootloader-hdd/makefile b/os/bootloader-hdd/makefile index 178f3146..d676e57c 100644 --- a/os/bootloader-hdd/makefile +++ b/os/bootloader-hdd/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc NASM := "../../Tools/nasm" SRC_DIR := src diff --git a/os/bootloader/makefile b/os/bootloader/makefile index 7ea25b3b..abc2358f 100644 --- a/os/bootloader/makefile +++ b/os/bootloader/makefile @@ -1,4 +1,4 @@ -GCC := /opt/cross/bin/i686-elf-gcc +GCC := /opt/cross/bin/i386-elf-gcc NASM := "../../tools/nasm" SRC_DIR := src diff --git a/os/kernel/makefile b/os/kernel/makefile index ba05cc5e..697a99d6 100644 --- a/os/kernel/makefile +++ b/os/kernel/makefile @@ -1,5 +1,5 @@ -GCC := /opt/cross/bin/i686-elf-gcc -OBJCOPY := /opt/cross/i686-elf/bin/objcopy +GCC := /opt/cross/bin/i386-elf-gcc +OBJCOPY := /opt/cross/i386-elf/bin/objcopy NASM := "../../tools/nasm" SRC_DIR := src From 1c2358e2e33400bb42ca6440086614504281696e Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Mon, 28 Dec 2020 12:46:46 +0100 Subject: [PATCH 107/165] Some changes --- debug.log | 90 +++++++++++++++ os/kernel/src/v8086/tests/tests.c | 184 ++++++++++++++++-------------- os/kernel/src/v8086/tests/tests.h | 2 - os/kernel/src/v8086/v8086.c | 49 +++++++- os/kernel/src/v8086/v8086.h | 17 ++- 5 files changed, 249 insertions(+), 93 deletions(-) create mode 100644 debug.log diff --git a/debug.log b/debug.log new file mode 100644 index 00000000..543b2645 --- /dev/null +++ b/debug.log @@ -0,0 +1,90 @@ +SeaBIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) +BUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) binutils: version 2.27-28.base.el7_5.1 +No Xen hypervisor found. +Running on QEMU (i440fx) +RamSize: 0x28000000 [cmos] +Relocating init from 0x000d77f0 to 0x27fab680 (size 84208) +Found QEMU fw_cfg +QEMU fw_cfg DMA interface supported +RamBlock: addr 0x0000000000000000 len 0x0000000028000000 [e820] +Moving pm_base to 0x600 +=== PCI bus & bridge init === +PCI: pci_bios_init_bus_rec bus = 0x0 +=== PCI device probing === +Found 6 PCI devices (max PCI bus is 00) +=== PCI new allocation pass #1 === +PCI: check devices +=== PCI new allocation pass #2 === +PCI: IO: c000 - c04f +PCI: 32: 0000000080000000 - 00000000fec00000 +PCI: map device bdf=00:03.0 bar 1, addr 0000c000, size 00000040 [io] +PCI: map device bdf=00:01.1 bar 4, addr 0000c040, size 00000010 [io] +PCI: map device bdf=00:03.0 bar 6, addr feb80000, size 00040000 [mem] +PCI: map device bdf=00:03.0 bar 0, addr febc0000, size 00020000 [mem] +PCI: map device bdf=00:02.0 bar 6, addr febe0000, size 00010000 [mem] +PCI: map device bdf=00:02.0 bar 2, addr febf0000, size 00001000 [mem] +PCI: map device bdf=00:02.0 bar 0, addr fd000000, size 01000000 [prefmem] +PCI: init bdf=00:00.0 id=8086:1237 +PCI: init bdf=00:01.0 id=8086:7000 +PIIX3/PIIX4 init: elcr=00 0c +PCI: init bdf=00:01.1 id=8086:7010 +PCI: init bdf=00:01.3 id=8086:7113 +Using pmtimer, ioport 0x608 +PCI: init bdf=00:02.0 id=1234:1111 +PCI: init bdf=00:03.0 id=8086:100e +PCI: Using 00:02.0 for primary VGA +Found 1 cpu(s) max supported 1 cpu(s) +Copying PIR from 0x27fbfca4 to 0x000f5a20 +Copying MPTABLE from 0x00006e44/27fa2690 to 0x000f5940 +Copying SMBIOS entry point from 0x00006e44 to 0x000f5780 +Scan for VGA option rom +Running option rom at c000:0003 +Start SeaVGABIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) +VGABUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) binutils: version 2.27-28.base.el7_5.1 +enter vga_post: + a=00000010 b=0000ffff c=00000000 d=0000ffff ds=0000 es=f000 ss=0000 + si=00000000 di=00005df0 bp=00000000 sp=00006d6e cs=f000 ip=d02a f=0000 +VBE DISPI: bdf 00:02.0, bar 0 +VBE DISPI: lfb_addr=fd000000, size 16 MB +Attempting to allocate 512 bytes lowmem via pmm call to f000:d0e1 +pmm call arg1=0 +VGA stack allocated at eb620 +Turning on vga text mode console +set VGA mode 3 +SeaBIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) +Searching bootorder for: /pci@i0cf8/isa@1/fdc@03f0/floppy@0 +ATA controller 1 at 1f0/3f4/c040 (irq 14 dev 9) +ATA controller 2 at 170/374/c048 (irq 15 dev 9) +Found 1 lpt ports +Found 1 serial ports +ata0-0: QEMU HARDDISK ATA-7 Hard-Disk (100 MiBytes) +Searching bootorder for: /pci@i0cf8/*@1,1/drive@0/disk@0 +DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] +Searching bootorder for: /pci@i0cf8/*@1,1/drive@1/disk@0 +PS2 keyboard initialized +All threads complete. +Scan for option roms +Running option rom at c980:0003 +pmm call arg1=1 +pmm call arg1=0 +pmm call arg1=1 +pmm call arg1=0 +Searching bootorder for: /pci@i0cf8/*@3 +Searching bootorder for: /rom@genroms/kvmvapic.bin +Searching bootorder for: HALT +drive 0x000f56b0: PCHS=203/16/63 translation=large LCHS=203/16/63 s=204800 +Running option rom at ca80:0003 +Space available for UMB: cd000-ea800, f52a0-f5650 +Returned 131072 bytes of ZoneHigh +e820 map has 6 items: + 0: 0000000000000000 - 000000000009fc00 = 1 RAM + 1: 000000000009fc00 - 00000000000a0000 = 2 RESERVED + 2: 00000000000f0000 - 0000000000100000 = 2 RESERVED + 3: 0000000000100000 - 0000000027fe0000 = 1 RAM + 4: 0000000027fe0000 - 0000000028000000 = 2 RESERVED + 5: 00000000fffc0000 - 0000000100000000 = 2 RESERVED +enter handle_19: + NULL +Booting from Floppy... +Booting from 0000:7c00 +set VGA mode 13 diff --git a/os/kernel/src/v8086/tests/tests.c b/os/kernel/src/v8086/tests/tests.c index e1fd734e..9bd68539 100644 --- a/os/kernel/src/v8086/tests/tests.c +++ b/os/kernel/src/v8086/tests/tests.c @@ -7,96 +7,104 @@ #include "string.h" #include "../../debug_helpers/library/kernel_stdio.h" -char* effective_addresses[3][8] = { - {"[BX+SI]", "[BX+DI]", "[BP+SI]", "[BP+DI]", "[SI]", "[DI]", "disp16", "[BX]"}, - {"[BX+SI]+disp8", "[BX+DI]+disp8", "[BP+SI]+disp8", "[BP+DI]+disp8", "[SI]+disp8", "[DI]+disp8", "[BP]+disp8", "[BX]+disp8"}, - {"[BX+SI]+disp16", "[BX+DI]+disp16", "[BP+SI]+disp16", "[BP+DI]+disp16", "[SI]+disp16", "[DI]+disp16", "[BP]+disp16", "[BX]+disp16"} -}; -#define test_mod_16_func(width) void test_mod_16_width_##width(v8086* machine){\ - uint##width##_t* memory_##width;\ - uint##width##_t* expected_memory_##width;\ - machine->IP.w.ip = 0; \ - machine->sregs.cs = 0; \ - machine->regs.x.bx = 0; \ - machine->regs.x.bp = 0; \ - machine->regs.x.si = 0; \ - machine->regs.x.di = 0; \ - char str[100] = ""; \ - for(uint16_t mod_rm=0; mod_rm < 192; mod_rm++) \ - { \ - char* effective_address = effective_addresses[mod_rm >> 6][mod_rm & 7]; \ - uint16_t cumulative_offset = 0; \ - uint8_t bp_on_road = 0; \ - if(strstr(effective_address, "BX") != NULL) \ - { \ - uint16_t offset = 98; \ - machine->regs.x.bx = offset; \ - cumulative_offset += offset; \ - } \ - if(strstr(effective_address, "BP") != NULL) \ - { \ - uint16_t offset = 56; \ - machine->regs.x.bp = offset; \ - cumulative_offset += offset; \ - bp_on_road = 1; \ - } \ - if(strstr(effective_address, "SI") != NULL) \ - { \ - uint16_t offset = 15; \ - machine->regs.x.si = offset; \ - cumulative_offset += offset; \ - } \ - if(strstr(effective_address, "DI") != NULL) \ - { \ - uint16_t offset = 32; \ - machine->regs.x.di = offset; \ - cumulative_offset += offset; \ - } \ - if(strstr(effective_address, "disp8") != NULL) \ - { \ - int16_t offset = 69; \ - machine->Memory[0] = offset; \ - cumulative_offset += offset; \ - } \ - if(strstr(effective_address, "disp16") != NULL) \ - { \ - uint16_t offset = 1520; \ - machine->Memory[0] = offset & 0xff; \ - machine->Memory[1] = offset >> 8; \ - cumulative_offset += offset; \ - } \ - memory_##width = (uint##width##_t*)get_memory_from_mode(machine, mod_rm, width); \ - expected_memory_##width = (uint##width##_t*)(machine->Memory + cumulative_offset + (bp_on_road ? machine->sregs.ss:machine->sregs.ds) * 0x10);\ - machine->internal_state.IPOffset = 0; \ - machine->regs.x.bx = 0; \ - machine->regs.x.bp = 0; \ - machine->regs.x.si = 0; \ - machine->regs.x.di = 0; \ - if(memory_##width != expected_memory_##width){ \ - kernel_sprintf(str, "ERROR for mode %x and width %d\n", mod_rm, width); \ - serial_send_string(COM1_PORT, str); \ - } \ - else{ \ - kernel_sprintf(str, "OK for mode %x and width %d\n", mod_rm, width); \ - serial_send_string(COM1_PORT, str); \ - } \ - } \ -} - -test_mod_16_func(8) -test_mod_16_func(16) -test_mod_16_func(32) - -void test_mod_16() +void interactive_tests() { - v8086* machine = v8086_create_machine(); - - test_mod_16_width_8(machine); - test_mod_16_width_16(machine); - test_mod_16_width_32(machine); - - v8086_destroy_machine(machine); + union test_v8086* machine = v8086_create_machine(); + while(true) + { + char d[100]; + vga_printstring("Waiting for commands!\n"); + char debug_operation = serial_receive(COM1_PORT); + vga_printstring("Recived Byte: \n"); + vga_printchar(debug_operation); + vga_printchar(' '); + itoa(debug_operation, d, 10); + vga_printstring(d); + vga_newline(); + if(debug_operation == 0) // EXIT + break; + else if(debug_operation == 1) // SEND REGS + send_regs(machine); + else if(debug_operation == 2) // SEND SREGS + send_sregs(machine); + else if(debug_operation == 3) // READ BYTE + { + uint16_t seg; + uint16_t off; + seg = read_reg_16(); + off = read_reg_16(); + uint8_t mem = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + serial_send(COM1_PORT, mem); + } + else if(debug_operation == 4) // READ WORD + { + uint16_t seg; + uint16_t off; + seg = read_reg_16(); + off = read_reg_16(); + uint16_t mem = read_word_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + send_reg_16(mem); + } + else if(debug_operation == 5) // READ DWORD + { + uint16_t seg; + uint16_t off; + seg = read_reg_16(); + off = read_reg_16(); + uint32_t mem = read_dword_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + send_reg_32(mem); + } + else if(debug_operation == 6) // GET IP + { + send_reg_16(machine->machine.IP.w.ip); + } + else if(debug_operation == 7) // READ MEM + { + for(int i = 0; i < 0x100000; i++) + serial_send(COM1_PORT,machine->machine.Memory[i]); + } + else if(debug_operation == 8) // READ SEG + { + uint16_t seg = read_reg_16(); + for(int i = 0; i < 64 * 1024; i++) + serial_send(COM1_PORT,machine->machine.Memory[seg * 0x10 + i]); + } + else if(debug_operation == 9) + { + machine->machine.IP.w.ip = read_reg_16(); + } + else if(debug_operation == 10) + { + read_regs(machine); + } + else if(debug_operation == 11) + { + read_sregs(machine); + } + else if(debug_operation == 12) + { + uint32_t seg = read_reg_16(); + uint32_t off = read_reg_16(); + uint8_t length = read_reg_8(); + uint32_t addr = seg * 0x10 + off; + for(int i = addr; i < addr + length; i++) + { + machine->machine.Memory[i] = serial_receive(COM1_PORT); + } + } + else if(debug_operation == 13) + { + int16_t result = parse_and_execute_instruction(machine); + serial_send(COM1_PORT, result >> 8); + serial_send(COM1_PORT, result & 0xFF); + } + else{ + vga_printstring("Unknown byte: "); + vga_printchar(debug_operation); + vga_newline(); + } + } } #endif \ No newline at end of file diff --git a/os/kernel/src/v8086/tests/tests.h b/os/kernel/src/v8086/tests/tests.h index e8308b22..cb6650f5 100644 --- a/os/kernel/src/v8086/tests/tests.h +++ b/os/kernel/src/v8086/tests/tests.h @@ -5,8 +5,6 @@ #ifdef TEST_V8086 -void test_mod_16(); - #endif #endif \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 103e5132..c1343b82 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - #define DEBUG_V8086_INTERACTIVE + //#define DEBUG_V8086_INTERACTIVE #endif int16_t parse_and_execute_instruction(union test_v8086* machine); @@ -59,6 +59,53 @@ void send_sregs(union test_v8086* machine) send_reg_16(machine->machine.sregs.ss); } +void read_regs(union test_v8086* machine) +{ + machine->machine.regs.d.edi = read_reg_32(); + machine->machine.regs.d.esi = read_reg_32(); + machine->machine.regs.d.ebp = read_reg_32(); + machine->machine.regs.d.cflag = read_reg_32(); + machine->machine.regs.d.ebx = read_reg_32(); + machine->machine.regs.d.edx = read_reg_32(); + machine->machine.regs.d.ecx = read_reg_32(); + machine->machine.regs.d.eax = read_reg_32(); + machine->machine.regs.d.eflags = read_reg_16(); + machine->machine.regs.d.esp = read_reg_32(); +} + +void read_sregs(union test_v8086* machine) +{ + machine->machine.sregs.es = read_reg_16(); + machine->machine.sregs.ds = read_reg_16(); + machine->machine.sregs.fs = read_reg_16(); + machine->machine.sregs.gs = read_reg_16(); + machine->machine.sregs.cs = read_reg_16(); + machine->machine.sregs.ss = read_reg_16(); +} + +uint16_t read_reg_16() +{ + uint16_t value; + value = (uint16_t)serial_receive(COM1_PORT); + value |= (uint16_t)serial_receive(COM1_PORT) << 8; + return value; +} + +uint8_t read_reg_8() +{ + return serial_receive(COM1_PORT); +} + +uint32_t read_reg_32() +{ + uint32_t value; + value = (uint32_t)serial_receive(COM1_PORT); + value |= (uint32_t)serial_receive(COM1_PORT) << 8; + value |= (uint32_t)serial_receive(COM1_PORT) << 16; + value |= (uint32_t)serial_receive(COM1_PORT) << 24; + return value; +} + #endif void v8086_set_8086_instruction_set(v8086* machine) diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index a7088e51..c8f4a71e 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -18,8 +18,8 @@ #define DIRECTION_FLAG_BIT 10u #define OVERFLOW_FLAG_BIT 11u -//#define DEBUG_V8086 -//#define TEST_V8086 +#define DEBUG_V8086 +#define TEST_V8086 typedef enum _segment_register_select { V8086_ES, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT @@ -173,4 +173,17 @@ int16_t v8086_call_int(union test_v8086* machine, int16_t num); void v8086_set_8086_instruction_set(v8086* machine); void v8086_set_386_instruction_set(v8086* machine); uint32_t v8086_get_address_of_int(union test_v8086* machine, int16_t num); + +#ifdef DEBUG_V8086 + void send_reg_32(uint32_t reg); + void send_reg_16(uint16_t reg); + void send_regs(union test_v8086* machine); + void send_sregs(union test_v8086* machine); + int16_t parse_and_execute_instruction(union test_v8086* machine); + uint8_t read_reg_8(); + uint16_t read_reg_16(); + uint32_t read_reg_32(); + void read_regs(union test_v8086* machine); + void read_sregs(union test_v8086* machine); +#endif #endif \ No newline at end of file From 6e4796c9b1a6da9315401f4e1d8997b129f36464 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 2 Jan 2021 23:42:08 +0100 Subject: [PATCH 108/165] Added Test Runner --- debug.log | 48 +++++++++++++++++-------------- os/kernel/src/kernel.c | 13 +++++---- os/kernel/src/v8086/tests/tests.c | 2 ++ os/kernel/src/v8086/tests/tests.h | 2 +- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/debug.log b/debug.log index 543b2645..4279fbfe 100644 --- a/debug.log +++ b/debug.log @@ -1,12 +1,11 @@ -SeaBIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) -BUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) binutils: version 2.27-28.base.el7_5.1 +SeaBIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) +BUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) binutils: version 2.27-43.base.el7_8.1 No Xen hypervisor found. Running on QEMU (i440fx) -RamSize: 0x28000000 [cmos] -Relocating init from 0x000d77f0 to 0x27fab680 (size 84208) Found QEMU fw_cfg QEMU fw_cfg DMA interface supported -RamBlock: addr 0x0000000000000000 len 0x0000000028000000 [e820] +qemu/e820: addr 0x0000000000000000 len 0x0000000028000000 [RAM] +Relocating init from 0x000d4bf0 to 0x27fa9460 (size 92944) Moving pm_base to 0x600 === PCI bus & bridge init === PCI: pci_bios_init_bus_rec bus = 0x0 @@ -34,37 +33,43 @@ PCI: init bdf=00:02.0 id=1234:1111 PCI: init bdf=00:03.0 id=8086:100e PCI: Using 00:02.0 for primary VGA Found 1 cpu(s) max supported 1 cpu(s) -Copying PIR from 0x27fbfca4 to 0x000f5a20 -Copying MPTABLE from 0x00006e44/27fa2690 to 0x000f5940 -Copying SMBIOS entry point from 0x00006e44 to 0x000f5780 +Copying PIR from 0x27fbfc8c to 0x000f5b90 +Copying MPTABLE from 0x00006d30/27fa03f0 to 0x000f5ab0 +Copying SMBIOS entry point from 0x00006d30 to 0x000f58f0 +table(50434146)=0x27fe1404 (via rsdt) +ACPI: parse DSDT at 0x27fe0040 (len 5060) Scan for VGA option rom Running option rom at c000:0003 -Start SeaVGABIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) -VGABUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) binutils: version 2.27-28.base.el7_5.1 +Start SeaVGABIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) +VGABUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) binutils: version 2.27-43.base.el7_8.1 enter vga_post: a=00000010 b=0000ffff c=00000000 d=0000ffff ds=0000 es=f000 ss=0000 - si=00000000 di=00005df0 bp=00000000 sp=00006d6e cs=f000 ip=d02a f=0000 + si=00000000 di=00005f60 bp=00000000 sp=00006ca6 cs=f000 ip=d07a f=0000 VBE DISPI: bdf 00:02.0, bar 0 VBE DISPI: lfb_addr=fd000000, size 16 MB -Attempting to allocate 512 bytes lowmem via pmm call to f000:d0e1 +Attempting to allocate 512 bytes lowmem via pmm call to f000:d137 pmm call arg1=0 -VGA stack allocated at eb620 +VGA stack allocated at eac40 Turning on vga text mode console set VGA mode 3 -SeaBIOS (version rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org) +SeaBIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) Searching bootorder for: /pci@i0cf8/isa@1/fdc@03f0/floppy@0 -ATA controller 1 at 1f0/3f4/c040 (irq 14 dev 9) -ATA controller 2 at 170/374/c048 (irq 15 dev 9) +ATA controller 1 at 1f0/3f4/0 (irq 14 dev 9) +ATA controller 2 at 170/374/0 (irq 15 dev 9) +Searching bootorder for: HALT Found 1 lpt ports Found 1 serial ports +PS2 keyboard initialized ata0-0: QEMU HARDDISK ATA-7 Hard-Disk (100 MiBytes) Searching bootorder for: /pci@i0cf8/*@1,1/drive@0/disk@0 +Searching bios-geometry for: /pci@i0cf8/*@1,1/drive@0/disk@0 DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] Searching bootorder for: /pci@i0cf8/*@1,1/drive@1/disk@0 -PS2 keyboard initialized +Searching bios-geometry for: /pci@i0cf8/*@1,1/drive@1/disk@0 +Device reports MEDIUM NOT PRESENT All threads complete. Scan for option roms -Running option rom at c980:0003 +Running option rom at ca00:0003 pmm call arg1=1 pmm call arg1=0 pmm call arg1=1 @@ -72,9 +77,9 @@ pmm call arg1=0 Searching bootorder for: /pci@i0cf8/*@3 Searching bootorder for: /rom@genroms/kvmvapic.bin Searching bootorder for: HALT -drive 0x000f56b0: PCHS=203/16/63 translation=large LCHS=203/16/63 s=204800 -Running option rom at ca80:0003 -Space available for UMB: cd000-ea800, f52a0-f5650 +drive 0x000f5830: PCHS=203/16/63 translation=large LCHS=203/16/63 s=204800 +Running option rom at cb00:0003 +Space available for UMB: cd800-ea000, f5410-f57d0 Returned 131072 bytes of ZoneHigh e820 map has 6 items: 0: 0000000000000000 - 000000000009fc00 = 1 RAM @@ -87,4 +92,3 @@ enter handle_19: NULL Booting from Floppy... Booting from 0000:7c00 -set VGA mode 13 diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 5061433b..4a121226 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -447,16 +447,17 @@ int kmain() //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); #ifdef TEST_V8086 - test_mod_16(); + //test_mod_16(); + interactive_tests(); #endif - v8086->machine.regs.h.ah = 0x00; - v8086->machine.regs.h.al = 0x13; - int16_t status = v8086_call_int(v8086, 0x10); + //v8086->machine.regs.h.ah = 0x00; + //v8086->machine.regs.h.al = 0x13; + //int16_t status = v8086_call_int(v8086, 0x10); //mode13h_set_mode(); - mode13h_clear_screen(); - drawLenaIn13H(); + //mode13h_clear_screen(); + //drawLenaIn13H(); /*char str[100] = ""; itoa(status, str, 16); diff --git a/os/kernel/src/v8086/tests/tests.c b/os/kernel/src/v8086/tests/tests.c index 9bd68539..6c696869 100644 --- a/os/kernel/src/v8086/tests/tests.c +++ b/os/kernel/src/v8086/tests/tests.c @@ -4,8 +4,10 @@ #include "stdint.h" #include "../mod_rm_parsing.h" #include "../drivers/serial/serial.h" +#include "../drivers/vga/vga.h" #include "string.h" #include "../../debug_helpers/library/kernel_stdio.h" +#include "../memory_operations.h" void interactive_tests() diff --git a/os/kernel/src/v8086/tests/tests.h b/os/kernel/src/v8086/tests/tests.h index cb6650f5..ce0c1868 100644 --- a/os/kernel/src/v8086/tests/tests.h +++ b/os/kernel/src/v8086/tests/tests.h @@ -4,7 +4,7 @@ #include "../v8086.h" #ifdef TEST_V8086 - +void interactive_tests(); #endif #endif \ No newline at end of file From 7434adfcc154f2927d8adb40801d6fdc960ddbbf Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 19 Feb 2021 01:48:18 +0100 Subject: [PATCH 109/165] Finally corrected the memory access for 16 and 32 adressing mode in v8086 --- os/kernel/src/kernel.c | 24 +++++++++-- os/kernel/src/v8086/mod_rm_parsing.c | 63 +++++++++++++++------------- os/kernel/src/v8086/tests/tests.c | 12 ++++++ os/kernel/src/v8086/v8086.c | 17 +++++--- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 4a121226..77775d36 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -448,16 +448,34 @@ int kmain() #ifdef TEST_V8086 //test_mod_16(); - interactive_tests(); + //interactive_tests(); #endif //v8086->machine.regs.h.ah = 0x00; //v8086->machine.regs.h.al = 0x13; - //int16_t status = v8086_call_int(v8086, 0x10); + //v8086->machine.regs.h.al = 0x6a; + + v8086->machine.regs.x.ax = 0x4f03; + int16_t status = v8086_call_int(v8086, 0x10); + + char str[100] = ""; + if(v8086->machine.regs.x.ax == 0x004f) + { + itoa(v8086->machine.regs.x.bx, str, 16); + vga_printstring(str); + vga_newline(); + } + else{ + vga_printstring("DUPA!"); + } + + v8086->machine.regs.x.ax = 0x4f02; + v8086->machine.regs.x.bx = 0x11b; + status = v8086_call_int(v8086, 0x10); //mode13h_set_mode(); //mode13h_clear_screen(); - //drawLenaIn13H(); + drawLenaIn13H(); /*char str[100] = ""; itoa(status, str, 16); diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index c5663bcc..812d9844 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -151,25 +151,25 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 case 0: switch(mod_rm & 7u){ case 0: - *offset = machine->regs.x.bx + machine->regs.x.si; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.si); return V8086_OK; case 1: - *offset = machine->regs.x.bx + machine->regs.x.di; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.di); return V8086_OK; case 2: - *offset = machine->regs.x.bp + machine->regs.x.si; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.si); return V8086_OK; case 3: - *offset = machine->regs.x.bp + machine->regs.x.di; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.di); return V8086_OK; case 4: - *offset = machine->regs.x.si; + *offset = (uint16_t)(machine->regs.x.si); return V8086_OK; case 5: - *offset = machine->regs.x.di; + *offset = (uint16_t)(machine->regs.x.di); return V8086_OK; case 6:{ - *offset = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + (machine->internal_state.IPOffset))); + *offset = (uint16_t)(read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + (machine->internal_state.IPOffset)))); machine->internal_state.IPOffset += 2; return V8086_OK; } @@ -184,28 +184,28 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 machine->internal_state.IPOffset += 1; switch(mod_rm & 7u){ case 0: - *offset = machine->regs.x.bx + machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.si + disp); return V8086_OK; case 1: - *offset = machine->regs.x.bx + machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.di + disp); return V8086_OK; case 2: - *offset = machine->regs.x.bp + machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.si + disp); return V8086_OK; case 3: - *offset = machine->regs.x.bp + machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.di + disp); return V8086_OK; case 4: - *offset = machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.si + disp); return V8086_OK; case 5: - *offset = machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.di + disp); return V8086_OK; case 6: - *offset = machine->regs.x.bp + disp; + *offset = (uint16_t)(machine->regs.x.bp + disp); return V8086_OK; case 7: - *offset = machine->regs.x.bx + disp; + *offset = (uint16_t)(machine->regs.x.bx + disp); return V8086_OK; default: return V8086_BAD_RM; @@ -216,28 +216,28 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 machine->internal_state.IPOffset += 2; switch(mod_rm & 7u){ case 0: - *offset = machine->regs.x.bx + machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.si + disp); return V8086_OK; case 1: - *offset = machine->regs.x.bx + machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.bx + machine->regs.x.di + disp); return V8086_OK; case 2: - *offset = machine->regs.x.bp + machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.si + disp); return V8086_OK; case 3: - *offset = machine->regs.x.bp + machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.bp + machine->regs.x.di + disp); return V8086_OK; case 4: - *offset = machine->regs.x.si + disp; + *offset = (uint16_t)(machine->regs.x.si + disp); return V8086_OK; case 5: - *offset = machine->regs.x.di + disp; + *offset = (uint16_t)(machine->regs.x.di + disp); return V8086_OK; case 6: - *offset = machine->regs.x.bp + disp; + *offset = (uint16_t)(machine->regs.x.bp + disp); return V8086_OK; case 7: - *offset = machine->regs.x.bx + disp; + *offset = (uint16_t)(machine->regs.x.bx + disp); return V8086_OK; default: return V8086_BAD_RM; @@ -249,7 +249,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 return V8086_UNKNOWN_ERROR; } -int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, uint32_t *offset) +int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t** segment, uint32_t *offset) { uint8_t sib = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; @@ -302,6 +302,7 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, break; case 4: *offset += machine->regs.d.esp; + *segment = select_segment_register(machine, V8086_SS); break; case 5: if (mod == 0) @@ -315,7 +316,7 @@ int16_t read_and_parse_sib(v8086* machine, uint8_t mod, const uint16_t* segment, else { *offset += machine->regs.d.ebp; - segment = select_segment_register(machine, V8086_SS); + *segment = select_segment_register(machine, V8086_SS); } break; case 6: @@ -353,7 +354,7 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.ebx; break; case 4: // SIB - read_and_parse_sib(machine, mod, segment_register, offset); + read_and_parse_sib(machine, mod, &segment_register, offset); break; case 5:{ uint32_t disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, @@ -391,7 +392,10 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.ebx + disp; break; case 4: // SIB - read_and_parse_sib(machine, mod, segment_register, offset); + machine->internal_state.IPOffset -= 1; + read_and_parse_sib(machine, mod, &segment_register, offset); + disp = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; *offset += disp; break; case 5:{ @@ -427,7 +431,10 @@ int16_t calculate_segment_offset_from_mode_32(v8086 *machine, uint8_t mod_rm, ui *offset = machine->regs.d.ebx + disp; break; case 4: // SIB - read_and_parse_sib(machine, mod, segment_register, offset); + machine->internal_state.IPOffset -= 4; + read_and_parse_sib(machine, mod, &segment_register, offset); + disp = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 4; *offset += disp; break; case 5:{ diff --git a/os/kernel/src/v8086/tests/tests.c b/os/kernel/src/v8086/tests/tests.c index 6c696869..39859507 100644 --- a/os/kernel/src/v8086/tests/tests.c +++ b/os/kernel/src/v8086/tests/tests.c @@ -101,6 +101,18 @@ void interactive_tests() serial_send(COM1_PORT, result >> 8); serial_send(COM1_PORT, result & 0xFF); } + else if(debug_operation == 14) + { + char x[20]; + for(long i = 0; i < 0x100000; i++) + { + machine->machine.Memory[i] = serial_receive(COM1_PORT); + if((i % 0x100) == 0){ + kernel_sprintf(x, "%x\n", i); + vga_printstring(x); + } + } + } else{ vga_printstring("Unknown byte: "); vga_printchar(debug_operation); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index c1343b82..dbb1987c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -63,7 +63,12 @@ void read_regs(union test_v8086* machine) { machine->machine.regs.d.edi = read_reg_32(); machine->machine.regs.d.esi = read_reg_32(); + machine->machine.regs.d.ebp = read_reg_32(); + //char x[100]; + //kernel_sprintf(x, "%x\n", read_reg_32()); + //kernel_sprintf(x, "%x\n", machine->machine.regs.d.ebp); + //vga_printstring(x); machine->machine.regs.d.cflag = read_reg_32(); machine->machine.regs.d.ebx = read_reg_32(); machine->machine.regs.d.edx = read_reg_32(); @@ -71,6 +76,8 @@ void read_regs(union test_v8086* machine) machine->machine.regs.d.eax = read_reg_32(); machine->machine.regs.d.eflags = read_reg_16(); machine->machine.regs.d.esp = read_reg_32(); + //kernel_sprintf(x, "%x\n", machine->machine.regs.d.esp); + //vga_printstring(x); } void read_sregs(union test_v8086* machine) @@ -87,7 +94,7 @@ uint16_t read_reg_16() { uint16_t value; value = (uint16_t)serial_receive(COM1_PORT); - value |= (uint16_t)serial_receive(COM1_PORT) << 8; + value |= ((uint16_t)serial_receive(COM1_PORT) & 0xFF) << 8; return value; } @@ -99,10 +106,10 @@ uint8_t read_reg_8() uint32_t read_reg_32() { uint32_t value; - value = (uint32_t)serial_receive(COM1_PORT); - value |= (uint32_t)serial_receive(COM1_PORT) << 8; - value |= (uint32_t)serial_receive(COM1_PORT) << 16; - value |= (uint32_t)serial_receive(COM1_PORT) << 24; + value = ((uint32_t)serial_receive(COM1_PORT) & 0xFF); + value |= ((uint32_t)serial_receive(COM1_PORT) & 0xFF) << 8; + value |= ((uint32_t)serial_receive(COM1_PORT) & 0xFF) << 16; + value |= ((uint32_t)serial_receive(COM1_PORT) & 0xFF) << 24; return value; } From 32831fcf8798438e91b89e5d40d8d7fcef08fe29 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Mon, 22 Feb 2021 02:42:33 +0100 Subject: [PATCH 110/165] Added VBE Return SVGA Information function --- .gitignore | 1 + debug.log | 94 ---------------- os/kernel/src/drivers/vbe/vbe.c | 81 ++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 29 +++++ os/kernel/src/kernel.c | 109 +++++-------------- os/kernel/src/v8086/tests/tests.c | 20 ++-- os/kernel/src/v8086/v8086.c | 172 +++++++++++++++--------------- os/kernel/src/v8086/v8086.h | 25 ++--- 8 files changed, 244 insertions(+), 287 deletions(-) delete mode 100644 debug.log create mode 100644 os/kernel/src/drivers/vbe/vbe.c create mode 100644 os/kernel/src/drivers/vbe/vbe.h diff --git a/.gitignore b/.gitignore index 3d832840..2b6aff02 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ cloc.bat .idea/vcs.xml .idea/MicrOS.iml .idea/misc.xml +debug.log diff --git a/debug.log b/debug.log deleted file mode 100644 index 4279fbfe..00000000 --- a/debug.log +++ /dev/null @@ -1,94 +0,0 @@ -SeaBIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) -BUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) binutils: version 2.27-43.base.el7_8.1 -No Xen hypervisor found. -Running on QEMU (i440fx) -Found QEMU fw_cfg -QEMU fw_cfg DMA interface supported -qemu/e820: addr 0x0000000000000000 len 0x0000000028000000 [RAM] -Relocating init from 0x000d4bf0 to 0x27fa9460 (size 92944) -Moving pm_base to 0x600 -=== PCI bus & bridge init === -PCI: pci_bios_init_bus_rec bus = 0x0 -=== PCI device probing === -Found 6 PCI devices (max PCI bus is 00) -=== PCI new allocation pass #1 === -PCI: check devices -=== PCI new allocation pass #2 === -PCI: IO: c000 - c04f -PCI: 32: 0000000080000000 - 00000000fec00000 -PCI: map device bdf=00:03.0 bar 1, addr 0000c000, size 00000040 [io] -PCI: map device bdf=00:01.1 bar 4, addr 0000c040, size 00000010 [io] -PCI: map device bdf=00:03.0 bar 6, addr feb80000, size 00040000 [mem] -PCI: map device bdf=00:03.0 bar 0, addr febc0000, size 00020000 [mem] -PCI: map device bdf=00:02.0 bar 6, addr febe0000, size 00010000 [mem] -PCI: map device bdf=00:02.0 bar 2, addr febf0000, size 00001000 [mem] -PCI: map device bdf=00:02.0 bar 0, addr fd000000, size 01000000 [prefmem] -PCI: init bdf=00:00.0 id=8086:1237 -PCI: init bdf=00:01.0 id=8086:7000 -PIIX3/PIIX4 init: elcr=00 0c -PCI: init bdf=00:01.1 id=8086:7010 -PCI: init bdf=00:01.3 id=8086:7113 -Using pmtimer, ioport 0x608 -PCI: init bdf=00:02.0 id=1234:1111 -PCI: init bdf=00:03.0 id=8086:100e -PCI: Using 00:02.0 for primary VGA -Found 1 cpu(s) max supported 1 cpu(s) -Copying PIR from 0x27fbfc8c to 0x000f5b90 -Copying MPTABLE from 0x00006d30/27fa03f0 to 0x000f5ab0 -Copying SMBIOS entry point from 0x00006d30 to 0x000f58f0 -table(50434146)=0x27fe1404 (via rsdt) -ACPI: parse DSDT at 0x27fe0040 (len 5060) -Scan for VGA option rom -Running option rom at c000:0003 -Start SeaVGABIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) -VGABUILD: gcc: (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) binutils: version 2.27-43.base.el7_8.1 -enter vga_post: - a=00000010 b=0000ffff c=00000000 d=0000ffff ds=0000 es=f000 ss=0000 - si=00000000 di=00005f60 bp=00000000 sp=00006ca6 cs=f000 ip=d07a f=0000 -VBE DISPI: bdf 00:02.0, bar 0 -VBE DISPI: lfb_addr=fd000000, size 16 MB -Attempting to allocate 512 bytes lowmem via pmm call to f000:d137 -pmm call arg1=0 -VGA stack allocated at eac40 -Turning on vga text mode console -set VGA mode 3 -SeaBIOS (version rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org) -Searching bootorder for: /pci@i0cf8/isa@1/fdc@03f0/floppy@0 -ATA controller 1 at 1f0/3f4/0 (irq 14 dev 9) -ATA controller 2 at 170/374/0 (irq 15 dev 9) -Searching bootorder for: HALT -Found 1 lpt ports -Found 1 serial ports -PS2 keyboard initialized -ata0-0: QEMU HARDDISK ATA-7 Hard-Disk (100 MiBytes) -Searching bootorder for: /pci@i0cf8/*@1,1/drive@0/disk@0 -Searching bios-geometry for: /pci@i0cf8/*@1,1/drive@0/disk@0 -DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] -Searching bootorder for: /pci@i0cf8/*@1,1/drive@1/disk@0 -Searching bios-geometry for: /pci@i0cf8/*@1,1/drive@1/disk@0 -Device reports MEDIUM NOT PRESENT -All threads complete. -Scan for option roms -Running option rom at ca00:0003 -pmm call arg1=1 -pmm call arg1=0 -pmm call arg1=1 -pmm call arg1=0 -Searching bootorder for: /pci@i0cf8/*@3 -Searching bootorder for: /rom@genroms/kvmvapic.bin -Searching bootorder for: HALT -drive 0x000f5830: PCHS=203/16/63 translation=large LCHS=203/16/63 s=204800 -Running option rom at cb00:0003 -Space available for UMB: cd800-ea000, f5410-f57d0 -Returned 131072 bytes of ZoneHigh -e820 map has 6 items: - 0: 0000000000000000 - 000000000009fc00 = 1 RAM - 1: 000000000009fc00 - 00000000000a0000 = 2 RESERVED - 2: 00000000000f0000 - 0000000000100000 = 2 RESERVED - 3: 0000000000100000 - 0000000027fe0000 = 1 RAM - 4: 0000000027fe0000 - 0000000028000000 = 2 RESERVED - 5: 00000000fffc0000 - 0000000100000000 = 2 RESERVED -enter handle_19: - NULL -Booting from Floppy... -Booting from 0000:7c00 diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c new file mode 100644 index 00000000..74ba3adc --- /dev/null +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -0,0 +1,81 @@ +#include "vbe.h" +#include "../v8086/v8086.h" +#include "../v8086/memory_operations.h" +#include +#include +#include "../memory/heap/heap.h" + +v8086* machine = NULL; +bool initialized = false; + +void VBE_initialize() +{ + if(!initialized) + { + machine = v8086_create_machine(); + if(machine == NULL) return; + v8086_set_386_instruction_set(machine); + initialized = true; + } +} + +void VBE_close() +{ + if(initialized) + { + v8086_destroy_machine(machine); + initialized = false; + } +} + +bool VBE_is_initialized() +{ + return initialized; +} + +VBEStatus VBE_check_existance_of_VESA() +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f03; + v8086_call_int(machine, 0x10); + if(machine->regs.x.ax != 0x004f) return VBE_NOT_EXIST; + return VBE_OK; +} + +VBEStatus VBE_get_svga_information(svga_information** information_struct_ptr){ + if(!initialized) return VBE_NO_INITAILIZED; + svga_information* information_struct = heap_kernel_alloc(sizeof(svga_information), 0); + if(information_struct == NULL) return VBE_INTERNAL_ERROR; + machine->regs.x.ax = 0x4f00; + machine->sregs.es = 0x0000; + machine->regs.x.di = 0x7E00; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *(uint32_t*)(information_struct->signature) = read_dword_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E00)); + information_struct->signature[5] = '\0'; + information_struct->vesa_standard_number = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E04)); + uint16_t off = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E06)); + uint16_t seg = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E08)); + uint16_t len = strlen(machine->Memory + get_absolute_address(seg, off)); + information_struct->producent_text = heap_kernel_alloc(len + 1, 0); + strcpy(information_struct->producent_text, machine->Memory + get_absolute_address(seg, off)); + information_struct->additional_info = read_dword_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E0A)); + off = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E0E)); + seg = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E10)); + for(len = 0; read_word_from_pointer(machine->Memory, get_absolute_address(seg, off + 2*len)) != 0xffff; ++len); + information_struct->number_of_modes = len; + information_struct->mode_array = heap_kernel_alloc(2 * len, 0); + memcpy(information_struct->mode_array, machine->Memory + get_absolute_address(seg, off), len * 2); + *information_struct_ptr = information_struct; + return VBE_OK; +} + +VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr) +{ + heap_kernel_dealloc(svga_information_ptr->mode_array); + heap_kernel_dealloc(svga_information_ptr->producent_text); + heap_kernel_dealloc(svga_information_ptr); + return VBE_OK; +} \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h new file mode 100644 index 00000000..8125c9b6 --- /dev/null +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -0,0 +1,29 @@ +#ifndef VBE_H +#define VBE_H + +#include +#include +#include + +typedef struct _svga_information{ + char signature[5]; + uint16_t vesa_standard_number; + char* producent_text; + uint32_t additional_info; + uint16_t* mode_array; + size_t number_of_modes; +} svga_information; + +typedef enum _VBEStatus{ + VBE_OK, VBE_NOT_EXIST, VBE_FUNCTION_FAILURE, VBE_NO_INITAILIZED, VBE_INTERNAL_ERROR +} VBEStatus; + + +void VBE_initialize(); +void VBE_close(); +bool VBE_is_initialized(); +VBEStatus VBE_check_existance_of_VESA(); +VBEStatus VBE_get_svga_information(svga_information** information_struct_ptr); +VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); + +#endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 77775d36..c02d1322 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -37,6 +37,7 @@ #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" #include "v8086/v8086.h" +#include "drivers/vbe/vbe.h" #ifdef TEST_V8086 #include "v8086/tests/tests.h" @@ -411,96 +412,42 @@ int kmain() switch_active_terminal(0); //process_manager_run(); - - union test_v8086* v8086 = v8086_create_machine(); - v8086_set_386_instruction_set(&(v8086->machine)); - - //filesystem_create_file("A:/DUMP.BIN"); - //bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->Memory + 0xC0000, 64*1024); - if(filesystem_is_file("A:/DUMP.BIN")) - filesystem_delete_file("A:/DUMP.BIN"); - - //if(filesystem_is_file("A:/SEG0x40.BIN")) - // filesystem_delete_file("A:/SEG0x40.BIN"); - - filesystem_create_file("A:/DUMP.BIN"); - bool dupa = filesystem_save_to_file("A:/DUMP.BIN", (char*) v8086->machine.Memory + 0xC0000, 64*1024); - - //filesystem_create_file("A:/SEG0x40.BIN"); - //dupa = filesystem_save_to_file("A:/SEG0x40.BIN", (char*) v8086->Memory + 0x400, 64*1024); - - serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); keyboard_scan_ascii_pair kb; vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); while(!keyboard_get_key_from_buffer(&kb)); - /*for(long long i = 0; i < 1024*1024; i++) - { - serial_send(COM1_PORT, *((char*) v8086->Memory + i)); - }*/ - - //if(filesystem_is_file("A:/CSIP.BIN")) { - //filesystem_delete_file("A:/CSIP.BIN"); - //} - - //filesystem_create_file("A:/CSIP.BIN"); - - //void (*ptr)() = (void*)(v8086_get_address_of_int(v8086, 0x10) + v8086->Memory); - - #ifdef TEST_V8086 - //test_mod_16(); - //interactive_tests(); - #endif - - //v8086->machine.regs.h.ah = 0x00; - //v8086->machine.regs.h.al = 0x13; - //v8086->machine.regs.h.al = 0x6a; - - v8086->machine.regs.x.ax = 0x4f03; - int16_t status = v8086_call_int(v8086, 0x10); - char str[100] = ""; - if(v8086->machine.regs.x.ax == 0x004f) + char buff[100]; + VBE_initialize(); + VBEStatus status = VBE_check_existance_of_VESA(); + if(status != VBE_OK) { - itoa(v8086->machine.regs.x.bx, str, 16); - vga_printstring(str); + vga_printstring("Problems with VBE: \n"); + vga_printstring(itoa(status, buff, 10)); vga_newline(); } + svga_information* svga_info_ptr; + status = VBE_get_svga_information(&svga_info_ptr); + if(status == VBE_OK){ + vga_printstring(svga_info_ptr->signature); + vga_newline(); + vga_printstring(svga_info_ptr->producent_text); + vga_newline(); + itoa(svga_info_ptr->vesa_standard_number, buff, 16); + vga_printstring(buff); + vga_newline(); + itoa(svga_info_ptr->number_of_modes, buff, 10); + vga_printstring(buff); + vga_newline(); + for(int i=0; i < svga_info_ptr->number_of_modes; i++) + { + itoa(svga_info_ptr->mode_array[i], buff, 16); + vga_printstring(buff); + vga_printstring(", "); + } + } else{ - vga_printstring("DUPA!"); + vga_printstring("DUPA\n"); } - - v8086->machine.regs.x.ax = 0x4f02; - v8086->machine.regs.x.bx = 0x11b; - status = v8086_call_int(v8086, 0x10); - - //mode13h_set_mode(); - //mode13h_clear_screen(); - drawLenaIn13H(); - - /*char str[100] = ""; - itoa(status, str, 16); - vga_printstring(str); - vga_newline(); - vga_printstring("IP: "); - uint16_t IP = *(uint16_t*)(v8086->machine.Memory + 0x10 * 4); - uint16_t CS = *(uint16_t*)(v8086->machine.Memory + 0x10 * 4 + 2); - vga_newline(); - itoa(IP, str, 16); - vga_printstring(str); - vga_newline(); - vga_printstring("CS: "); - itoa(CS, str, 16); - vga_printstring(str); - vga_newline(); - for(uint32_t i = CS * 16 + IP; i < (CS * 16 + IP + 16); i++) - { - uint8_t mem = v8086->machine.Memory[i]; - itoa(mem, str, 16); - vga_printstring(str); - vga_printstring(" "); - }*/ - - while (1); return 0; } diff --git a/os/kernel/src/v8086/tests/tests.c b/os/kernel/src/v8086/tests/tests.c index 39859507..39645df5 100644 --- a/os/kernel/src/v8086/tests/tests.c +++ b/os/kernel/src/v8086/tests/tests.c @@ -12,7 +12,7 @@ void interactive_tests() { - union test_v8086* machine = v8086_create_machine(); + v8086* machine = v8086_create_machine(); while(true) { char d[100]; @@ -36,7 +36,7 @@ void interactive_tests() uint16_t off; seg = read_reg_16(); off = read_reg_16(); - uint8_t mem = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint8_t mem = read_byte_from_pointer(machine->Memory, get_absolute_address(seg, off)); serial_send(COM1_PORT, mem); } else if(debug_operation == 4) // READ WORD @@ -45,7 +45,7 @@ void interactive_tests() uint16_t off; seg = read_reg_16(); off = read_reg_16(); - uint16_t mem = read_word_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint16_t mem = read_word_from_pointer(machine->Memory, get_absolute_address(seg, off)); send_reg_16(mem); } else if(debug_operation == 5) // READ DWORD @@ -54,27 +54,27 @@ void interactive_tests() uint16_t off; seg = read_reg_16(); off = read_reg_16(); - uint32_t mem = read_dword_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint32_t mem = read_dword_from_pointer(machine->Memory, get_absolute_address(seg, off)); send_reg_32(mem); } else if(debug_operation == 6) // GET IP { - send_reg_16(machine->machine.IP.w.ip); + send_reg_16(machine->IP.w.ip); } else if(debug_operation == 7) // READ MEM { for(int i = 0; i < 0x100000; i++) - serial_send(COM1_PORT,machine->machine.Memory[i]); + serial_send(COM1_PORT,machine->Memory[i]); } else if(debug_operation == 8) // READ SEG { uint16_t seg = read_reg_16(); for(int i = 0; i < 64 * 1024; i++) - serial_send(COM1_PORT,machine->machine.Memory[seg * 0x10 + i]); + serial_send(COM1_PORT,machine->Memory[seg * 0x10 + i]); } else if(debug_operation == 9) { - machine->machine.IP.w.ip = read_reg_16(); + machine->IP.w.ip = read_reg_16(); } else if(debug_operation == 10) { @@ -92,7 +92,7 @@ void interactive_tests() uint32_t addr = seg * 0x10 + off; for(int i = addr; i < addr + length; i++) { - machine->machine.Memory[i] = serial_receive(COM1_PORT); + machine->Memory[i] = serial_receive(COM1_PORT); } } else if(debug_operation == 13) @@ -106,7 +106,7 @@ void interactive_tests() char x[20]; for(long i = 0; i < 0x100000; i++) { - machine->machine.Memory[i] = serial_receive(COM1_PORT); + machine->Memory[i] = serial_receive(COM1_PORT); if((i % 0x100) == 0){ kernel_sprintf(x, "%x\n", i); vga_printstring(x); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index dbb1987c..94d27353 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -20,7 +20,7 @@ //#define DEBUG_V8086_INTERACTIVE #endif -int16_t parse_and_execute_instruction(union test_v8086* machine); +int16_t parse_and_execute_instruction(v8086* machine); #ifdef DEBUG_V8086 void send_reg_32(uint32_t reg) @@ -35,59 +35,59 @@ void send_reg_16(uint16_t reg) serial_send(COM1_PORT, ((reg) >> (i*8)) & 0xff); } -void send_regs(union test_v8086* machine) +void send_regs(v8086* machine) { - send_reg_32(machine->machine.regs.d.edi); - send_reg_32(machine->machine.regs.d.esi); - send_reg_32(machine->machine.regs.d.ebp); - send_reg_32(machine->machine.regs.d.cflag); - send_reg_32(machine->machine.regs.d.ebx); - send_reg_32(machine->machine.regs.d.edx); - send_reg_32(machine->machine.regs.d.ecx); - send_reg_32(machine->machine.regs.d.eax); - send_reg_16(machine->machine.regs.d.eflags); - send_reg_32(machine->machine.regs.d.esp); + send_reg_32(machine->regs.d.edi); + send_reg_32(machine->regs.d.esi); + send_reg_32(machine->regs.d.ebp); + send_reg_32(machine->regs.d.cflag); + send_reg_32(machine->regs.d.ebx); + send_reg_32(machine->regs.d.edx); + send_reg_32(machine->regs.d.ecx); + send_reg_32(machine->regs.d.eax); + send_reg_16(machine->regs.d.eflags); + send_reg_32(machine->regs.d.esp); } -void send_sregs(union test_v8086* machine) +void send_sregs(v8086* machine) { - send_reg_16(machine->machine.sregs.es); - send_reg_16(machine->machine.sregs.ds); - send_reg_16(machine->machine.sregs.fs); - send_reg_16(machine->machine.sregs.gs); - send_reg_16(machine->machine.sregs.cs); - send_reg_16(machine->machine.sregs.ss); + send_reg_16(machine->sregs.es); + send_reg_16(machine->sregs.ds); + send_reg_16(machine->sregs.fs); + send_reg_16(machine->sregs.gs); + send_reg_16(machine->sregs.cs); + send_reg_16(machine->sregs.ss); } -void read_regs(union test_v8086* machine) +void read_regs(v8086* machine) { - machine->machine.regs.d.edi = read_reg_32(); - machine->machine.regs.d.esi = read_reg_32(); + machine->regs.d.edi = read_reg_32(); + machine->regs.d.esi = read_reg_32(); - machine->machine.regs.d.ebp = read_reg_32(); + machine->regs.d.ebp = read_reg_32(); //char x[100]; //kernel_sprintf(x, "%x\n", read_reg_32()); - //kernel_sprintf(x, "%x\n", machine->machine.regs.d.ebp); + //kernel_sprintf(x, "%x\n", machine->regs.d.ebp); //vga_printstring(x); - machine->machine.regs.d.cflag = read_reg_32(); - machine->machine.regs.d.ebx = read_reg_32(); - machine->machine.regs.d.edx = read_reg_32(); - machine->machine.regs.d.ecx = read_reg_32(); - machine->machine.regs.d.eax = read_reg_32(); - machine->machine.regs.d.eflags = read_reg_16(); - machine->machine.regs.d.esp = read_reg_32(); - //kernel_sprintf(x, "%x\n", machine->machine.regs.d.esp); + machine->regs.d.cflag = read_reg_32(); + machine->regs.d.ebx = read_reg_32(); + machine->regs.d.edx = read_reg_32(); + machine->regs.d.ecx = read_reg_32(); + machine->regs.d.eax = read_reg_32(); + machine->regs.d.eflags = read_reg_16(); + machine->regs.d.esp = read_reg_32(); + //kernel_sprintf(x, "%x\n", machine->regs.d.esp); //vga_printstring(x); } -void read_sregs(union test_v8086* machine) +void read_sregs(v8086* machine) { - machine->machine.sregs.es = read_reg_16(); - machine->machine.sregs.ds = read_reg_16(); - machine->machine.sregs.fs = read_reg_16(); - machine->machine.sregs.gs = read_reg_16(); - machine->machine.sregs.cs = read_reg_16(); - machine->machine.sregs.ss = read_reg_16(); + machine->sregs.es = read_reg_16(); + machine->sregs.ds = read_reg_16(); + machine->sregs.fs = read_reg_16(); + machine->sregs.gs = read_reg_16(); + machine->sregs.cs = read_reg_16(); + machine->sregs.ss = read_reg_16(); } uint16_t read_reg_16() @@ -339,30 +339,30 @@ void v8086_set_386_instruction_set(v8086* machine) machine->is_compatibility = V8086_IS386; } -union test_v8086* v8086_create_machine() +v8086* v8086_create_machine() { - union test_v8086* machine = (union test_v8086*) heap_kernel_alloc(sizeof(union test_v8086), 0); + v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); if(machine == NULL) return NULL; - memset(machine, 0, sizeof(union test_v8086)); - machine->machine.regs.x.flags = 0x2; - machine->machine.sregs.cs = 0xf000; - machine->machine.IP.w.ip = 0xfff0; - machine->machine.sregs.ss = 0x0; - machine->machine.regs.d.ebp = 0x7bff; - machine->machine.regs.d.esp = 0x7bff; - memcpy(machine->machine.Memory, (void*)0xc0000000, 0x100000); + memset(machine, 0, sizeof(v8086)); + machine->regs.x.flags = 0x2; + machine->sregs.cs = 0xf000; + machine->IP.w.ip = 0xfff0; + machine->sregs.ss = 0x0; + machine->regs.d.ebp = 0x7bff; + machine->regs.d.esp = 0x7bff; + memcpy(machine->Memory, (void*)0xc0000000, 0x100000); v8086_set_8086_instruction_set(machine); return machine; } -void v8086_destroy_machine(union test_v8086* machine) +void v8086_destroy_machine(v8086* machine) { heap_kernel_dealloc(machine); } -int16_t v8086_call_function(union test_v8086* machine) +int16_t v8086_call_function(v8086* machine) { - while(!(machine->machine.IP.w.ip == 0xFFFF && machine->machine.sregs.cs == 0xFFFF)) + while(!(machine->IP.w.ip == 0xFFFF && machine->sregs.cs == 0xFFFF)) { int16_t status = parse_and_execute_instruction(machine); if(status != V8086_OK) return status; @@ -370,12 +370,12 @@ int16_t v8086_call_function(union test_v8086* machine) return V8086_OK; } -int16_t v8086_call_int(union test_v8086* machine, int16_t num) +int16_t v8086_call_int(v8086* machine, int16_t num) { if ((num < 0) || (num > 0xFF)) return V8086_BAD_INT_NUMBER; - machine -> machine. IP.w.ip = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4)); - machine -> machine. sregs.cs = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4 + 2)); - push_word(machine, machine->machine.regs.w.flags); + machine->IP.w.ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); + machine->sregs.cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); + push_word(machine, machine->regs.w.flags); push_word(machine, 0xFFFF); push_word(machine, 0xFFFF); int16_t x = v8086_call_function(machine); @@ -383,20 +383,20 @@ int16_t v8086_call_int(union test_v8086* machine, int16_t num) return num; } -uint32_t v8086_get_address_of_int(union test_v8086* machine, int16_t num) +uint32_t v8086_get_address_of_int(v8086* machine, int16_t num) { - uint32_t ip = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4)); - uint32_t cs = read_word_from_pointer(machine->machine.Memory, get_absolute_address(0, num * 4 + 2)); + uint32_t ip = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4)); + uint32_t cs = read_word_from_pointer(machine->Memory, get_absolute_address(0, num * 4 + 2)); return cs * 0x10 + ip; } -int16_t parse_and_execute_instruction(union test_v8086* machine) +int16_t parse_and_execute_instruction(v8086* machine) { - machine->machine.internal_state.IPOffset = 0; - machine->machine.internal_state.operand_32_bit = 0; - machine->machine.internal_state.address_32_bit = 0; - machine->machine.internal_state.segment_reg_select = V8086_DEFAULT; - machine->machine.internal_state.rep_prefix = V8086_NONE_REPEAT; + machine->internal_state.IPOffset = 0; + machine->internal_state.operand_32_bit = 0; + machine->internal_state.address_32_bit = 0; + machine->internal_state.segment_reg_select = V8086_DEFAULT; + machine->internal_state.rep_prefix = V8086_NONE_REPEAT; int16_t status = V8086_OK; @@ -467,7 +467,7 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) #endif #ifdef DEBUG_V8086_BIN - for(uint32_t i = 0; i < sizeof(union test_v8086); i++) + for(uint32_t i = 0; i < sizeof(v8086); i++) { serial_send(COM1_PORT, machine->bytes[i]); } @@ -499,7 +499,7 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) seg |= serial_receive(COM1_PORT); off = (uint16_t)serial_receive(COM1_PORT) << 8; off |= serial_receive(COM1_PORT); - uint8_t mem = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint8_t mem = read_byte_from_pointer(machine->Memory, get_absolute_address(seg, off)); serial_send(COM1_PORT, mem); } else if(debug_operation == 4) @@ -510,7 +510,7 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) seg |= serial_receive(COM1_PORT); off = (uint16_t)serial_receive(COM1_PORT) << 8; off |= serial_receive(COM1_PORT); - uint16_t mem = read_word_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint16_t mem = read_word_from_pointer(machine->Memory, get_absolute_address(seg, off)); send_reg_16(mem); } else if(debug_operation == 5) @@ -521,17 +521,17 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) seg |= serial_receive(COM1_PORT); off = (uint16_t)serial_receive(COM1_PORT) << 8; off |= serial_receive(COM1_PORT); - uint32_t mem = read_dword_from_pointer(machine->machine.Memory, get_absolute_address(seg, off)); + uint32_t mem = read_dword_from_pointer(machine->Memory, get_absolute_address(seg, off)); send_reg_32(mem); } else if(debug_operation == 6) { - send_reg_16(machine->machine.IP.w.ip); + send_reg_16(machine->IP.w.ip); } else if(debug_operation == 7) { for(int i = 0; i < 0x100000; i++) - serial_send(COM1_PORT,machine->machine.Memory[i]); + serial_send(COM1_PORT,machine->Memory[i]); } else if(debug_operation == 8) { @@ -539,7 +539,7 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) seg = (uint16_t)serial_receive(COM1_PORT) << 8; seg |= serial_receive(COM1_PORT); for(int i = 0; i < 64 * 1024; i++) - serial_send(COM1_PORT,machine->machine.Memory[seg * 0x10 + i]); + serial_send(COM1_PORT,machine->Memory[seg * 0x10 + i]); } else{ vga_printstring("Unknown byte: "); @@ -552,10 +552,10 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) //Maybe opcode, an be also prefix uint8_t opcode; - decode: opcode = read_byte_from_pointer(machine->machine.Memory, get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset)); - uint32_t temp = get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset); - uint8_t* ptr_to_opcode = get_byte_pointer(machine->machine.Memory, get_absolute_address(machine->machine.sregs.cs, machine->machine.IP.w.ip + machine->machine.internal_state.IPOffset)); - machine->machine.internal_state.IPOffset += 1; + decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); + uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + machine->internal_state.IPOffset += 1; /*char str[5] = ""; @@ -571,43 +571,43 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) //Segment Prefix V8086_CS DS V8086_ES SS if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment { - machine->machine.internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; + machine->internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; goto decode; //continue parsing opcode; } //Segment Prefix FS else if(opcode == 0x64) { - machine->machine.internal_state.segment_reg_select = V8086_FS; + machine->internal_state.segment_reg_select = V8086_FS; goto decode; //continue parsing opcode; } //Segment Prefix GS else if(opcode == 0x65) { - machine->machine.internal_state.segment_reg_select = V8086_GS; + machine->internal_state.segment_reg_select = V8086_GS; goto decode; //continue parsing opcode; } //Operand Size Prefix else if(opcode == 0x66) { - machine->machine.internal_state.operand_32_bit = 1; + machine->internal_state.operand_32_bit = 1; goto decode; //continue parsing opcode; } //Address Szie Prefix else if(opcode == 0x67) { - machine->machine.internal_state.address_32_bit = 1; + machine->internal_state.address_32_bit = 1; goto decode; } //REPNE Prefix else if(opcode == 0xF2) { - machine->machine.internal_state.rep_prefix = V8086_REPNE; + machine->internal_state.rep_prefix = V8086_REPNE; goto decode; //continue parsing opcode; } //REP/REPE Prefix else if(opcode == 0xF3) { - machine->machine.internal_state.rep_prefix = V8086_REP_REPE; + machine->internal_state.rep_prefix = V8086_REP_REPE; goto decode; //continue parsing opcode; } //LOCK Prefix @@ -616,12 +616,12 @@ int16_t parse_and_execute_instruction(union test_v8086* machine) goto decode; //ommit prefix, contniue parsinf opcode; } - if(machine->machine.operations[opcode] != NULL) - status = machine->machine.operations[opcode](&(machine->machine), opcode); + if(machine->operations[opcode] != NULL) + status = machine->operations[opcode](machine, opcode); else return V8086_UNDEFINED_OPCODE; - machine->machine.IP.w.ip += machine->machine.internal_state.IPOffset; + machine->IP.w.ip += machine->internal_state.IPOffset; #ifdef DEBUG_V8086 #ifdef DEBUG_V8086_TEXT serial_send_string(COM1_PORT, "------------------------------------------\n"); diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index c8f4a71e..0b05dd82 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -160,30 +160,23 @@ typedef struct _v8086 }__attribute__((packed)) v8086; -union test_v8086 -{ - struct _v8086 machine; - uint8_t bytes[sizeof(struct _v8086)]; -}; - - -union test_v8086* v8086_create_machine(); -void v8086_destroy_machine(union test_v8086* machine); -int16_t v8086_call_int(union test_v8086* machine, int16_t num); +v8086* v8086_create_machine(); +void v8086_destroy_machine(v8086* machine); +int16_t v8086_call_int(v8086* machine, int16_t num); void v8086_set_8086_instruction_set(v8086* machine); void v8086_set_386_instruction_set(v8086* machine); -uint32_t v8086_get_address_of_int(union test_v8086* machine, int16_t num); +uint32_t v8086_get_address_of_int(v8086* machine, int16_t num); #ifdef DEBUG_V8086 void send_reg_32(uint32_t reg); void send_reg_16(uint16_t reg); - void send_regs(union test_v8086* machine); - void send_sregs(union test_v8086* machine); - int16_t parse_and_execute_instruction(union test_v8086* machine); + void send_regs(v8086* machine); + void send_sregs(v8086* machine); + int16_t parse_and_execute_instruction(v8086* machine); uint8_t read_reg_8(); uint16_t read_reg_16(); uint32_t read_reg_32(); - void read_regs(union test_v8086* machine); - void read_sregs(union test_v8086* machine); + void read_regs(v8086* machine); + void read_sregs(v8086* machine); #endif #endif \ No newline at end of file From ad3ca2ad54100c85292562d77865d9529546244c Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 16 Mar 2021 00:22:20 +0100 Subject: [PATCH 111/165] Corrected next Errors --- os/kernel/src/drivers/vbe/vbe.c | 35 ++++++++++ os/kernel/src/drivers/vbe/vbe.h | 24 +++++++ os/kernel/src/kernel.c | 58 +++++++++++++-- .../v8086/operations/arithmetic_operations.c | 70 ++++++++++++++----- .../src/v8086/operations/mov_operations.c | 26 +++---- 5 files changed, 179 insertions(+), 34 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 74ba3adc..491106c8 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -72,6 +72,41 @@ VBEStatus VBE_get_svga_information(svga_information** information_struct_ptr){ return VBE_OK; } +VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struct, uint16_t mode_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f01; + machine->regs.x.cx = mode_number; + machine->sregs.es = 0x0000; + machine->regs.x.di = 0x7E00; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + infromation_struct->mode_attributes = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E00)); + infromation_struct->window_a_attributes = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E02)); + infromation_struct->window_b_attributes = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E03)); + infromation_struct->granularity = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E04)); + infromation_struct->windows_size = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E06)); + infromation_struct->segment_of_window_a = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E08)); + infromation_struct->segment_of_window_b = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E0A)); + infromation_struct->far_pointer_to_bank_swap_function = read_dword_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E0C)); + infromation_struct->logical_line_length = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E10)); + infromation_struct->mode_width = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E12)); + infromation_struct->mode_height = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E14)); + infromation_struct->char_matrix_width = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E16)); + infromation_struct->char_matrix_height = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E17)); + infromation_struct->plane_count = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E18)); + infromation_struct->bits_per_pixel = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E19)); + infromation_struct->bank_count = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1A)); + infromation_struct->memory_organization = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1B)); + infromation_struct->bank_size = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1C)); + infromation_struct->page_count = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1D)); + infromation_struct->reserved = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1E)); + + return VBE_OK; +} + VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr) { heap_kernel_dealloc(svga_information_ptr->mode_array); diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 8125c9b6..5a116412 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -14,6 +14,29 @@ typedef struct _svga_information{ size_t number_of_modes; } svga_information; +typedef struct _svga_mode_information{ + uint16_t mode_attributes; + uint8_t window_a_attributes; + uint8_t window_b_attributes; + uint16_t granularity; + uint16_t windows_size; + uint16_t segment_of_window_a; + uint16_t segment_of_window_b; + uint32_t far_pointer_to_bank_swap_function; + uint16_t logical_line_length; + uint16_t mode_width; + uint16_t mode_height; + uint8_t char_matrix_width; + uint8_t char_matrix_height; + uint8_t plane_count; + uint8_t bits_per_pixel; + uint8_t bank_count; + uint8_t memory_organization; + uint8_t bank_size; + uint8_t page_count; + uint8_t reserved; +} svga_mode_information; + typedef enum _VBEStatus{ VBE_OK, VBE_NOT_EXIST, VBE_FUNCTION_FAILURE, VBE_NO_INITAILIZED, VBE_INTERNAL_ERROR } VBEStatus; @@ -24,6 +47,7 @@ void VBE_close(); bool VBE_is_initialized(); VBEStatus VBE_check_existance_of_VESA(); VBEStatus VBE_get_svga_information(svga_information** information_struct_ptr); +VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struct, uint16_t mode_number); VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); #endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index c02d1322..ed122f5b 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -416,9 +416,14 @@ int kmain() vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); while(!keyboard_get_key_from_buffer(&kb)); + serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); + char buff[100]; VBE_initialize(); - VBEStatus status = VBE_check_existance_of_VESA(); + + //svga_mode_information mode_info; + //VBE_get_vesa_mode_information(&mode_info, 0x105); + /*VBEStatus status = VBE_check_existance_of_VESA(); if(status != VBE_OK) { vga_printstring("Problems with VBE: \n"); @@ -432,22 +437,63 @@ int kmain() vga_newline(); vga_printstring(svga_info_ptr->producent_text); vga_newline(); + vga_printstring("VESA VERSION: "); itoa(svga_info_ptr->vesa_standard_number, buff, 16); vga_printstring(buff); vga_newline(); + vga_printstring("VESA NUMBER OF MODES: "); itoa(svga_info_ptr->number_of_modes, buff, 10); vga_printstring(buff); vga_newline(); + uint16_t mode_number = 0; + uint32_t max_width = 0; + uint32_t max_height = 0; + uint16_t max_bit_per_pixel = 0; for(int i=0; i < svga_info_ptr->number_of_modes; i++) + //for(int i=0x11b; i < 0x11c; i++) { - itoa(svga_info_ptr->mode_array[i], buff, 16); - vga_printstring(buff); - vga_printstring(", "); + svga_mode_information mode_info; + status = VBE_get_vesa_mode_information(&mode_info, svga_info_ptr->mode_array[i]); + if(status != VBE_OK){ + itoa(svga_info_ptr->mode_array[i], buff, 16); + vga_printstring("Unable to get SVGA MODE INFORMATION: "); + vga_printstring(buff); + vga_newline(); + while(!keyboard_get_key_from_buffer(&kb)); + } + else{ + if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) + { + if(max_bit_per_pixel <= mode_info.bits_per_pixel){ + mode_number = svga_info_ptr->mode_array[i]; + max_width = mode_info.mode_width; + max_height = mode_info.mode_height; + max_bit_per_pixel = mode_info.bits_per_pixel; + } + } + } } + vga_printstring("BEST MODE: "); + itoa(mode_number, buff, 16); + vga_printstring(buff); + vga_newline(); + vga_printstring("MAX WIDTH: "); + itoa(max_width, buff, 10); + vga_printstring(buff); + vga_newline(); + vga_printstring("MAX HEIGHT: "); + itoa(max_height, buff, 10); + vga_printstring(buff); + vga_newline(); + vga_printstring("BITS PER COLOR: "); + itoa(max_bit_per_pixel, buff, 10); + vga_printstring(buff); + vga_newline(); + } else{ - vga_printstring("DUPA\n"); - } + vga_printstring("Unable to get SVGA INFORMATION\n"); + }*/ while (1); return 0; } diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index fde7f670..bdcae0e0 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -358,7 +358,7 @@ perform_multiplication_3_byte(v8086 *machine, void *dest, void *source, void *im } else if (second_width == 32) { int32_t a_imm = *((int32_t *) imm); __asm__ __volatile__( - "imul %%cx, %%dx; pushfw; pop %%bx;" + "imul %%ecx, %%edx; pushfw; pop %%bx;" : "=b" (temp_flags), "=d" (*((uint32_t *) dest)) : "d" (*((uint32_t *) source)), "c" (a_imm) ); } else return V8086_BAD_WIDTH; @@ -373,20 +373,23 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 uint16_t temp_flags; if (signed_div) { if (width == 8) { - if(*((int8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((int8_t *) source) == 0) + return V8086_DIVISION_BY_ZERO; int16_t temp = (int16_t) machine->regs.w.ax / *((int8_t *) source); if((temp > (int8_t)0x7f) || (temp < (int8_t)0x80)) return V8086_DIVISION_OVERFLOW; machine->regs.h.al = temp; machine->regs.h.ah = (int16_t) machine->regs.w.ax % *((int8_t *) source); } else if (width == 16) { - if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((uint16_t *) source) == 0) + return V8086_DIVISION_BY_ZERO; int32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; int32_t temp = dividend / *((int16_t *) source); if((temp > (int16_t)0x7fff) || (temp < (int16_t)0x8000)) return V8086_DIVISION_OVERFLOW; machine->regs.x.ax = temp; machine->regs.x.dx = dividend % *((int16_t *) source); } else if (width == 32) { - if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((uint32_t *) source) == 0) + return V8086_DIVISION_BY_ZERO; int64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; int64_t temp = dividend / *((int32_t *) source); if((temp > (int32_t)0x7fffffff) || (temp < (int32_t)0x80000000)) return V8086_DIVISION_OVERFLOW; @@ -395,20 +398,25 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 } else return V8086_BAD_WIDTH; } else { if (width == 8) { - if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((uint8_t *) source) == 0) + return V8086_DIVISION_BY_ZERO; uint16_t temp = machine->regs.w.ax / *((uint8_t *) source); if(temp > 0xff) return V8086_DIVISION_OVERFLOW; machine->regs.h.al = temp; machine->regs.h.ah = machine->regs.w.ax % *((uint8_t *) source); } else if (width == 16) { - if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((uint16_t *) source) == 0) + return V8086_DIVISION_BY_ZERO; uint32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; uint32_t temp = dividend / *((uint16_t *) source); if(temp > 0xffff) return V8086_DIVISION_OVERFLOW; machine->regs.x.ax = temp; machine->regs.x.dx = dividend % *((uint16_t *) source); } else if (width == 32) { - if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; + if(*((uint32_t *) source) == 0) { + + return V8086_DIVISION_BY_ZERO; + } uint64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; uint64_t temp = dividend / *((uint32_t *) source); if(temp > 0xffffffff) return V8086_DIVISION_OVERFLOW; @@ -438,7 +446,22 @@ int16_t perform_test(v8086 *machine, void *source, void *dest, uint8_t width) { } int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { - uint64_t result = 0; + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("incb %%al; pushfw; pop %%bx;" : "=a" (*((uint8_t *) dest)), "=b" (temp_flags) : "a" (*((uint8_t *) dest))); + else if (width == 16) + __asm__ __volatile__("incw %%ax; pushfw; pop %%bx;" : "=a" (*((uint16_t *) dest)), "=b" (temp_flags) : "a" (*((uint16_t *) dest))); + else if (width == 32) + __asm__ __volatile__("incl %%eax; pushfw; pop %%bx;" : "=a" (*((uint32_t *) dest)), "=b" (temp_flags) : "a" (*((uint32_t *) dest))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); + return V8086_OK; + /*uint64_t result = 0; uint32_t dest_before; if (width == 8) dest_before = *((uint8_t *) dest); @@ -461,11 +484,26 @@ int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return V8086_OK; + return V8086_OK;*/ } int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { - uint64_t result = 0; + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("decb %%al; pushfw; pop %%bx;" : "=a" (*((uint8_t *) dest)), "=b" (temp_flags) : "a" (*((uint8_t *) dest))); + else if (width == 16) + __asm__ __volatile__("decw %%ax; pushfw; pop %%bx;" : "=a" (*((uint16_t *) dest)), "=b" (temp_flags) : "a" (*((uint16_t *) dest))); + else if (width == 32) + __asm__ __volatile__("decl %%eax; pushfw; pop %%bx;" : "=a" (*((uint32_t *) dest)), "=b" (temp_flags) : "a" (*((uint32_t *) dest))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); + return V8086_OK; + /*uint64_t result = 0; uint32_t dest_before; if (width == 8) dest_before = *((uint8_t *) dest); @@ -488,7 +526,7 @@ int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { if (width == 8) *((uint8_t *) dest) = result & 0xFFu; else if (width == 16) *((uint16_t *) dest) = result & 0xFFFFu; else if (width == 32) *((uint32_t *) dest) = result & 0xFFFFFFFF; - return V8086_OK; + return V8086_OK;*/ } int16_t perform_artihmetic_or_logical_instruction(v8086 *machine, uint8_t recalculated_opcode, uint32_t carry, @@ -574,29 +612,29 @@ int16_t perform_arithmetic_or_logical_instruction_group(v8086 *machine, uint8_t machine->internal_state.IPOffset += 1; break; case 1: //OPERATION rm16, imm16 or rm32, imm32 + width = machine->internal_state.operand_32_bit ? 32 : 16; + dest = get_memory_from_mode(machine, mod_rm, width); if (machine->internal_state.operand_32_bit) { - width = 32; immediate = read_dword_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 4; } else { - width = 16; immediate = read_word_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 2; } - dest = get_memory_from_mode(machine, mod_rm, width); + break; case 3: //OPERATION rm16, imm8, or rm32, imm8 if (machine->internal_state.operand_32_bit) width = 32; else width = 16; - signed_immediate = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, + dest = get_memory_from_mode(machine, mod_rm, width); + signed_immediate = (int8_t)read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - dest = get_memory_from_mode(machine, mod_rm, width); break; default: return V8086_UNDEFINED_RECALCULATED_OPCODE; diff --git a/os/kernel/src/v8086/operations/mov_operations.c b/os/kernel/src/v8086/operations/mov_operations.c index 8004d0cb..c4ecd18c 100644 --- a/os/kernel/src/v8086/operations/mov_operations.c +++ b/os/kernel/src/v8086/operations/mov_operations.c @@ -5,7 +5,7 @@ #include "mov_operations.h" #include "internal_funcs.h" -int16_t perform_mov(v8086* machine, void* source, void* dest, uint8_t width) { +int16_t perform_mov(v8086* machine, void* source, void* dest, uint8_t width, uint8_t flags_affected) { switch (width) { case 8: *((uint8_t *) dest) = *((uint8_t *) source); @@ -20,12 +20,14 @@ int16_t perform_mov(v8086* machine, void* source, void* dest, uint8_t width) { return V8086_BAD_WIDTH; } - bit_clear(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT); - bit_clear(machine->regs.w.flags, 1u << CARRY_FLAG_BIT); - bit_clear(machine->regs.w.flags, 1u << SIGN_FLAG_BIT); - bit_clear(machine->regs.w.flags, 1u << ZERO_FLAG_BIT); - bit_clear(machine->regs.w.flags, 1u << PARITY_FLAG_BIT); - bit_clear(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT); + if(flags_affected){ + bit_clear(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << CARRY_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << SIGN_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << ZERO_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << PARITY_FLAG_BIT); + bit_clear(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT); + } return V8086_OK; } @@ -46,10 +48,10 @@ int16_t perform_mov_rm(v8086* machine, uint8_t opcode) { case 0x88: case 0x89: - return perform_mov(machine, source, dest, width); + return perform_mov(machine, source, dest, width, 0); case 0x8a: case 0x8b: - return perform_mov(machine, dest, source, width); + return perform_mov(machine, dest, source, width, 0); default: return V8086_UNKNOWN_ERROR; } @@ -147,9 +149,9 @@ int16_t perform_mov_segment(v8086* machine, uint8_t opcode) if(dest == NULL) return V8086_UNABLE_GET_MEMORY; if(opcode == 0x8c) - return perform_mov(machine, source, dest, 16); + return perform_mov(machine, source, dest, 16, 0); else if(opcode == 0x8e) - return perform_mov(machine, dest, source, 16); + return perform_mov(machine, dest, source, 16, 0); else return V8086_UNKNOWN_ERROR; } @@ -164,7 +166,7 @@ uint16_t perform_mov_gpr_imm(v8086* machine, uint8_t opcode) if(reg == NULL) return V8086_UNDEFINED_REGISTER; void* imm = get_variable_length_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset), width); machine->internal_state.IPOffset += width / 8; - return perform_mov(machine, imm, reg, width); + return perform_mov(machine, imm, reg, width, 0); } uint16_t perform_mov_rm_imm(v8086* machine, uint8_t opcode) From f5b5ca71cbd4118c1736e6a0d39dc4353546c989 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 16 Mar 2021 01:18:00 +0100 Subject: [PATCH 112/165] Added set and get mode for VESA --- os/kernel/src/drivers/vbe/vbe.c | 25 +++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 2 ++ os/kernel/src/kernel.c | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 491106c8..6340222d 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -113,4 +113,29 @@ VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr) heap_kernel_dealloc(svga_information_ptr->producent_text); heap_kernel_dealloc(svga_information_ptr); return VBE_OK; +} + +VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f02; + machine->regs.x.bx = mode_number & 0x7FFF; + if(clear_screen) machine->regs.x.bx | 0x8000; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_get_current_video_mode(uint16_t* mode_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f03; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *mode_number = machine->regs.x.bx; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 5a116412..41be0f6a 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -49,5 +49,7 @@ VBEStatus VBE_check_existance_of_VESA(); VBEStatus VBE_get_svga_information(svga_information** information_struct_ptr); VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struct, uint16_t mode_number); VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); +VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); +VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); #endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index ed122f5b..dcacd6d9 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -420,7 +420,7 @@ int kmain() char buff[100]; VBE_initialize(); - + VBE_set_video_mode(0x18c, false); //svga_mode_information mode_info; //VBE_get_vesa_mode_information(&mode_info, 0x105); /*VBEStatus status = VBE_check_existance_of_VESA(); From a13773133461369f03aaf6e3540e52fe5656f849 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Tue, 16 Mar 2021 19:12:04 +0100 Subject: [PATCH 113/165] Added VBE save/restore state function --- os/kernel/src/drivers/vbe/vbe.c | 28 ++++++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 6340222d..3d541957 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -138,4 +138,32 @@ VBEStatus VBE_get_current_video_mode(uint16_t* mode_number) if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; *mode_number = machine->regs.x.bx; return VBE_OK; +} + +VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f04; + machine->regs.h.dl = 0x00; + machine->regs.x.cx = requested_states; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *buffer_block_number = machine->regs.x.bx; + return VBE_OK; +} + +VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f04; + machine->regs.h.dl = save? 0x01 : 0x02; + machine->regs.x.cx = requested_states; + machine->sregs.bx = buffer_pointer; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 41be0f6a..93bd9619 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -51,5 +51,7 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); +VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); +VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); #endif \ No newline at end of file From 9562ab725e60c7d7294f741a5c0478bebb517378 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Tue, 16 Mar 2021 19:18:10 +0100 Subject: [PATCH 114/165] Added VBE display window control function --- os/kernel/src/drivers/vbe/vbe.c | 42 +++++++++++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 3 +++ 2 files changed, 45 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 3d541957..75befaa4 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -166,4 +166,46 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; return VBE_OK; +} + +VBEStatus VBE_get_display_window_control_16bit(uint8_t window_number, uint16_t* window_mem_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f05; + machine->regs.h.bh = 0x01; + machine->regs.h.bl = window_number; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *window_mem_number = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_set_display_window_control_16bit(uint8_t window_number, uint16_t window_mem_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f05; + machine->regs.h.bh = 0x01; + machine->regs.h.bl = window_number; + machine->regs.x.dx = window_mem_number; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_set_display_window_control_32bit(uint8_t window_number, uint16_t window_mem_number, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = window_number; + machine->regs.x.dx = window_mem_number; + machine->sregs.es = memory_selector; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 93bd9619..9966c05f 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -53,5 +53,8 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); +VBEStatus VBE_get_display_window_control_16bit(uint8_t window_number, uint16_t* window_mem_number); +VBEStatus VBE_set_display_window_control_16bit(uint8_t window_number, uint16_t window_mem_number); +VBEStatus VBE_set_display_window_control_32bit(uint8_t window_number, uint16_t window_mem_number, uint16_t memory_selector); #endif \ No newline at end of file From 4b3d087d04ac07c9deda9496dd28c6e204e36c9a Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Tue, 16 Mar 2021 19:21:18 +0100 Subject: [PATCH 115/165] Revert "Added VBE display window control function" This reverts commit 9562ab725e60c7d7294f741a5c0478bebb517378. --- os/kernel/src/drivers/vbe/vbe.c | 42 --------------------------------- os/kernel/src/drivers/vbe/vbe.h | 3 --- 2 files changed, 45 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 75befaa4..3d541957 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -166,46 +166,4 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; return VBE_OK; -} - -VBEStatus VBE_get_display_window_control_16bit(uint8_t window_number, uint16_t* window_mem_number) -{ - if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f05; - machine->regs.h.bh = 0x01; - machine->regs.h.bl = window_number; - int16_t status = v8086_call_int(machine, 0x10); - if(status != 0x10) return VBE_INTERNAL_ERROR; - if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; - if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; - *window_mem_number = machine->regs.x.dx; - return VBE_OK; -} - -VBEStatus VBE_set_display_window_control_16bit(uint8_t window_number, uint16_t window_mem_number) -{ - if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f05; - machine->regs.h.bh = 0x01; - machine->regs.h.bl = window_number; - machine->regs.x.dx = window_mem_number; - int16_t status = v8086_call_int(machine, 0x10); - if(status != 0x10) return VBE_INTERNAL_ERROR; - if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; - if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; - return VBE_OK; -} - -VBEStatus VBE_set_display_window_control_32bit(uint8_t window_number, uint16_t window_mem_number, uint16_t memory_selector) -{ - if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.h.bh = 0x00; - machine->regs.h.bl = window_number; - machine->regs.x.dx = window_mem_number; - machine->sregs.es = memory_selector; - int16_t status = v8086_call_int(machine, 0x10); - if(status != 0x10) return VBE_INTERNAL_ERROR; - if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; - if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; - return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 9966c05f..93bd9619 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -53,8 +53,5 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); -VBEStatus VBE_get_display_window_control_16bit(uint8_t window_number, uint16_t* window_mem_number); -VBEStatus VBE_set_display_window_control_16bit(uint8_t window_number, uint16_t window_mem_number); -VBEStatus VBE_set_display_window_control_32bit(uint8_t window_number, uint16_t window_mem_number, uint16_t memory_selector); #endif \ No newline at end of file From 6689da0c7ac3d098358ffe5a85c29f6e722a4443 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Tue, 16 Mar 2021 19:54:45 +0100 Subject: [PATCH 116/165] Added VBE set and get scan line length --- os/kernel/src/drivers/vbe/vbe.c | 31 +++++++++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 3d541957..962b9b5b 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -166,4 +166,35 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; return VBE_OK; +} + +VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = get_maximum_length? 0x03: 0x01; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *bytes_per_line = machine->regs.x.bx; + *actual_pixel_in_line = machine->regs.x.cx; + *maximum_scan_lines_number = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = in_pixels? 0x00: 0x02; + machine->regs.x.cx = length; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *bytes_per_line = machine->regs.x.bx; + *actual_pixel_in_line = machine->regs.x.cx; + *maximum_scan_lines_number = machine->regs.x.dx; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 93bd9619..8bd79ae8 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -53,5 +53,7 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); +VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); #endif \ No newline at end of file From 4017e04eba37de431ae7d05659722b6d653c14df Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 17 Mar 2021 02:25:43 +0100 Subject: [PATCH 117/165] DrawingNotWorking --- os/kernel/src/drivers/vbe/vbe.c | 33 +++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 3 ++ os/kernel/src/kernel.c | 49 +++++++++++++++++++++++++++----- resources/LENAD.bmp | Bin 0 -> 192122 bytes 4 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 resources/LENAD.bmp diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 6340222d..b95f7750 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -7,6 +7,8 @@ v8086* machine = NULL; bool initialized = false; +int currentBank = -1; +uint8_t* mem_buff = (uint8_t*)0xc0000000 + 0xA0000; void VBE_initialize() { @@ -107,6 +109,11 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc return VBE_OK; } +uint16_t VBE_get_word(uint32_t seg, uint32_t offset) +{ + return read_word_from_pointer(machine->Memory, get_absolute_address(seg, offset)); +} + VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr) { heap_kernel_dealloc(svga_information_ptr->mode_array); @@ -125,6 +132,7 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen) if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + currentBank = -1; return VBE_OK; } @@ -138,4 +146,29 @@ VBEStatus VBE_get_current_video_mode(uint16_t* mode_number) if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; *mode_number = machine->regs.x.bx; return VBE_OK; +} + +void VBE_set_current_bank(uint32_t bank_number, uint32_t winsize, uint32_t granularity) +{ + if(bank_number != currentBank) + { + uint32_t banknum = bank_number * (winsize / granularity); + machine->regs.x.ax = 0x4f05; + machine->regs.x.bx = 0; + machine->regs.x.dx = banknum; + int16_t status = v8086_call_int(machine, 0x10); + machine->regs.x.ax = 0x4f05; + machine->regs.x.bx = 1; + machine->regs.x.dx = banknum; + status = v8086_call_int(machine, 0x10); + } +} + +void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) +{ + uint64_t l = (uint64_t) y * (mode_width * 3) + (x*3); + VBE_set_current_bank((l>>10)/winsize, winsize, granularity); + mem_buff[(uint32_t)l] = b; + mem_buff[(uint32_t)l + 1] = g; + mem_buff[(uint32_t)l + 2] = r; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 41be0f6a..81bb061f 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -51,5 +51,8 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); +void VBE_set_current_bank(uint32_t bank_number, uint32_t winsize, uint32_t granularity); +void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b); +uint16_t VBE_get_word(uint32_t seg, uint32_t offset); #endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index dcacd6d9..9a4dd33d 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -420,10 +420,10 @@ int kmain() char buff[100]; VBE_initialize(); - VBE_set_video_mode(0x18c, false); - //svga_mode_information mode_info; + //VBE_set_video_mode(0x18c, false); + svga_mode_information mode_info; //VBE_get_vesa_mode_information(&mode_info, 0x105); - /*VBEStatus status = VBE_check_existance_of_VESA(); + VBEStatus status = VBE_check_existance_of_VESA(); if(status != VBE_OK) { vga_printstring("Problems with VBE: \n"); @@ -462,7 +462,15 @@ int kmain() while(!keyboard_get_key_from_buffer(&kb)); } else{ - if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) + if(mode_info.mode_height == 200 && mode_info.mode_width == 320 && mode_info.bits_per_pixel == 24) + { + mode_number = svga_info_ptr->mode_array[i]; + max_width = mode_info.mode_width; + max_height = mode_info.mode_height; + max_bit_per_pixel = mode_info.bits_per_pixel; + break; + } + /*if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) { if(max_bit_per_pixel <= mode_info.bits_per_pixel){ mode_number = svga_info_ptr->mode_array[i]; @@ -470,7 +478,7 @@ int kmain() max_height = mode_info.mode_height; max_bit_per_pixel = mode_info.bits_per_pixel; } - } + }*/ } } vga_printstring("BEST MODE: "); @@ -489,11 +497,38 @@ int kmain() itoa(max_bit_per_pixel, buff, 10); vga_printstring(buff); vga_newline(); - + VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); + itoa(mode_info.mode_attributes, buff, 16); + vga_printstring(buff); + vga_newline(); + uint32_t off = VBE_get_word(0x0, 0x7E1E + 10); + uint32_t seg = VBE_get_word(0x0, 0x7E1E + 12); + VBEStatus x = VBE_set_video_mode(mode_number | (1 << 14), true); + VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); + off = VBE_get_word(0x0, 0x7E1E + 10); + seg = VBE_get_word(0x0, 0x7E1E + 12); + uint8_t* mem_buff = (uint8_t*)0xc0000000; + /*for(int i = 0; i < 320 * 240; i++) + { + //mem_buff[seg * 0x10 + off + i * 3] = 255; + //mem_buff[seg * 0x10 + off + i * 3 + 1] = 255; + //mem_buff[seg * 0x10 + off + i * 3 + 2] = 255; + mem_buff[0xA0000 + i * 3] = 255; + mem_buff[0xA0000 + i * 3 + 1] = 0; + mem_buff[0xA0000 + i * 3 + 2] = 0; + }*/ + VBE_set_current_bank(0, mode_info.windows_size, mode_info.granularity); + for(int xx = 0; xx < 320; xx++) + { + for(int yy = 0; yy < 200; yy++) + { + VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); + } + } } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); - }*/ + } while (1); return 0; } diff --git a/resources/LENAD.bmp b/resources/LENAD.bmp new file mode 100644 index 0000000000000000000000000000000000000000..967ff071d4ddc63f655d0ea80df59c0b661bcbcd GIT binary patch literal 192122 zcma&ORa9Kjx;1$Ie(8sM&p8p?J;Xi1$`vV`f^v6v7mA_^DBRtH#NCZ3G2(%^yCcbc z?8UjGN56K)W>dAp7?91Hd&)OgkOcFO|LY%%f6U-R3O?Zf=O6!=1fT!UKZ3v+`~iP| z>0kf&&&U5>_{TqxxO~n3`}+Uy=l}gK|KC?zWkVLxpp4chDC{C4>vEI4_)X>MYi;Og z4J=H82o=HNtcVy(Qm_^pso55wND7uhqAZ9FO$7A5+`{WD(L<@_mB#blT>Ht^_|eqz z$=344(e_!_^v%@##o6}B-TbMs>&x))=i#GYeIuW>m2U;A$HgU=@-buSYwI%;oc!cU zQD#SjdE8ZYq8MI-4k99#WWkr`!ToaKO9;s2c__b<+-MeQvsswpB5sfgpyuTNB0!g9 z;{qu;0d(dzV`)*d4pqtAsO4-NDU#Z2=RZTiSd+bMfI?;zeUkno?k&*Eh>0QzA$H2rtC;K5v~+z(-Drcb8RnOV@S~!`#HdI)I>C~$)rVVcgZk6aK?MlE zLU<@MBegPPy$$9^hxwCHVLX^01G=1o2&2ROiqb-axM&e1lm`i7!To9Ai(!FuSO5(c zz(hr`uu-DS1Q{wpfs7O)qm=L{4K`K`jgUe@#VN};$-%O$O`fdnHCbtWMEqe=!32|f zg+`p95wFlnZc@m1nADpz>P-&y7N0uBEt!(AZb+DSB$5Xb={+(3E}uUw;XjfIXB6V6 zGSO3`a#}8#(TJy&(ixd_Mk<+6%O6Tr(<YInbIHN5h)zNzkf+c5gR zd+&#y{hxY|d>lOfY2d`?kyBp=PJJ0U_jT;-*OBvIcTIdBJ^N$y?9W{nevVz7-Fta< z=fsEMsFOYMnDPsR6api%PU(R+i?kGU1}6O5Pz~=Tn{QzRYx6B|oQ8oK|Q~ z>2&Ais#99s35n*S+IWR8J1dr+H70e_?tbIjge>-C2O^DkgN139ZE$%_SL4w5-;W%uZ@<4}&;BC-pK5+eod7SckHdc{i)D!8H4DAhAYyR(x5?Lsj#785_qHvkzhe3nxF|b z{AxFHZB<4}18!?Gesd#XdsBK!OKw`Lg4`p>ZK2|ubD)*DH8$KD6Cz#>4HLtIg%E!x zEQp;FEP=1Eq(xg&qKqkls+33_Vuc&Cy|<8Xriebpl~2peFH9Bh4RxRNtzV2ypDfK^ ztW966&0q8Y$c>+kE#K{(-@VP>YMVZ`w|;0E{p1?`!V+K0$MxY7tFh5$LV{VCTuIsD zs4|V2ofEiNKJ>rwZ~)IU=0%C=tL3@zeA-H0MqmM9d9ECz-D&IXmUNV5mRYh(E9ss_s&`o1y3f+R z*W7iqs{d%qjGpFgS+4e?aMJ2)EE^yWh>l+xg)>M-VY1vgaaKO9w z{K$m{^&V$oOVL)|SntlmP2CYg$FQTLF5!aN}68@Dx8l96ClD_h!6&J@ov-M!Axif8y-SWT}Fq7 za*(kaWV{L;Aw@>W(6LH*I2RcyMTGJpK>}Ee4!fZ|C#f+bWi%UmlwNp=oOg**e4R?X z#vtEd)9z5IcPNzWT=I2h@og6Awt#(0#JZ~#JWz=5O2zjiylH`GMlPM^37^Vk&y*?v z*vE4D6RBics(hr9KN3m6`Jq}hty4`awU3R~XC}u>TlK4ow%1i1uN#Knw(fk_eeiw% zv5!M1KlGmZyyNWGfis`S&wUv@^L6a}*O7DI#?Sv4Klf|=!uS1`-VKdktv2*>({0FD z3M?!?EtmvZo|E*i%#`L zqsaQC(JJd-*fsvUQE!i!STQL*%pLVradIW1P4 zkgBdo)fYM9Gko4r7XP?_eV9!@#GxNz(+{x7I|ZaMa^4Pd&JZ{gvv(9_4Hn?L$l0AF zd=ELNpPJoYl0P7%4AAp?=y_fAf_4V6mqqGf75DH+z1-q1KDm=!+{VgpX6Ckwc)MI( zGnL1`H(pujy7{;H#-EBSf2tj0cD&v#D#>6n~rzcJr+eZJ@VT*tLJ@S@||pZ2T2 zn@<1m?*Hr_ePix?%#dGB$M(WjI#Pm#X#v!vCFE^OIk0dUBwPiHR$~*)xb>dQt#$bA ztyw9JnOp1Aw>M;`wdSW*XK!+3tTm$(wU|ULDq4mJ6T(Az=twpyh>QuM!u$oOcq2T{ z2937?6hmTcn9cPBujNAx;smNo@tf8(_<;U=; zs|C3c^pY4BBY`bQmbD8ThVJlGoolKsl8|Kv-D9uAP2b}yNBdNXK-g&BP zuQ|(-6_bMx$wP-w@sR>tv<4S%%-mXqU0IF{VWa$rsO1HyP%2@QC3}Mr6Ul-5Q}EGj zL^u->M1cn~5W!S{Uwo_>zWBUlU?bUxFg7xn0}bM%Lb=dDE;@>jjF%vzM2H9xCQ^=w zk-@`w$VdSsM35FNg2q~~8@!px?S$0feC!cg&N)iq^Svd$H~t-&Vb|V z@cFOfXTFb}|F&!5+xUeqJ5RkB9Ga-N_Q}#M_(U2iybu{uf($7}MKDvB7N9~3AWL&$ z%Ls{H~+{K8>!X!`TS_fgX2e-+c5APsss=*|b7H)Hs zQd}8P3K4y{W$3ZW`9SV?AeEitGY?3Fhh*yWQppLi?4(q2hQmF^=bhki4zZaB*|Y;3 z+8%1rPG<2Qa@GhfZbU0i6K{L^-A0nl#G4e(;F^ZH!-^*`O$=36h%R-gXiJMy)B&nM@=TVumBf#oKN zegKzLyFF02?O)Vw|E8oZV}f5dHb#bwG@w>Gup2AzTN<)cn+eHn8JlXep>>!91wKJR zSf|cNRN-Pp=rAEHkOvFmz=LTiOA3?!U6i_%kru9k#M@Ep$`OfW*wtRtw&vWdqa~C{ zhTs8L`BZIvsrG!()xWnk0|VLO4y9Wa?P~e}VtFxaNjhSA7W|)h%(6V%Hj@Nd zMc!yBT&2#8WEUm~3Rg)pLTGuB?EGkfrKp0RY|oElrAIIdqL_pr5+jbUh3lIH)!mBL zA!&OVv0^~mK4|G`rd1K6DLElIlmxl~ZLDQg^{QGAS9Kq6?Kfqb)eu!}j?IG5dkCdI zYWaYwrHk1lz&acxpE}h>jAMy%D|?+gYfXFls&*W1+0(?U#f1?tfjO9fd~_fQ5y>a6 zQ)5@!G9h*8o2pP@d_-Ug+@FMvWMEer@GDj6;aqeeB_oD~3TI;iY0v-)GMJ4F4-bN{)&U!y}}K5CI&Jb%Y4&&x3^sP>I%z z?KSuKZk9$+Zzr$hQlW^~d z1-B%^2VwzW;YV`eBc*Ict9YVRJ=5u)nM_Z#h8ex)u~z*=qkf>*J~FDNO&W0Jkxu`} zVSncKKCftcRnzghrvFXn*xQ~%ABT>8969}I=;W87Q(wkUf7&_mZQuDHdoO=EaB60x z|8$MAn}gNlZ=?`bkkaFb_y~G>6gxedkrBhhg_5xmMYu?Ci^%wJ4lZ6?xZO>J`Y3sw zlH$(X&1JdUDhiN33bH0+y`8YVB7LK$0M(hh#Yb3Qp1;jQ-db9isN&>yxAo5`osU$d zk5qtaSx3d3{c_215%(}(a8}Ge$R_RQGxqZ+JE_I{>7>2%lARpl2$i@Soaw|-R^bk2 z(J;GckX|srF79WNhj^47Jo>nlKQ83#lyY_{griFSn3TUuCEce{jww}pHOg_lVoW6+ zQHh4NqJAl-TgmEC@poE#9@U)w-g0fB_uk*Gy9@O<|5jgJsJlE@d+ATp)rIECxz0uY zUFZTY7Rh%3K)B`dT=n_imB)X24}GiL|Is`0&eick?Y>2$?Zs{L!9qolC5$vb64Z|j z4Pqd|1*k|BJkEq(Ta~%J0l%d>W0M!V&IJXlB~plq5~L?e(a{`a1P>X&hWb&{mK7!c zyD<5mL`X0A?j&lv9lHkTz=yV#S0A4so4=v`L#4$tsHC z5aL-%tTQi`hYuxYM$qyjsJVf~!Y#4}e#4-uZAjKyRp9G3b?z+dY30>&w#kW!jEto@ z`9b-TE%E`euY=+1Q`DVk?Ca1p`|_Pun8urH=@!&b1Hhw|pW@F&B-jxfs&Si|@X0*{)Si;8)5P3Mtdi>j z<{cjM4u^VI$hu8025`PXXWZqm@ABAp`22fp-hHL$nm}+{B)qMbJ^y_9Jd_0}rjpTSFnND$H3?f(s{M!bsRqHY!4h zjNl*wsn7r_Vp$O)kPHu`qeFS{NKwINXXdsFVrHkHpfhW|Coj1&3*uv7Ycn^LXKyLb zTvwh0Z_V0Vge;OtiYOgLdUH#K=^>5qcT+fYJ0O8JS-~f&oDC$4;i|C%Oo0w}o z{j=uS=bHT=s|H?Ko2C`UONGTdahuDb!6I}3CFNiFDgQ1^{Wk>~z=B0d&pbW%0l1%-NIqimvCjv~3F1eAEGbM`T9~#hFLg;t3Q%-$*0fdSm@Rdf4K=8> z)me~!66p+EaEm3MQ5c`=N?+np;2F+P+#lzL+|`+B&`%TfbTtQT)x^`P0ajJp2MvxOoDT<crA#hkbzWq028QX2w1V< zAfOOJgE+8YDlCKr4Q9cX(bIy!O6I@=SXl5NjTXYdb2VO_79xPgsSz=Xv`}$s2q(#( zpXATk9xOtwcOW;^p#grkHi8I?gg-#cImygDBcfhmQ?K!uQ(ORK#uS}#kH@|*5I*1u z@AHNCxuSal;XSc%N}{-}P~De`r`57)rF_P2d9E`*Gg@ER%buF;0LafRmM0F!Q-kxV z#reeQd}4Avb-JEg%AQp=Joh!ds_%Z+wc~x?o{#;na=W znyT(9T+d9ln|%JUl7cY?We=HtoLVr>${#B!*jbV{&L)l1Ne8GUdx3uDF?MmtJ4K8! zA#)d>HNxlYkqh@orF$geJzDtzjrzD+chqS*YA~JB=}(yTM~$YVHuE8~>7d!T&u-dp zHXKl^cd8U)8u1RfU`Qe87f`!p{1Hdfy}ILHdTuNL@D4xxpPsvaTCXqEPcAfH|I>E; zPxFn1&Kq-`Q}cj)d#}%ST$=}oZk?P3e!1!LeEo&l+B4sMN5A++-<#W?8>;T}m1pv^ zdr+%v$sow`D~2p9NL!Yhvb-=YkOme&YLo`OrVIoE*fmasKNTLzg@-UvAsj#o$Y4s^ z5+Y=2QQES_bLvuJQjicHZ$oeLp;KG)Qd%$@+OpF|3kxnV01TBgGV^nd>y5GUqpALb zwe7Q|^^2wBn+{NL*Jo4bS99AZN9T7-+jncncV+DtaoI2*HS;PCxd+cQkM)|m>Pjl}L}Z*E6RSi9P#^&$L@=ONDiSQ?U=A#RleUx!1y@2@kN^&3IRG;FMetw& zbdX3RVkM|pIU<~w8X|y2Do`N8ijk#7NK^cH+x-M75gJ&66SkrPy}kvvtqrrWD-SW2 zi#b3{KUb1}j$3q@MZU>p-V?Fz@!1c=+(#E z(6EtwY^)3$EkJ@GE{uT)Afuz1$WU%-Fay8Nj0~4$ZTC@gdg+9YjBPd9N!8?>mVy*t z*1GbnP375X_4)AD^o`Yscnf-sH*2*sKhZ!(c&i(4)weyAI%cfy+kD{}GI5m3+D9ji z7vv7niQ~kQeQfeBCT%a5bBM**!{rV zW)52_uK1390NE7K&pRIc?RoG&?Y9>iZ!Ul=tM$f0`;CRR8$Ua50TsQNKeu07Xt}=7 zd~L4&>U_hMKaE!xd=qmXz{2}JId;6WcRkm*r%E`-(qY|@C?jM!1MqLkvO>i2ytHNc zkY&Y?Ku&6y0v4r)#^@0KG_Z1@%NdvmR$2f(b!lbJ6>Yim%eScR7m38q*7<`?aC^y|L+|x&1SMt-bw=rUl^ltGVNw zvGc3F_nWQjw*^?>ny)g?dx7yKmH!|+_fkg6j_kw=UP@)R^VsRrGfl&{$&e1_cAr~) z+`t>h2NmO%5->~i@>d81sSW|um=Vgtgz}2lDRbk5Inf;QI%QtG2pw3G5k|)b5V1iy zxBwy{pd^1u7G*8vptp0}&@pK4JXpD-Puyz4+bkJQ>1GWhhRI&Zw`P`h=-LmIb=uKp z!FoYup=}4hqQ1ypO?Mxy=sQwBw#U1xQ_)pLskcySo67bNd-tE}J2YS#G$0MRD@Yj; zMflKsY)C#fxDX#!j12)(A!0@t4IL@W+*Y2xp)@O{3Z0+jo03Q!RO;DTX6END0v5d^TzfQN8^3r2?Vkw7NJic#@OOdJ>@NKo+# zXp|Hgr-DWREiDAn8k$&&TJObfZ$qrFfyTMeU?Q-lnvm2?!4FY!qxAGqX4Y;_?qN~U z8FBH1oOVghxM&nz)Uqd(%!_K)gpzkvFS%r3Pb&FSX4SM^{?MhFuJS%DvpuWyK6jVD zbeF$!mcOp7c~xKc##i^MvF2qh)+*R>5V>#H7D+3xzR*J^E(9>*<=;T;JhfmgjkuCZNF;-|SqZG{I2yQ7nbEAw4SH;>5EsiqM}VY-jEn&$ zf{_-$M6WcU!sQuTJ)9zd-*!TBZ2_{O5Z71)@n!(SxWN zFJ-&G*!tc|eUHh?Nqo*O__}gbv?wWnnhKVae}2lpa+3dD01Ou-hzkn@OQ;0lPfl4z zh5#T3Qd5^vQkGC)ek6!r0X%@1vXqt;ErrLKGgIpFP(8V*ZUUsgfN+>fnPdy^v6WBM z<`-Je8?E=fz45E1^|P%5Na&BwmM@m}Z>G*~w(f7PzVD8{U$*vNnwqat?GPbB!8%LXLzU_=w0|+$FB=z7Sh7yffs_`kRTE+b z`3cgDXi;92h!93ESR*W2CC3JqGVyMkqI$0Y$!-zs9-^6 zu6ANpm1S;qqvJKuKr(b$9>6brwFbS`0ET)XbH+w8p+OWR$eAN0@K6rKAFwtD8q9+R zf<&4N31)$`0T#-KMakfCDolb76(vhwt3@YhvGH1Lq7D%*S)3mMqrJ+FTvLfpYDUJp zP;s`j2onTk6j4T4oC6kVgU35jD_odW9>T`D0$4}>_8}r-pa?l$0vjWx@8ad05R^>N z3odX-x44WcG2@|<^U%t>qt!eyYMFbJ$H{}(tE6d+l%rDJ`S60nS z@It4bQOO>N_}68kYfRy#65+kP%ze1E?u=+MHjI)UK?kBJCyq>rC1uAFvt!7aQN@H< zR%R54=2*B$M)qbCJc5sinpO>mKLqk7jCqdS6*!$m{B+$xvL*)tvBS#LlVIO zQpp|$b1#p5fXzRuR2-K{4{6jV7ozyH~B+Wiswk$#yG6qe{Vm zgxx1&_NnCiUBff==fC&dnjL-gXXx?Y;fH_v?*8eyv(R%343!qTr{=qF|7pKD-+OZ& zyzZD<=)SoC^fm~k!8oaTa=!EGpT>)GjT1ksPyciu{$?HfsA_x1uY6i0n@rCdhi|Ba zgi5w8rEdLiV$u>KpyT8vB*-$LmdUVXCFme3B9MXrxk@mYWl$hXOMrexhg0ExOn8U{ zmEgc7x8|bz^Km1@^gTrd=Q*tFz)4BeGdjl$gZs6y`n|c~v!(5`qxFlaeKCS|bbht; z{IGQWwDf#;^!zfl{nR#n)%m`0Oz)Vorv>C2nW#g!jSZ-94K75Qx4z6s9cfeV<3n1g zNe)wfJpg99Uv_R3g|*#g$gV9~uO_b76|GZcg|UkggvBd`*|7rpW=(!Pzj%dU(SiEq zWJi<~N0IaY8!v(L&bJN?tJ=rx9d2R;b%l_;lB-J9i#JMnD|vd9y^Y=2#HnhhR|Eca zQ_Bx~dt2BwtyJG`MdOIF{fKw(Zr`ar6{mVQZA0q5ddUvEWZ1yy$yrIy2+P6+X5)hM zG9p1-24=n_TnH5x$;5<`KzNP>b(bhLYNZXgwG3!xs6QDRNP>dQYNZmrQnx4% zMja``fp4+447JLOO?0P4S)d`Bv><6}uq-7=nHp|N4!1&LN>gLXlj15;Vm&Ew70}f! z=%lW!)Zr||E=taBUg2RD@f?+Wkw?EN;!cSL57g3WgX)3V^xR^4X)(O8=w6n(-c(k; zt*m-iTKS>8>TRj>mBsSXV18w^ys|o;n~YBks)uUj9jW97LwYB>;4ETIBh0@T5m1Z? z1%m)uR%8hwj!KB2W=EF*{hSrU%!*>;LTLDCI+&)RB1EWA781m9|H)n;flM&6Oph1g zWA%iTdS>A;1K*mLR-d`uN5M4Yq}E{8xiXTfbD{P5h*sR@YFMl-J*_D-!ITv#F4*j- zuDsOIJuP)Ta#udGm)%n6PD$h^xPWcNha~b-GVK|q?xfayMz1?-uuhomXKnWLR{I%S z>1ns;tlfRi>7FR{TyR!gaFkEj0rQrfv%Ah)o#*V%bB5CM4(D;F{g~5!#AZEavK}^D z_FGJV!S|bt2lTpq8u^%7GAv~cN?H9{@u;osZtcl0fMkasE{s3^J3jMw=>7s=;ojSS zI&RK&-CpRqz0eCVdwYK1&OEp{czb^E)_nhsMIeJ-2dH^;OoD31Z1csrx^urOPX6*7 z{!zN;n{nv9xbB(AbStCy5Mq0Ma;PRHfCUerLj6h5Wkrxcu!`tueiZ0(I>hgP!z*g) zl43{@2@ys^hVbCw3dHJ)jMR=COm886oRo8rO1sQqPcirpM9Rks(@VYMt=jj|)bOda z9T?uPhL*3k&M$y@&0Rmr|3kj^uAlafU)ts$hU(8e`#ZMcSqXKDfH{Z<_>H#Wpbf1K2zP*r)X}a*Y+v8cRTj(Y@Zw~J;dIq<{|Xz!Ujok3mNLj ziYm;A%p=4S@!|RDVMQ5{6nq#J7f#QJ0M3q-5lPO9;^1SY8Hu{|^=AAk3$S>oAQCc! z0*{emS7?!;;AYZrF)Vl(2PkJuv=9|a26h+*G;;(S5z0aYv7wP7Bq(vk0KqKBtdhgS z#qdx7VI?YBfs0oG*^CI|p<FA<~#DU(BOh?SMF zwat*V{ixL4IB=xx%|IQ^%e_D;x=Jm$!lhj06it9GhlF`o!hay-KUFKAYvoT3+UI)x zOPB4n&HTz`f96ieQAOcMTWH=ugEP#cuF_BtAYAv&{uNd2!n^K>#y{ZV;oRw08UFX4WsmOyiWG6LX zH`L-*T5=H0_yj{%m?(R-uF`d`q2r0wGi`7^v{l?ynJz1IXXVOcTH{fT`LxD%!DK&g zuum9mmyC`J7UzV^d&yA-fO*#Cov@dmcepQD%P-ggR9zE`;4QmgFTY?bJ!>sJWpSK! z*p6H5M@-gZ2GbFcU+GLoOvb~2g$*E-*6o+ecgdxrGXAiH-K*dX>bzGyM?SP)n+43f z^U0sxGk?b)Eet+b=)3c``__EtEr8jD-aGSMx956p&-LH^15iA4cYf&3Lhr4G?pq7J zKv!P{DE{4kWw!OwLhHr(x(joSXJ#u;{VYH5)iU@&+Vq-ceL&!xN8(42TfDFsWoif; z9RiAcG)xd36~aP<(-A>r#A1Js0s}#o9~BxXLM0eMSWQUj%SR35<8~5rPco^OxxCv< z!F`_eu?+a%vNyV_kLIS2){ak>E-*RzW^4bd?fnLr*Vg;p+WXVi`^(YwQ`h`mQSn(~ z|3H;KC(~|aV~=3hb)cf1=qOv}N>A3tS~8+TLfTK*T8a;+p@XUE;jH{9Ms5I61W{U8 zEsD&V+!$e2I4LKVOIjz-4rLU^F?rkc^fjXNfC5}#es%~sXITz0yr8nM{D7msU0UC* zX%%nP<%AUr)=DI+C8Zfg7v9oHuB9S3dg{eqfKdgYLyp_S7%s2=au z@9!@?q{{TsQ!2<13$w7Xc)Klc6+bIMoE=953lb=2ESMPulQCg*Ob8YHs0e=|Cb$?C z%s@v=kTE(~f&my_cnAwn5-gCK1|}wndT^7WflN#oh!a_0h6@j8r!J=e--it4Z}$Tf z%z=dp;PIe5BTWUlbTnw)@S#C$NSHh$Q2~iopjYb=QF3?)7a6a{t#=~V`;Z9^Xb2zT z$K1MvzWKko+m>llBkj=WO7!|pT+$9a@@Qt(`Fz3!QtlOE&NV9WI+Jo+!nns}-3Mp6 zU`8f?q5(5s^;4DhnMM1;YYX9h~|5#Q1zTEe| zyym0N_ugIkrmW(n*YVV( zfqwQ*n7x;r?sK-XQ>M~0_C*VP(pGxPY&~YN9yD1F+AN24rb9-FW)e-GTB-}U(K-X{w?XBI~9|LwUA{O^3rt=XQbg)X3?@6Hb0 znH#>hFnD)vowfJm*J>i(=)47LzuLs%0HYd_{UlNmdjsFP>W%$IcEZB7~7R$$Huvd3s<` zMsNW!l9dyX%Ui*#rqmtuj@DAEd&ITmI6-b?34f)48OyT6)UHfhGut<=YU=0I_VH?V zn_Kpn+Pc|Q%_L8&ptYGj+^0F!Vm#+#?II<$*>ZcBxN;S{J7<*wFi7@#4JKZk9$5m! zGsw;Gk#uaV1RKQyb6((o!Eh4^QmJq;I@SP>(PQE@h#&^Y7SMopqeYk%T98=*ZvyV{ z;^a3$0q6z>f~-Z&!-fRV;ERh{3X74$LnW!9Qbe>IP%R=%gk7nHf-4b9+)6DnMwu4K zgRi!N0x&Gro)RQY@?&jZ%GtVH1Pw7IM|)FNG($J^Bew2BryV0?Tr4D9BNL~nMYrjs zyFA)`F5`ii^H{=tBI7-iiJmDGPfVI8YQ+-(VWa+~-SpaMeCsZMUsdVvQ5 zeP#WJ+Ij%w4_@Dgs+y1Wb)Ty1KQy(xFROW1=6Ye#fH5(cx;|9OFJqu%DgWX^mz1Dm zCAe5MK8%tTU7Q(1&jczust8zMkPqO11qKD71Qj|#ks8c{fXPU>2pT4U1n^ozKkt3$Te=vs!DjACNHHP9iz*Lm1o8( z-OdYb{nL)xX@hsh*YHSfzHW3(=-t=M6<3Vjs}A3!)py-i4N!c!)O*3?m@v5}oSsXi zA%S&o{m#|`EqYU5#p z>6l)3Lq#kPh&4Hd}-ZD){0r!J)e zMB_oJ&kwW+)al#m)05h=VFP)H;XKq}5oR~BaDvLX!4TbJN@gU6=TgTTz3-i+>65eb zi@oQow&$y%_p7e+tFh;sx%<0m;HMenS6z$#SLOS}Gk>JZpORU3vNMk3wsd0>s?c%e znd_@_x3$nw-85{k9Nj_QR-V5~mlMmQtySfRF!NRlYsIY+j6E|XKRS?6eihE@A~;H7nfVc9S|pvlnr+E24aw{F znLBqoyZQw6?OgA$vSmzG*H-BAWI1+M?(dh3d5MSX)mN&u7sVN){A3F~y^NXJnvb=R zvt8LMIJ7KJW+Xi;q97|80G5W27vVtc42HQO6l??--7=Bkz{F_~Q7U+(5*^6}8y28` zbTm-Kv2ti29efRluwbDa7}$dl0MN}$0rOwb#{h-rXbB_)aJLo`CQb{JLBnK_2*qOO zDpCarm%u>td4&cMtpFoq>^eJQof{QrPWBgVUCP_MM7|-woD^M|y0#U%Z8&Z7K4j8? zbkw=roNKha>-3^29_22BeqX?PAm!c{ac0DV83i8{o?qycFLbJ>deE)XzO-6jS*&lI zuJ`qIADY|V`KsU7HoUI{5UvF(`cqZShsx?V-pY@4^&hKS-?wxDMt<-1JS#UpF>9wy z_G!K0c5c>T_%b1M83_`|#jY+zFFK2&^cV_0oPv)i#0D27An z<;f9>yyRMVxH2nRjt!T2oToecXFQFM&7Mczx<@kOq{(qrUw+k4d&5|L-BEMHR&(86 zd&N?91#q#=bJ^yeu$5mfE5GO{zi6vE@2I#~3WPMc=sxf8oGq=Guz4n|KtFpf7|PC; zm7M_=SZ6HNbooSxn_f>Ow0mBZl&V~0Qm|~P4b-nqIGtBB!{)dK#buRCCY8ZwQ9Tz7edU9 z=j28*@L?tC%L!SLWL=hvy-tZ;R*(}?OpKwI#B+38bViKxu)EKgWv?o7f~p2Lk;7Qa zD=VN{tK7%?c|{52N6LCX4_F9T`Z@h-4rGn6PM3NwN+N z=C+YaNEkPDX-U#@Du`Q=aWZHy9c(*F31Yya0m%Z`l0fc?3<5JdR$7P{bTgpQYGk++ z8lg-JRYF3Auy6r9S`M}yLBplU6*@?q0Tv_zOBb`D6uH)u6s+00RJzSyw>`|0lu!%Z z&j3$_E3f$E@OV3KQT}}OGAf)SS z-F#z~iZQt!HM ztGe!}yZSISu?u*v4bETfMR@X(F=aQxT zqPhHvt^AVNJz*&WD867UJ8O5GHCj)aZGeK07|n|;Y%m_y=ntvYhg8}_O8HKud|WK( zmoj>l;$5z`2hHcc4cwXqu-)_I&)D?B*vy~72Y);7fbe;)=hl4REnt3s58s{}othiI z^Ly;>+&HkncjtE8TV&+H+jD(Wv%NQd10mgY{de2s@6O5JJy(BsT>ag>cmO#6?!PkI zcV({q%I~I&vyBtKQ84O$sZ}qPj!x$s*3luv>4}~hyG`JUL3`oUCP_6%?QlT4=KtHV^R}D zvNck9hWT{UunkvQUsz^_Ybpwzt!&@0puUCS?Nv67DO&o(bwkqTRz`Jwq1OymYc>ll zMeaS$aYN>QChn$(H_6L3V1e5E>x|+J}h33+)x2c zaBuZfBn29_MO6a93|Zd|+cJ)a9l*hk;*qDa(l6y_T`S7JOD=gRU_Iutr#XyiK5LrC zo{yrk$V8eb34FsXKru`*yLFN^WK}kyRU;|cHqX(#TS#a zU6a51Cx3NM{_edx+dVngap_mn#kn*;u&<4l8o&h0FU^mG2;w3^5E{e0<@B@gmG#YQb49`iM#Z9QP} z`_1Ay1r_siY;!_xj;U-!l2{m3`H1N>V=y_=0bm9f1a6JLu6_hctl=5J|MO#1zyuVam*!?J%gK$Snlj6TNsIa! zK$sLOWXAFt;WTZo_EP&u8KJB!-{~u{_p*Jhj2dr_d)VB#&)VIxlPi*^>xX5bvZYr?R89`k7a@`xjw@h%moGbXW-p_t3$l#l#?5fM2Bn0eku?6+B!72i06~H^97Xam%C# z<}X66v@?qb3!!cJjg{yPJ{qAtXS)x-t_;1xj$Y@+ZSZAosX-)|5YakxxGE!9j9;Ov zDm&BA_t0JYK;@b#t()QNr;P3!M(;JF=bE|xrnP3uTr+8@y6ULB=Js8)R$Z|I62jPToscx_oc;v%YE5ZamnfhaK2;)L*X)DgfBW=mjHgjfEcJ~gX6f-cFJNn zYP20SSQdk5V24%m-E!#;nP5oD0Nasv7(F+tj(h;TIePEUEa?H-PPT zOV@X2&kqnjJNkb+dw-hSzgug+YP=sL);Dz7Ga~Ia0e>ca+W>Aw1t!Lul~75AwYnKQ zU9B1TG7+oF5*DN{A#~om8Z!ImZZxuF^wm_Ci<}w?3Ik>o_ zx|{(G7DJaY5ea54Whf`D6>O71uCFY@fr42DYF!1OVB~6d`etutQZ;I&85SZ#g-HmJ zvg}nRyX9CH-Gouob3a}=^MX$t^*>T>ztfzpZwi5IgbN5XDA!&UrPz%r3G=5 z{WvN9f~4hw#hSD~C+S~8M4}@X(NmB)PRtxH!tJ2oc7gUXk9AETni9w#3DnP3wwDIa z2Xo^mTl*JV*B5gisBL_;bboVn|8VyFbc67!Z_d{C)71Dy@B5%|zGbPNk*K%v*faPI zov3I}W5-K_ni zZ8xUwed#|t+jQ=)Y5Z*#wi6Rtj9gj>y7$N+VrC2lv$&av47MRa{eY$AV58)aKrt)= zsA4fHm;zf~f?Sl2!nEaFfLu^DhXsTGnu7*v8(<2Ih?FB^K}aP9`yHSW8blm86sZAR z5K2J8q>H;AB2}PvgGf z+`sSc^Hx3eRA+{ns$p2{z1LoA?TF^M$QE2|I~CVW#1B%*L-?c-CjFg|J;G)U^Vkrn zF(P7)bD84;{+NUZnH%GL-l#${D&$YfxnpA1ghD*7fYDeyqLfcs^wS3Y6zqbt9Y8gI zOw0M~%=oCaf3aIX8Lb~J*3aqo8IyI&pqnr#M)lwUR}71k-I3w-L4UG?e8f;IL)U|f zAR+kA6y(YT4EV5C6Jg&S;>|!pqXLG7jcn{T5eB@>AURtv^j%30-6#XQT<{hh?0;i} zi^C6O1#fqzU`oP#3o!?Bf_GVB3(YLCzx{Wzqnk=BOx(vDPru;U2UZ)9q>8uuK`fIDJ&79qA%W5)ZbpU=% znXLw=huX5bnoTYMc%wP(g$3~Igy%UB(MB66DjSXVr&h~jK(Wd41XyT;{-IKFTO++8 z5nPoDFA3?jeELO+sl|2uL(!X`AiJu62M`AQ{tYGg{NTSY4g9Qs`!|%@n*+b<-~PLy z|7V?tw)zDuG!$QeEr7J9Yq7R#;au0k#qPz+y$jH6Lpyz;d#SSPXH7RW(o1#S@C84s z;DPqL2wKJS`;!j}YDz>&a#(G0*oCCf zI!fpzV!|UTsfEq$=gHqm^`i>glrkIi&tJ_j{GR<`hMjMv+fY4ku3Aj1S+dnGI%*be zk{pQR*5_&MDrR zQptG%%EdV-Iz`K?*H`DIoIJ-po0f1X$JX+u<->*ALECwE@rz&Lll`Gv#8DgZF&hbB zvWWCa#Xwo{N(Bo8W*s?n6G#*UXdfPSivqKS2aFBci;P~+3fUqESTl?731TfL$cqCCF3e^XNGM~DJ3{tok>C#7rVBk< zfZkVvJzgE|cR9rGN(ACg1mm8n2|j0p&m9r6M@8&0_$=X%h*%>m)`$=aG<4UpNwIuF zBcC$Df>=MUSHp){qi#m8nKha}+Dy|%%ecilZjerB`9o^Oh*<=CuTFPxD{R4LRrp zL0afqLeO#?Vnrf$T?%qF5wVsKvY873BOus7ZRCaSQldQs3(J2U_xN%SVuQl(H;_|m zC~@aveTyOv<)Zgy$6(Gx9?e1QvIlN81$nX~%n`_w5eKZk%cLOv4PVVl_O)l)o}Vlo zNY5GInMZWlLkioV)Yz*`@AS;P>FxTQ9%EjYF{@pl-C=gY{M%yilv=3Ht!7t;6+UFN z+gx1+7eKoW&<$nR>S{7MUmG)C8(|}CYcx4tSezh)er~ir)0rRZEl*752O1;jrJu;O zkCf6I0^toIuU^c##Anva&28pOA5Okrs_FaZ%KLu+yjR}+ePQUIOK&|S6_ntM{XZ`c z{%RQfcf;GCR|bAw9{3xu3`AC4-(qdg()q5%s?No8oeQ-c3$@*Dfb+So#p=$5>aGR& ze5q@(zIzd%4Y)qv4PX4TuKOnnHj?WYfveca^_Pb9GQe->#-B>5sY#1+4Z8|y_#-bkYzRA;l#WQog@cFT|}@S&^m5i1kIR!2(%B&INX>JC0( z8#58~&#R-^I~Zk*yy087&pYaFXV+wfIr#?}7qzf9s)RjnoxC_VKFb=Ubt3c{fBAVq zW*I;KqWUxx+%t?4O;oAEKRq)!r&3bO4$3d(U*|_ZJyX!#)H;)$J7~-2dy^z|V$(rE3HKZh&R++h5oEe_jFRxoh!k*Ft6IVriSZqJ6%s-CfnbP}Q|i z1rY9r0=;;?W8r+~;(2JZyP?@$y43YEbQ2pmXHdTcd+|Yh>*w*NN&VN#e7(fJtEIu- za{qM-km^MQmc}8gqW#LFj-SPa-=$F6*rK;e&4|)GuF05ExxQ-3zF8~2JF4f5HFM6I zAI@`bW7UGOZqZb?Xof0WzMwz#U7r3~WSk}Q#&Cqr$dG#>f0d&*X2x!^#_r4!C0we@ z>CzEzkb>)|Vb>UuH%0OFDSsJ5SJUu5oRn=6GxcO$*7>A^n&96PLf6n@ya?DoBAJIc zwkR8J4=-*VIeJ+B z`5`fF6VVZ=y_ZqeU@a{s7s|u)U8<|ddK zanl)hM)}wBw)uGar3f!Zgcm-_hk#iHz9! z24XgWxRDC>BILSM%tpw-QH5+(fYc$-OB%XciQFp1?1Y>vF!`#3*YeTe;@m8XJLZVk zZNMH$j|3n0CN+Ai76uvA?n1<&8jSDN2-JNb5TY#5h{6% zMjj`UhGE}CB)+GS`cjEKDe+w?vE9irUHF6^Vss}drkj+|!AkCvGW#{MA*XZFXdDO2 zgF-YRQ;x}0Z<)NNfb9iCN$9%ku*vnUBo(cQ#_Hi5gcC3qA7=SIB`ZTzF~Nu}pAU1#i=1wwe&zO>se|f;Os9 z>%_ojM{ZznF)q8Msigd^)!8et55WkmP9GMV2Njl1V@`+8)nU%*Q0KP72YpVfKDWz~ z*>1?}bmVrJ(%L;Uud7R+(GKO<44rm%k1@N`n%QDXZ?vX0+A>}kp$ca<=^ZcimRAPL zYm*gN=x2KK3!UYu+44-Kf3DL%lq>IvWOu~8D+1Of4*iDA+-|!tTlB(R(FOSZU%+qu zz(1Gz|GC%)BM`#%|A{qpM5wuQF7P;)u&+3^?F!s3`Zjp@q2Z@}%`loHsX}k#{x!68X3x=#K<& z4aBS?h5a6j-%iTHJG9|?{03sIH$fX@um$S1zJ@2oHIGhTsbv*Pj!I9lGp{SkvZK=q zQ(fi!lP0u@yH7~n&g3D)7nDUcocx={Q$_ruOipD5^Q{LrQ(Wt#DFt>f_m`^BLEsW3i_aH&bFa;$t_HqPM0-fgIYK8nJ~Qxs4sQ zO$6fJ!~;A?h6!Cy3f;`XY+^&*0ZJdcffljjKOWefB2Q$;ZdC{%ccUb9uPS0cBt)s9 z{RR>{Y^N;YL^^h>CJvDs=bM4vZouxggdfO7?Ku;E;!*_Sek}G;JoYfnn(ASU#Y36MNF$e<5V$U`*hFqb{XV~vS9qXNOWkT)R_ObNu(0>P|6I3-|D zF&SfY+Bls$MyHQb$WVeuQ;0*Use^>X!K9e}q`1L^*ik%g6qh(kBusHg(|Ft@K7Ndt zI6{jb7UJI<#3L5Vu+cKAR*wUftx~)fNxD+;&#?y!&^t}Y70JOXaOl;^!G9(PtVn@e z2#?O{chJ?dAk+&3tc$l06lK91VNE7RtmU3q#zk(`#|IU}`4yse+e7xdl8{A+-A>@5 zk(*5?)@smujQH^403Rjjy^+fqp{p5GY_84Jbh5ZlYwJ-v-ie@v&KT#|2KCN9ZJLLL z*5!3-v)Z)T9l#9hGP_M#ZN`jtLsq9XyTh2#Q#gj+a{V3!~++&h*4!e5TPomg}D?HTUI;I}+(Fp`by?yvXL< zRoQzimp!@%EH2L5gsgyqpcFyz+u{sgMIu5Zaxi2HtC==*uCf9clXuj_;V zzA^Cg#voAEKQDT|W)XPla!(a@m$fYde$TYdpKf)ZZdoXAahJBtRkXP)I{?n}m2K{G zZEm!eho=fy!wK+~`LCDydr1Q}D1z2&1H9CM>*T@fRDoVf^iF5gv4Tk7vefXhL_`fC z`VOB3_#IFh#}sMP>a1B!{ukq^udp++Rev|u!2W2#^R8P0{F*K;rq#JK%jYvreY0eI zu-K*{A&p7yhzhxd-Cu;+o*TL~J7!lA?&ui@=Wbbghn4x1iM~X|+>j^U(}U3X*n!Grhw)azW%8;5gPQ~Evs*`ltbH#xc>!V4GeLjrMc zxDWKwo>@3-Gb_X!CSP{QE@sFk2IL_CDIK~IWR^@2UxB0~Rl-`Qswqlt?r! zlz!xhW`v?CI%|~6o}kkvsMK*XWdx5KVvz=5YfQuqB_>ReaAWkOX==&`4(+pu^g&LW zHFLk3cwbZuc)rR~KeCC_JmR>H{a&pdHX4THs&S2aRH1@=k4}8Ttp#fi;N;&R>Yu1fd#oix3v*AXfwDV9*8u3hb5}xc45mFl2RG0l%5;0AY1nvksQR&Ns&N zW(zRV>92LpCNtTmB-4Ny{jKrchVUGhx9Z+|ts zUAor4cooLs{>2+_7vZnN@~EbJv9trWy^Cks-DNF+;)OHK^QFyhz;clX&hFCYg^HGW zpis~ogu!cgAeBe@NCMVtPOQ`f_!xZG>HIh7{MV|3)+&%&?U9FbWBf{zkY|&SwUmSh ze0Hl`IjFacY0_rYu36j3FZ$B2rm}CAsvp+sIZO4twa#s>^C+Lw&d+CFaA#Hg$S(Qn z%KK7$=EIrNF_WyDl=v|6NO`bN8gioxyDdNdKruVG#wC4m*4ZIRyvM*^r$*dUCDsxT zIO4qdVk1Y;isYppVfxPp?d}4 z>p_)Gz;5u&cVXZn1crPI2kb>?(4(#)1*{^1NCPNn@XBF8m;pggUK|uG*4J^+5Q?>3 zj`5bDx5+|x8^RBmgV%{6CK~I-NjPrA1>}eBwL=t7*da&YMm=VCdg!6DsK86HnEQ$0 z&*Gw9B}TWzMz=-Bba=+z#9mxNFA)zN?*N`K#GwwbsqbloQ69)PfS%${c&e>nN+z9= zDQBg!8Ma`S&!3_*CwNeHSz`pkNHT6HCFwm8_YRLArI035iL)umv&^KABI;Ki?Yo8Z z&A|AcF8<+={BZETYngLq);AOTtC{y%M;kZrhm8<+ryVt!#+3T^Vqu?v(;khiM6IF% zezEHa=yfTmRY|DT$(T)iu&H`-4A#+tR)95?8Q{eMEhT1$)^{a0a3uq=UW-1QLk}y% zz^|;`=_Ksw@PjVYP6uX(6}w#@v_(q@$p>)@EJ{!-8PGp7F!?#@ZQ1!9CdYu$@t$uS z(PfSBjKebfpvvBE%Iq>^b%BIKp9A>q@pRD{?K;4+tKIBsGr}J;JK+J0n=;xA=`Fg< zW@B2DA+1U403lYh$$44m`T{-5=I zzv}ycUhiMH+P4Tz^%bbd0|4ZuD{ny&y;R!`{1r^T&^Eg(Iu^>H7Pq-iw=bM-SuAOV zHvoAFyAi@n1PCu-&>Crg7pM*tL0($aW<%g+aD|(Ly!3%yTI3c>(uusdfZ}9CIT2IG zz&#eSTjZ)iXofZEQ^xEW{mIXk5?CI61KCwt^}Md;ySZjw5BwE$(dQQ|pyDW-x1Ic+ zd+OumQzMtmP5IJSIm%{1{B_LkeDvll^!D7Sy(bg@DpMymWJ?=!)Q!T(YvhRg!mv6% zA|JO~Av$bM-6g9~oXp@BC-0C3{*LqiJvL$mG3<{7=3m_0xHR%Uk??>#aWlgeXO--h zD$wGVbC(*jFI8|$Y{B}}jj3SU*959m{t6vdQza;@pclB}o!Vdn?}S2hl*c`))}tKG z82fE=tgy-o@LNl`^9o5ADb#cWk$_nN}?8ZaQWS_aM$4sxe1d`}h#nZl3cM;*-y-eeB{D=+L=bu<)T z%+tv5ri2*S^L8c1cj4nZ661SPQ+jd9eU#+h)a3U>!Vrt`o`f5wr+Qc^fq0n9pOi{x z`O*(c%}1&1BVRVnhVAE{%bhCUV_klM%aLy_#Ng8 zIrgtidUOSHyDjWU0S;LLJ74rRBXWxpz14(0U``6o^IHYEVW7{XL~dkJQF&RJtta!k zOr{RKeUJ^!ylaSQ91&Xvm5v^jvrC)ZZOrY4_kR{iU8bB4OF@?|x67Cb!*7cr9rj19 zYUrplTcLl}r8R?>(2&+_0|{1otJdDEH#VwlZ=iG5TN+^;Hke;&%2yNHlns$f;O0gH(QZDrXVjJYI|Dvq5Npy zlgY^PBXOCZ zCWYP-#od&LSCRj+QFclbyx7_(YZ<375gaa?DFJ`RMXbby{+<-I4sXTk#C|5iMjl}g zJ3r1rUW4Zzr#IJJyz07K#5l>>&r9(ksE)}j5yn%v^a^%v2_eUXv>329QGkxNlS1A? z6(G#{$%O^U8CPVb<%o-)fcgtxlS1!DJ)iNs8KTg2bQj!`d_2Xpb6h+4c%`=!T!z@+s+R=V#n-F!yHHpKb8}IB0FfS1HCH` zb)+sL=yp{2iOjAB55wk!(gR|0Gm>7D+!axl?rdB$Yavf*TPHXkVSW?@rSXyW@Ltk^5xHd=W5s>GOrB-DTzO^L6g>N_T$RS3P~w$Qd(<-x*c! z4CZmYc1$WBR7hIlu~n$$bnF^DdKDhI0^(fozyJh-Wy1>uDkM;9omhs4?4aO{62vA& zz-kEo;-c5fu!qv9(WOCKZ4kK@eYi06Kpxu15V%Hy-fKbcHYFmm5vzsZeLyXzMtHF) z*wUPWj{Lk%jk?K_K1kIMsndt(`u8%+pvK;-PV2JfbsF-z%{ko$SC2Ng$CA|oycSSc zT4%d9qg$QcZO`h`Ibo>;9e68r(Z=*9owXT+&>GuosKVe&(%PEzme*R#bEBV z->40*p!jMG&rIfLTHRxb64H2XO1TXT_5-=2$8dJqdV4+>!rMFlsqTTw`}f7(e^+%c zf$a!%(KUUb#PGDxfL|!DS9&~q-b+0T^?eH$dzJvj4FKeR7>yUN_PZPU7q9g}JH2qV z*L}Vhz`Ib_1rLzVfapbdKqCzy4-n~z*&+ii5MsRou~Cik(V;h)&|7WDEmp*O6Jmol zbdMwENLGw*ZYs7E5|%iG$4X(VO7m7_nJ_q~b@?AuCqL`|U*;qzH_px3s@%4kInzbA zSQU9O)uO#D>$~r3+jPR2?C5bPx?w}fUz%{FTAXkv zTiKE!YnI~f%5V?FA(d=DSLz-KZnp@(U#1VX#%*CGZe?Ru;zCv>g{>e&tWFmANx|ov z?9HJ3#j_&x_PV!;8i;E>3I(G{kogCaUF#bpXh7Y7+-5S|laC2S+7 z?qX!(b21|{b7C!UHsuVzCQsI)w|=CFK2n&I)YNy>_}0_4lTCx)Ywx@h${)mIs&TQ` z=y5lc%2$Q;LlxKGCM9P<999$@ZCOLW`oJa~nq(HZLIPG2e1A*w10}PM)X!TUv{roL z4~pLkNU9Vdx9VVpgxI8l!wNvigu@Rf{LWlK3j)vAdVUHrJ^COZ+7aiQ8wJsehw?-B zmqY|#k3v02jA@CF=}e62Nl55RB@D(T3=$LHQOR!!gm+}ZJ1S|InmR_Ij5Ao{eAc8$ zFs@Wgs@2m9#gtS6o%5_p{ZS;IVK64i^f5AiGzm9Kz)ukIGc??EO8jhc#D}Dq4-EWg zF8-5(_CZ7coG$xTl>Y5}>6iNI?=@vVZeRX>uHwhDhwi)g7au-x-@LbQws77g{G_E# zsM#ZW`CFyxy-qtJk&N)g{cOf-#IAHm^F}U%{uv(z@tf;FxWWp8)Fw|j7~X#c4rFPN zOArXDK|V?t;!qnT=zZ2i)F~j_A*?v!P*&{0g5V8CkFC;26?)tmb38q8730{yi13>s z%$r9IDJ#rxFUjo|NSd6kLAqu@Wgn(%M+KJm8fUl6(XGkp1;By?3lOT$?9!#R!@}2* z-KouJGkTim4ju5%nH?IKi__j{oNsKdH%dpd(eX-WZw3p4(eYYseWSHD8ci?F&R04| zlh)j%fj|J;YmL59X?UhkKaj{DC}sC#{99uFJ(01?P&#hC`6KuFF9?>b?DbfRz!(Ue zGjz_CfZy(=s_sSjT-^mb+(qc6fk_5DUg%l4(7RaQv(V7zzS6gNrFWsBfBr`Q!VQ3M z|H8H2dHCz~y$hFn-SyoImwP-iE!YCXKO4Lrq7Q_ia}M6%X`T@qwZR(BJ z1bABm*TeAzXV`&UJgSg_ETTnS5|bXO0KeKnm1WA50pWF@LA+tC@a%t$6?68pVEg?6 z5Y|^M+0QT8Y8IU}p8c<;@VhAeE9{S$f)Q$RClz&viN1VV@i5ok$%wiV{#QxZp0b3a zHN@a+7W(T`nl3Z#m63Kw8d*jC%M1z6w1b}8M#SCX@YRH{HN;p5yVyWUfFy8l0_(7V zc~F+@LzVc;~_|g%Z#K?`(ARnp6EWB2T-ld5=VnyvT1pP@0_>CI8ij6}-O1U-kh$}8QFXBiR ztbM}|L-D;I3EQIBw%GXol%!rfp)ZB}J}GGchkJ)34wH#P6yh)xUlx6u!x(3CCIP=( z&Xmj}iJXzCrX|W5zIawFoMN#j$)qVVeu97>CF6$)@e_=MadPAsF?up3YAQ8hnoIb= zCeBJpvx1b50O3r*r*zJYi#KypK3gjLRHXh~pZ@*U$!}LqeZ5}#y)x^IlmAgqnN(9e zCzG`5L4{&WES*rRho!QaZ0YTSy4N|C1cD zfyIcdNON@*q_wko&oi>$F_c3Z=X;iRm}`2kcXTW5F#PswvZ0Iaf@xQm;VHY;>~;+h z(V6X9M~gADUGMBLq<7gt>0xcs!L(~{GFcl{=9duM0kSKty~${MW3)r?&Pz|twKrNU zZ#0G`HAL}13$1&l)jd=k_eZR=2Wav8o58Rtp!p<}UXvT zyKueF1LSK^th*Pl_CQevnbs28ON!Va4FKlE8_pi7f_=1zjfUWDcFYzlW)m=IlY(`)aU;PNxQ zUlu3c&5?H(nELI!7pmk-q}|5wHFWWDZQ^c80yNL?tNV|HxNUU&UIG1>5WkKBpbZ^hs-uH8j-CwS~nsDU3 ziu5Z@46TnjUIAf`HrvZ9cl#BY*U_t!Lf3ktJ3&(fu@Zh@30a*CE#mQ2Jj8BY@KznD zd?EMAcNrK4Ve=~t@RnjX$r0!{7kWi2@v^B}~eh7yfArgjDQ%A^T=$yy7jA<5UipiYf zF{ee`DXC&sshE{3XN0m@j%1oj9;K$drKAkfQ~HUqUAVBO=)lGZzn4*guM&`LvDlu( z@IGQpKP9>!AKjZ8(?yDcr;`%doEqIsi*BQYbuyv{#VI2S@}!rd@GbAuU@@l=GBkdj?(_uK zfu0!%D_HFQXZQv1{sc=As5NRj7c1N0y>tPDRlQJ=J#5t_sI6TK^*!!ueeUbMKy58F zymdn@zV&tysxY7!+U)DlX~U%4vj|Sr!1dDL^-9EgNIL|oN{iYGC(N9|+igKUc7%^L z*vEnNv0?XRhaD_P^es*et!5LSNck-~{eTJZ>zp#=&Kioo*h+uEog>gc+kkwooCg#` z?4-FG{0nYt^@1Aa-;#N;>xaEZGbbGLxzlgjX+@Q?B@X^U!<#f7xOJY2Rl#GZxA&Lb4)kY)o~%ihnU?_^4XG$o9p zbE0BcB(e4h8HaefNDc3ZBz1>C8GF_#zMmm%P*ZN2G_AGuqpgp}-ZV}<>-qsDxUQiu zIl3|qU5AUijz^t`hQyivs{ZNQB*v-0|49g50g7KZAqNyIWJ*AQCovEXVH|K^x2lf+ zi+o}k4YY!Ot2ur!1A0qQK63O9Jr?f!9LqYkT6W~WQcwJgbYi)HfISttKP}=!E-|tq z?9fTnt|H8dhDhx5*s!LA#Gd4Yx0KYk6zVXJI)o#P5J@Ar6nMh|ca%n*V6tX-{23-^ zMl6_-il#-PS-JcJPx3*anB_?)afHD{)U#yNjR^m{h(lMA`|ADo)d&4`D+rALC!U~= zKMxIl6^d?73~vuZybKR|8s_&18*m46s2*|XCi?iJ(14fGA>9e#!^u%Ygt&LOs6Ha< z1sU~-=zEV8@>G!8%pH!nIi?YjWk6+y;kQo@OQMsVmb@-) zW(QPZO-46x&Po7pdIvnlG$_RF7HhNB{zheOvO3@Boo}o*kV?MRTS0u)Y;ZJcO>cCT zS2|Cc7I0Z_bkiFo`#L>TxN%CJ5;QQHbc z5%mR%7kcs?Tu@ES(Yge`D~!lHPR@%0W1p3MmvkU4b{#!p1)01p;AMnpix zSr3MN{IUNcAV3CrG&^tw^Th9De-HIa2YZOe_PbREwI+0r1-s84aU|Q5%Kit{?{|vt z3L!Q6bo8;D$P*_S(N&oJr?C4)0&qyAAqs7j%NoZMhGF}Yf`bL_ zcnWcxN}Hn4r`L<5JDM6F3dr;sc05EF_7 zMb;{ii&HQ@9ONp9?<0a73zF90f)92RJ9M8eY@Zb_=!GB3gkyOj2W;4b8Ib4>vdO@; zk`rE#=?67Ma^erN?|-ER{VO$mhr%p>keA z0A84a!Sb(%vTJ?@{FU1B3f8^~Ym?m2q=7&@bE8uKLZy1FQrwjbZwdtWr0Pah-jMp@ z2g~h+^ruVNZ+@L>{RL+H+DP8({#xJM)m{MX+^zn3XrymKQ{Cgf+vkQ4*ZLN2_PcMqbz`@ikX!T!ADzFK zI(V}YZuR1_xCdSds%|EWMKB^ha4)539Mw{?@Kss8r6WoHfnH9 zSqf%Ng`aGvzF8r*z3jX7%#U<9cvL=bsaOE#g7xB}y=uu?wWum~D_mdM=Fe2|L_86G zJf4IeJ{!I}J7i0C)cz7dd_$J@r8wb6qW^{H6IXHQn~cbZX5pI*;X}r;^r&@=s6R;| z%W$R;BO_Ro&n#pgR)?=mrR?P=?W7TRbIH4ei9QtE#?;iUWadr|buYV!nOT&Oqe43} zlJafQX&SUi9-tK+k@5EMxPkIqO0ETCBX4GrchPfWEIARjD$&VmLGdYGNl9v!_Nb5> z>@us`94S{biD%1f_wF|g+cHU(41<=?+> zwTGszJ^KH}`u-~};P(XoW%!_#DbVa8_hp3~&4Ck{uuk$@!9M;+YT$a2?^+>PdNHu} zJ)8l{qmaF6fy26i;)d0PXQ4 z;y`q4Z%kreGGP!$c~7Igr_qO4ykU`On8qGq@JHy}5ej3J!WhAmN64uo9NGwhI6{O; zIe9oGVK6miOvspJQ)cASDV_3zfICHj?mh7xg)qus43P;PG1&V_sC$gm7NuZ7r+lvz zcQaESpx5%Ts|i3vV^-r45DT_}fms80C`j0KG=MOy+h8XivPT_x*oN5x_;sN6r9~Xg z!Tgm8XBS|77PvtjxKWATZ2^hk(f>&b{DX}8Gd1QfqeK5Zr?6MWZICnXka0H!%1)lC zpJo^m7zeq!e#p|%XZ7fEdyTFx4Hy|<5uDkjwL|6Y)I-^|H|ZR$9!kpEuC%qApe440 zTC&w(e{FR(>Fv!LN2?LO#?)xB!U`Dnzb_!;9nvfn`qvtBvkHo`;gv@BLZ*5mRy>l5 zA$R(gMD|pd`&L);(Q;!x{n1j+i=QW3eicEgBzT2j1cv<)K=?mqKp1;r7B21Z_yIwr z0ljox=hC?jfUx@lG|%0O^&Za3Q*EK<-t3#d)wggRYAztxQ+Yk_JO4p(*e*MAqXpp& zscZTG9}{}JEqJQ~wIdz7Cj+(BiQNW&*MZz(LvM3o_vS<$D^5mLac~dC%r>RG-(()q zWK3IgW^}n#e&mwAO2uA`4Z55Vcq0XMUy}O5$-2u8%t_uUOxnbY z`Yn-uNN|c-Sj;M>9acfGf9f7y(q=kkFPF53o3fFK+es1~7BF_P>H9^+ge-laMUQnF z;R!N`k1IXJ_mGUfSCpQTnI7Yy>;hReop(Y8*BR2|(=Vt>E6kN8oPva{$;f{pk?V1s zxLRuH4Sw>?GuF2A=SLnrpL%w0=;rOw>#u**KbWq$J(McA8HK7!iMSAVq=J-iMQ?c4 zaKA4y$%$AVi(Z)+@LPP)pGk;y{FspH7<4J590x38fKl%F3UZ*ABygPw&~@!u)P-|)#N><(*lVNtJ)eM`Z+kBhEniCcNfKAL%m zt$WAS3`&eJ=k}>`dhJ;~+RQ#M8EJrX&VaVLTa(tVb96%U48<45Tb->s@~4{YepAJi^VXdH;X>xKB^TT_YJx#{sT$zf{i_D9m;q)xm(D^?9mL~+pSSZD z7!v^0@Icf?P5b;s@E>(8T=Q?=BP4F)#QIQp$0WpkJi=B6Z68y5Tuk4|5dAB~6Gg}5XB1`U6_uwM`L&L7b&gs_pe5)J3~CuV z_|N#%<7q1L4U@2?AhY*&`I`%Qk58NLm)M`yUwL=o=1~2Up>wwe5>hTFN7g1|YYA95 zKzXAe`(4wv-rIof=vjaiS{p_}wtX3t~)LTvT^*+&dcn zJvDWRM3_h=j+3b)6w(-jGDV|L@%RAVSw3e9&01pC0T8*kC<4WPUQZ@m$L5p?DRexRS)VP%U$d*`a?XFNelmCCmAm4`d_mQZLWqgZ|9+ zYm3I#Vsy5EQ_0|LHrtxD4p3gTfP_P5d;{|@#L|LM7IpAGQYz_GdrSU;WB{{R^@(&bBX|?SSOTCAj}v+U2PH>>>-3 zP?dt@`$9&uUf!oO4I7+O@ITj(_f-q}=i+aWqGKq9;`_~9?lx7rGtSPZU2vPKmh@FW z<);^vIX{@DPb}F)GG!nl;yLzMC1Oin(Dsud`%cCFRT_V+T9kOFME6EZdqj)8nuNa3 zBQ|Oo_m$W)$s2`|qgI7~hQQB~htGDV=5Ty95o^gw81t6&xtF;8B! zUpQ%c$mBjcvYK`H|Ab;7-1QGq!cnu5cHJSoZJ?hQ#8$IoYfOT>g=w$O7IoIuy={0p zTzt7F9D6P`p)UHwSt7ccLTISD)I~R6_5JVIfMv1%zsCoxB1If@gzT~+*D(XuF#T6i z{gyL**N8#G5a7i}Z_|Vwv|{&K!I2cOf_35#n*Z-K|5YMJTm><#k`!H&il{{&s1EhJ z6M=q#kLiey?N3R5mz+4lqP)kYjN((rXrys44N<5drkdh&rv=;@sc?!foZ$&R2>G*o z(FY!98o_3s z9M`DeuIQx6GHJ6;IWuM<$o)+9x66;`?!1|AZ2R%_{+ByfzTJH^_p*JV{;B)ogZaAK zUu&*FSoDluKBN>3s)a*3!JtYwpb!oS8BH;VT!`h#=#_-vRfG_rt+rC4x5G^<0(8`< zH7Ow=It6#(c3H$e3kaS=59Y@F1wV?`umfp9TQr#MTEupp?|Oyb3YI70AyYS$(>k9&JXCI=#=3-DApz z;@hK5>oR0^>22+52&=TVXl>0JTdT$K+G1@@T<{70D5sIDY?se4rPHj>zMMoS{XQGoq>~VQ1C! zdZ+P8Np4$3ap#p=gAFg_9lyW8{B=|#;~--xHz!)_K|V#D7azDe{>oI{1}5ULL!cHsFNJl6pu3{U`z|xAI0L2 zBK`;HmI0?Q{BoGHEH(_n(|~9he_AG*k;!M&>KUzaQYM{N%BN+rDTQW6Zwc=FA#3!wT_`QaqxUz1Iu-G|~Yvvy+u@J#+&Txsm`5?vS;FP;h{* zgM-M)!7JgU1t}8TSQ~}W+vTx)Wg&lMMjXkHKJ3Eow8M$&6RVZT9Xb&Ag4_i%#Qfpz z&%X!|-6sea2hzLguhHTG^xw#Rv7&Frz} z_SmvIj2T_Vv`$?{mnySc=jt}t+YR_WF18{U!U8 zpO&XTUC(~zyjp@7*fZ_F&a?wgA>r9`4!FEy5so!Lw$<4VSRpN(>wu;j3=0btaH+7v zUEA^Fa@Sl#muCvT**kZw+kLHj;Y#N`l---qIm1NUJ%6WX9dSnM~P7m}>!){9lIt#fu9lJL_>iB6wNFANiRMu$SQ{ zYJzqYqV^QR^_=kI72yYKV~$)Tqpzm18*{ZC(&W3$*xPFQ3r%!&f{&8AO_j1qW(;y< zL>CqdD+}2r5#F@O<%Eb;Bz}ktx1Yf|AjNNDCT^w)4oDNX(1ig??mQgpUdbh=nrQ7Nm`1~^mvEGN^S5Tk0sefR;(NJm#t zL$}F;L4?0nkbEqQ7E!^9xu~W#m{m^;(q5MrbyU^$*FPG$_~1QJ^(Z{>9E4-X_@5(& z*JL;zmtJcR3Qz|vj}7_*=Q;Shf&!_hNNEDnL{xmtVIRR27Fi6=q)22#GvS zqmELE-~oiI$}=3sG>0`U6nx-wXGOw~P>aDKsFY0c`7;vXlt?no6U>4NO9^rgm|nFX z)aqHSYDTU5sMgGC4bw*ZN40Los2>M2pjtZtj~I_%^ZDDa<}W_{R(t#F>AKGu1+!LAQOe)xlp_YkkU=yc7Y@io z-6HC%2uPv>mH27`gqQ&%jq#!&*MRSXf>?zE7At&*IA)JF)JGV3G&?TvG-kgGy~7lC zC^Nv@g4$_7Y=+HVBH` z9mhBT6c%iOVIb9I_o$t{`ivgEs}nr?mW)o2J)6=y)M=esE9AYmDIHxVd%M{NP?`ceB%*sSYBz(jdJrFnf9eb_fn>OB#}Q9OYca< z57f3!ZP|#f;j8nJ+xB$H{Pf?p$3LCVf9As_g_flfNRRAZf-7cl{})DJ5I_R?e6Afb zHx_FFyx`VvpRev%JlpE7ZlAl@9qM`PFL{G9L#}y#O^}$&g_8AuE34f053CQvkmfivgEs=aL!o#!vbf!%OJ>ZDgFGCq57w>bWvSA5BVD` z%O{F>0!QkD{ZUi^)ZhHz?S;raMWIJ3BahX@2Grw_H+V7k^W?4Bigpn!sz^6=iFK5H zdi-V~ew$cv%&73SlyJ^gX{)&?z2|(G50!e94L}tB@k98Qwti>tBb^yg|sutTLmfmlvc($Wl|;K zkP)+07PZTG{C|?6mj=ITh>tj7pMirea9JN_=5-a=-V|hYovrM@a`j#P)1eCuy|D@B z6QeIA1Xcp#*u*PUm)abaFVTA#0l&q9&=<9q1eTe=)nvbAslIDD$Cq)AuVnbI6Z~J2 z-ZChzglQZ8^V};*Hg3BccQ=AFz%YUg&M?Ca3}e{1y9@44(1f^boCFAQ!AS@S3BfhN zVfTLD_xt(v*{AB%)B&nel}eiKzWNex$YnUFa^EKQ+`@FLj^*`!i2rjUFkKhG{z&5yen4I%h7$JD?SMgT{7DTZT1Ik zYPTX4*?%?ZZ6+XWfMyUnFOaWn%_?h)%Gd&cGl=w6_BO~OghP@RO4#&Ds)mCvAkVL% zgcUkyyRYGvq=qTl@LZ~YA<;fpXrGGIP{K$T<_RAQ`3+Kio2Kxa>iT!}qeWBwlHtie z=7ztMpZt^dVi~qz@SOvYxu$Iyrf3NAE@@dRZAMBM>AbB_!iyCxpf*A(y0T^Nd^>Ex z^EW$@`57)p*V?DA1ESS6f4yVzZpZxXj(M1(p(=e&rgxM51m*c--R?8?t2|vgNIkh`XA=YLB%F|`Jq_pLOA2`B z)DbBWNBH3fAnc45^d~8F3n}=|=)^NZ>LD)AS;9QZ<2nemXqE7clmwSs~>FBUic_2Mhj ze8Xui$#Vk*NLk>AkKRH%9>iV3A^LZuqlYRA>8aj9}dZcUh;!Bpk7 znFmj2Z#T|ftDm{rFkN(MG9`D+Y#B0WzA0s2RI+aXXiF2m^5Z{ql0Gn^p5gYYK&a)v z4V(=i^^)wp2~jtoHv_wa1V^QSlN$fsBFrI05UR-kbUN7C`JG9{?Kh(SRD12$yKELY zZ-{qUMRNT)6#EBH#J-b#?tMY}Tbb;sm~kc2J154!f);g$Eo)EIf8wY<$4Ea)jPE5# z{eIM>b?Z{!t5QID)DA2xb4t6;+OD>M&1{<%W@anWeB~Adf``d&^(udmO=YcqJANfH}VC*g>F!4->3?|>Ml+h>*h`M zi!eVM8<&lZOR3M6GhZziyaqGaf5&FTPjVR`Xz+7B*9zJ|kmrLv`(k-3!sV!GU#vhz z=!L88&~WFj17OvO^xtbx$WXami+8%_?{+Le38T;C;LqfGABBZC6$cmI6S=q(dDs&< z_(SPlhqKWKlTrID?!SYU(1<>g8Hy^6!rfw!o{3?8mi0h*x5hTCO`DKs{D5phMLrDA zGupyA8I*9@qOKe$9LvcUfW`4&W%-h_U{+|KiPHmq)lZFmAMD$JKU;-8T7Wr{NjRMs z>{1rsej&{3O1SrRGVTt|ug(zrHdoP=uIl6m-(sJ(25gRv*crz?C03vei~~YFN|#H_ zKF2Fcj?0fa$tN9T6E;VN{y`4g5ko)1k2@ufJI+lwmW1$`LkxP1L4!9G#blJlrx%A> zIA?{olFLhD3UgVR*DN)K+)|~tIr<=%dQ2JbnjU#V#ljX+eaflMSy6{20ekonC*?rX zMXkXSHW4F_2{O5t%#x;5aecn&Sy^6d@wuLg8@<)nx`Tqwll-cJoX$}_FNkEXF5LL| z*Q>8|VL8~Cqv7JYkqUmZgq>{s9=iX|xWEJPgoE)xC&U5!M1=i_pN#LeMBMMugdOxq zH;agRfe~2EAY2Y~y%vUf6zTVr6x19|>|jzp#zuW+M17)1_p)L^`q#&xgXv9w5@U!L zH^hfN%NY@H#}WX!N*LoOj`I1#67H}>IHHh@OQqu~s8h|94nDOL1}*Zb){mRb6Gro- z&N2ZO?rPnrTs^GS4QsW-8ug$|0gZTADjgI6(j^^MXvdP1r%EqQ-)fw_`f#eCXbkGN z?8=W@O*6M2{kZb*$IVCIE3QmsLe#I44yYAQsAbz-%Ipe5@V+} z{i8AGqbjA#fDoa(;2dm7YnNGJ=WW#ibHm)CfuoYOT>|%4)KJJqU~arp znqdEhak?3b8tKc3q5&R+KPgf@mnvRJ)lcQ}$2?)3RQM3?O3JLy>WgEh`*X&IW$lxH z4E4*Fh9&dUrPSxkd9Rni6{q}P*cpyT|IW{g;C5B=Zn3Nx#%5@{0A9g5yl}n^40Dz) zwl7?4p99$HN+(jw*SqJSeqr;y{eJ#VCydaG1c$sJc)(ucRJQ-wtbnt*{-+C(=V+eK z;an(c^x_u9{(?nLQT=hk27*W_qwW$;8Oz_{BmgoMEK?+0B zoVIkvTt06)w`8eYG*ta1BeBF2 zNuD52Sncn>lPM$@7!z+Qs8=j;w^F4KOVgee6?R^{0~V$)gT2aQ!Yr zZ_MQ=-}5B&C0~b&{+JpO&&HIz(*QV9{Pa7A>#J(nI97vA9##rR%8R=nBEVp zJGW8&{-l6(8V?Eb8;STWB*q2*;+un4>^WLYqL`S zN^fpf>))tM%~E5l*7!zgey7oa5yw-R_PJX1LIOQn(;ybtDWwnjqQ^q%Q(g8)Rr#3t z_N=~s(bx$4@3OIeS>Lpj(e!uPGnk?mOPXQx{Ts-WRj>}XE!VUyoNHbJKaHxE#cJ@Z zYg>Se61>0_7>LmS>Kf**0WS-r4W08>+7_+@3f(aW`1AeFMeK<}EM%&l%Jw-3J8uT= zM7}q$$q@i%20O6YOF6VJa zif~8sp;CNd`SrX2{t^U_>mlCvqi~N{0Z$S_o>>##rLiBy9MR*~M&Q;&CORu69tO%W z3Hy+Qy*nvrLri+Ou1a-I;Aal{lSbGSLEg<2IVjX_8v362RJ<~UU?_{V=hMh$3piji*#)p(}gR6K!7YwntvJ6e-m0guLdZW1yKwnApzZf5U zRmiN%Pj7kHF`9d$9eap_-w=-99Etmr3Vp{1vTnDtF}s*Shk0OmhlTnDN-(%mfJx)V z*f5_I3HwGAzA_9|gE@04z~fG+->dMz=BThvQuxOh;-^UBS8`-8B?6QS--?|^y?oSn8oXRSO92Ue~R;T%<1$$EA7rCHUkkG@8@8q*v*^FkQ zcO^t2Lx2T(D+RSS3btU(783UNNZ&um_?;a8eM0>;!JA2RoC zeB3D=sHeTw(Y;oXDVV%u>&yJ|PX^gDovJB`dLb59h}|X&a7bgtJr`)YB)aYd^+%z$ zm#+i;(FYCCqEfom$sG!Nmk!`)0Hy8i8fypKf;Av&uyra;unxBXsY7k<(CFW)5VbGN z)o>JkqeCF*W;pvQpi>(Wnl#wys7&z9r)nLH&`$w{1|vJMyg?v*C{a9dXuj0|TeZwrw8AYI zp>Tlt25_+e!m4eb18Kvhj`>S%vlrnm+zz<(?46D|XvFx#x%e|#{%3QrC-Z!c6?z}e z!Jf|dIbDoBk`E0Ry(h(Umlb=+jz0!|yxGBL3xizFQ^FfL^k#wRvrOBsG!N@CC*+w^ zx`H2y{O{(%8CfB)un;b#v0?#MV13Q9zUFV`xn(8nzqaoT#aOIxAcFFq;QJJRrV4ko z0DYjy?@UR6Q-!}rZGgv(0MxB8?|YPhh9vS6M#zhVi05Klb=V$>-#RjGBbDc@Rrpx> z?mE_K1$l2`$i}Fkt&tg_*386GF4`EpgHGMU7J4Z3SX0~)zQ#kQbd#xkqy_XeyN^ka z*IXCpW)V`$m8EsI%bDRB7ZhdX;?khKG?$hBUR#Nn-xGXRMYDoSOx7V$$yb5snag^% z{dqLK~5w(D=DZdA*5DL`zu9WmzNJgJa2;|ZbXsq zMEYK1hToQR>aO1Heb7BF)ZcPn6%4#A*HvN8Yr@>uLE1%}|DgomLkX^%VHajQZ)7_B z7VWY!+I3Y76_YAp-X{Cj5L|08r!V=T8iRb_MFh8n1$9LPcZWyx5Q(2-$-QJsUlce- zM)grC{fYF!IOY(CJrd6v<|YF93MpOze~c>}mWzkP5(HsZt477raf5CW?nFB6gbAG3 zHKQt6exd)`Cm}gSt)J8z#&yO~rG7-M7*HeErC}LwKp5AT5c@TrHo%A;WHSci_`_P+ zAUCd85%)ROG*DhS`B&YK+mF6qemH&c_V=<2lc@!h$r)p2BMHA(=0WKcH6Q!ml++1Sl&%sw%Xd7Gzb z5$U@G+HS6gPhRZiGb3!c5t*qW@+;~l^KAn zW~2F)$@&U78z#^%KpL7J4#drBI2&2tg8zm}|6K7eqY~(pO5IC^=9ygi94J^KX`M{^ zK)|b$8{3pcgSuNkOpg|c{=bINU zwk|;ZRqx2Mo^(FgZizUjG19JPU;k1dq$D^VeEuZ?(??7Yl!^7=NbF z_f)RWp#towLd@|z%)va&p=|7tEbO67w>>FdJMHNG7VMF9+);3J$tE~fh50veVw(km z&wy-5;Ga8nQkC@`>@{=+GrIgA+M*eA$&9XKPF=bPw(b8~xc{RrUzX?332oC%`2EygU9!<$k7(AlZxh`U^vJFx6*Jcf~fl#<;>ioq%wJcnSPY3M{Bj7Dv_&#cUl;~ zCtivXUl8S6eT)ic@#VP8e0p~Mx$74=rFMd)%6u*_HXHq0kkcwGcogHoL}&#yKJ1b* zdnjJf65*2v$!=$V_VQkZ!>quE?xke0v*jU~^phf=jS()Zd}(0%;bfy@@H1QgP{)okV$)VM!+h5&#)OGF7TMrkN)0!~nl_74c!rj-tEsE*2sE20i#H!LT`2x#kbf&N_CNz7m3G2&~`LNuO#Bvn5ZEN zWrRu_VloF~V+JFGd!s`>@u}T5(dUZfo~!5jFI^k2z5Tu9%49~-q&;KQY#Xqc29$~c zy|Pcr{~}516~^@>us$ZRyJIM?!#v7-z^Py(#dj+Oza4gpDEt;8?)ON{ZY~bVjS~8v zv=TiFum`l*;}+jjR-l_YtYN!v7rU&Xd9EaTuZ`tJUo0x@&ME3vi=S#$FGZZ&vEFF_ zGkWe~Gf7wCh3!IJk3`>{r1`{AcBpNgx~v{u#z#$Nmm;lOZR>^++K|?zvjYXIMQH)f z6=)ecG^Q4nsZC*RHCf*vTr4;wSv&Mrqz{V$w(0}2al>B5FM(A8s z!A8wX@YJ-zGk@VfX!=9D!8bH;2yGKnv=NQ zQotz8Ba-AvZT5G_9|ZA{rew}sJZC7L1|xT4#iF%(2~iED6V&)Y z5~bT0^Thw`dGvuo%)vrmhq3_Y>L9O+A?TX~?|WgmhcN;5oPc^AsZJMlkLg~X;E|Q! zQB2w^Rr{uj+>QLxDyE}Wj!z~Z#C z>LbWEK!cCo6y(0%&ufLh=g$G28-w+c)@)u0)k}}sK!r;51^e+GNq+kTxb2+K6GFlX zO|(mLY*1+e>w!!P>J_+Id@^MBrJfrts2w!qKMx5=b^0a3>6cK~U!&Z%QgOQ}z@>EG z7~=r4qxB3>7lJm&a~+-Nna+*56ic}3d8EwyJlH5c4HdKL90s?&@TA`FLv1s3CdCZ2G3xep5*xrRA$I z@vA)P6T}e5(?7CeTB8E)`s`L>H`BpX2fvGo2OI5;p|Az}AK?4^$-?XrV~&6(3)VL! z=7#!OS0|BIDy8jaCwTUH4_^YU}C%fQ-PX1JYWCZkiC+M!D8R9M?pFh5&6fRQD)v>R>B z2qQY>of%ZXP}imwHPE5Kzs}mMGJ}=@xd_XEQ3=B{fMy2h#V-_yoerpwUMSU1MbgJ= zMZJhyCsw^sXZLE(j~VXH8tNB;g=KrP1djm_mv1|X}l8IDSDQ36-k zrOPd_`Od-S3&yZevoJXWTk;CB`Od@Vwf6a1sN(hosPRiJbC;XvZnVz%oyZS8Tj+N@ zA9ExJe>@)tYPBQz*ptP0*n$sddhbj11QpUQ3+AvHwOjA8(||di8|Zb5L4KW(*aP9e zQvHa+Hm=B?R^|V&!OUDfZ774w?~JK@UQ@cDFJClPEo;yHZ7o@l70!ua|5c7NIRotI zt`K~apTl{tLj}OU@;_CEIbGrBa)E%lO7QwC*z0}-uAULtAPKpp3A@U0FJn3-3%zQn z`;7{WU5&NNv1T>nl8#i%^RRMHN^!r1hpY?KV+6NtWjVBL+FtOhWEE3vyyHT~X}TOO zs$rxXFoslLQx&)HT6S%n?MmWd0UIZJkWo!NE_D6P-)BA1V@nkNnAB^BJm|QR;Gn}C z=DDm4aa|qYzS`e&Re<*zhz?JbxSH(r;#BSZP^TO;+-l*7`DZL<8w(;tUDgJ=ufln* zB7_{~TC8_%sqGm#pR%fkEANh0-W$E~Wb|6&x1yq_r&qGit_*itL2_74a#~GvUQKdY zM|A^1`g+K3rF*QSIj^8by4%>1we*0CsKe(xPhKNQzpTqzq@t0y$tNxd0h zXZV~{TakCYb<$*+&|Ah$#tDUHM64W@DuxAOB$^>QtcM!Wg9x3-Uq~S>BE||FZ*GyjJWM=+|C2iPf7?Mf`RkD7$ z;46}KnDiwnt~ZhKk1B?i3h4!u-rpzZYv;wW%Kr={@=kkP~)+kY8!x_gp1^ zB9}api|QqCMY44(D~2q0rcIBREJ*)d0{jYEuz(s3T3>3Jt!)8NYtHXvfuBPm z;YS__I&a!oIISt3HJqC>oSQb4A>rNns(;O|D*me|SrY%d|I+2-3B3LUS|>B8 zE*e$idnm^req9_d3~;Op_NWbXyAtYsI|BbO68AX9|A{>0z9RG%-?NB#)STp;OFd|i zdf7GJHifsfL~x-{dRK+X;yP+#4kqGO283=3ujHp!8>*ykhVb19CX70Me^Ts0iiw~q zrDSCITGKG5T4h<&g}XJ06~ryEf)MFdU6mhr5pN6!LmvO#@l=%E|Fnj1QscTc!C_^P z%Wpx>D+n&X26(O`5_ZKYU6hPH+{EC*OBdTU^vkH#6!$e@sI|c!>myN{sji#It}6rG zf5yB0$6t|DmR<9{u;xqNt)bfcL$$YuuG}BFaDTAsVh1g*+F=9LX?4WeRpE}S!W>p2 zCG5PB2A-2{5cs$z#%*;p!O4^mQ61}7gE~-*I&p*Ge%BZE$QSz}D4;Dgq?1JKCWiNt zh!Bwg;8lN2bU&z&;+Q~^9Oke=tuQ7P!Q?z95l@I^lhAXO%1O0+Ql*;!+J;&+rqfU8 z^y5&!ChMfmJfXHsn9SokE2RC73Y9>f1PbM_kT;kZ`-vLTO`-Ht=|fajUm&^;z1xi1 zBJN_I-w&x!*FGNvD!fc90VhX{~Y)3r$4?4t`gXaeB zgdKfAhdHFipGa}rl;pB0-gQenP+UBJAq5`RndHxk%D)ukzZbI}&+YJC@fquaPdBGq` zYE@fWV0Bf&AZ>(1vlcB-HNY>+0&*m9=V;cLz+LBs3|Jh-cT#ZS(7ciWSPdKx?Q^ZJ zNu_xXXK11Lky`vfEPgCEb{Go!O}C~@_vh_UzfG|D0+(_b25CzpA`ONwGhcxp`ywpD zmCbNMS_IBj_1n4XW_T8ATj$TW&0pw*LPpRkSbML*1ISg!4Cs<>cFbL9o4edHd%1Zw z#HBdYqsZ@6f$zxz|I>NCr}J^AaxllT;GE=hB-MKl%*+<=oqG2_G_G5K=ErmY(|~uZ z3=Mc36Wh%f^l{X~VjK8RPHXd~)rGM3&T5KgETyyBb92V>1zQz@UzyAQQ5F6z&7NnO zf6%293BtaZsP|OAhIrp=WaskWlf{HnB?PB(f?G|X>-7lF>k;1fNa%+wLYOvx-vtT6iL#+}v19p?D0jR@HkY7fyoNv}>OXG>hP zypufYpH$*jQZ~s@8k3QM(%XD=*E7zyT)v+cY^Q9G&E%(4D=Hui)EAIX(6#N14LisK zFY#!!&3iB3@mGJZ)j{6d!|;1q#AAHoo&;aO%GOh9uKGf0g)zDiwS#wdZH(h@;Vx^! zJvM~7Y=C+Ub@~bC{y(@#jOg5@*5c}(g7aT${u-#R?LYt5V8xAr+)F(L<;{NK73lpU zrKZl-rlAQ%_%0e_y5YbIslNu_F1uAGF! zkPHY{aPx)Z5uA#Q<9fiaU6>x^FbbFePp% zFrw4tSf$gR4AjXgwAYi6;Ev$Xk5QzasPNAe;ukutFEME(C3Cv++WeLJrN5e%vZ_Zl zhOZiRze4&=1-=DR8e^(!R`m6B$CRZ`MhlHV?qzg8=s z#*=Fx2^S5C!|Q@ko0*Zg3Yqi;U(?CecgLweh%_x)Yo{u+$B^?;o86^J?}W`4xX>yj zIi(XeU!YLJv}~}o!bGhzcY@6wSnC+90BV7YY@15+R;z>4(mRdimC4d9hx#>w3JG`} zZxp&$NIO&lI6wf8nCaLg&gmX`(dST4()m<91-iHwys&!chTBL?$UHzi<$)dR) z#_8p>=Zo1dmrC9(LAC-Me}RZq_IAFydA{l$0%VGw%UGx1;Wnxcc`JPGhIg;XaAjNyH4Mc@*yY%QC zYR9!nj;rF`e^>jSJ{KJDfE4o~Ht`EbH7u}=Lj7tAVELWZ7SHO+X3eFL1w3mgUx5Cr zJilnH{##YLXegZHndLmBz0BIqW^IgNEn8@`Jje^O+`WTggXn!+>l==pkd8t4jH$N5p)7{Obp z>NBz;ilJJWFLYBy?_or442#%KE@q?@k<(;HMQWV-R@Q~bSy$pu@B{y#Tr}p}DJfVm z6^B5>9c-_Sh-n6pkRx5J;E3q_iyvxDu;=fQQK!Vdd*ac*!-^W^u{y$geH47Djmj5L zDrxvE_lv7wfs1f?7j$Sw#tRwZ;Zlg}4_xZp%g; zEcQ8j1LFn>p|3-OTVlgHNKrj>%4Z7sOF~Q^o!lQsg`ISeK^x(7Mu2t&mm@eBNqA!_ z37}ZOu$oZF#^s7}4R9u9<9gkM$~b8?jH|V<`9cexFd$R(xY{tTHI9ho!wTsjhX=Vx zU!np!!u>j!q|fn;!PvNeoucXeVU#|8{1-A~05Vya)GySKPoy9~()xgz36ptd+3b~j z3%8#AedpbO?>?IaA7%w0S2F0o-(->jv3Niufr!H|3eXbLyQ5>;spMB7=o};Jed;^4?VZ66UheMznpT3NtgRX0 zTSBpeHHYanFfA1ZNJo0D`d39LQ@)T%!3(QSB6uj0G?}yCTWbbwcYf#_7Sf+C8XA|Z z4NI2#Wz(Z2^P^>$t8GsfGhQwgyk0DNgIKaxG%ucOhQKnY+{Mawi#5%2m929%Ezpi< zFEqonJb$%y_OFiF>+Q&MrG54WQopl7PDRjygPjWkPUrid2J%Lh@3BlAh?0(^qYs0w z!3NAp&mC<xEUx@n=`jo!1M{hYLdq_eqowbck_R3`vv6HQC<{#Zb0$rcxN5=QNcw zi1?^#Q3ozMHH)gsevx87f}AiIPV53J)WB2a;m7jWE>)(8TY20jBky%W zWD^l{lZv|=>0ieWxu=f2BM5sg3atYPF!Q*cc3ceplN#?7jfb^}Ra6#ND8ku=u6n+k zigtt-e=1RMMiRB3c2%CIAm~^J*`XVQ6Hjxh1zAPJRL%iTUcCKwZtYcNIb|0+XbcX5$?2c0 zc^_?=E$P;$S=J}THLV4=Kk5tLhlJEPZAx(bDb(TTV2`aN=XEjQ$>zQW{`--_+|BW! z7lJ&`x$nt#-<5+uTZ{LoBL=(-4{D}{cCw?p!R#V7wwFZ(6+=HOdXU8!WH3fJ@gssH zq;jG83i%^4(U?dwuGWkzRO6sf(3{3Jh6$ibYD|+F(>SoLwASxdJJc@#(Gy1Nq((O; z1gW4L6ortq@(D7_f_>X)p*`{RejaxS5*)bfp(O4wpEo3c__Kte=%_w&=qFOd*I34Y zS~hA;|6W=~W*d5u59#IJYfvXMZL8 zY-M?`Wpl~ZnHgRA`R~(g9R_`yO!y$iH`ntIhRf;@=M{L=s!-e!qcrKRP}!2G?h)wT z^Av3oWwS1`N1NTF&wP*6FT^o`q92Y&K_BE3`F5v4HFf1wNOU&yqtA>d4>eE~+4QrT0vtUjCH;jZQ{}Rx_-|F-T)cIfrJA52`GZ{nm^#dx(k`9cu?K4JLZrQqw50`4k^H^pI1yzs|d&uaQ175lh}al)v_r%9ZQX1uvL zzOay%&p08MyQ#!3YVJv%@EAXGS8RDgN**td1=9X?A#xYt1z}b}sEu=+drMhxH@o^g zuY|lUj_Jd%PAb4{MlO$mTPfjtSd0^V!huBW?=fI{;|_USzYqxf6GM;b=_so@JfEw0 z!DU_aJ(3=Tz7Wo9lBKn91doC|GdvGSum`yAn<;Lq!yQ)yA%TOdBG4=R!cK9^?6*_W z-sugm)cgktlxqo*HA%5IHPWW^Oh9CV-?Q%Rv_*<5CsGFrbIY*Sk61ax7OWm2OZ z6G=ye{6U`Z8=Li+9M}^Vk(`_#RkaIu8<*eq{=e?g|L@6%<*G{~e92dh>YGq8D3cGWfX5~HDog4`@`#~+ zW8rVn&Ww0U!d>+KQx1wkkF}rzj`D^@7-(s~$3SEo{*cz+!HPd*#GJHx`~k_BjI%$7 zqt-yGMUpb{T3%jzZgzXJty6FB(yHpi9LzquxSks#oLBmzehUjYu8yNz6Nq04G~Edb z*nitO@@8dnw>GC+l?E&DdqA=Nl_Pa2z}Ma0DFcp{6}%{+5x0Rsw9E|Wq-M1p?6W!y zz}c`h8z5lC+-$ZtYxKas0-6VG$M1kenUeWJ27MXS4Vvc?MUzT-Jd3M)iNy#ml0+xdiKUjC_(DKM+jp3dB9|IbQC$ zKMS)r%kLNfXjKgF%gV63wwO9C^BE`jA&+of7JNfUY!ZQ8eAvaXy&~EH1>ZecicS_f z=wpwH@?-MzVhh!16ZJ4x~BG?t3tfi(cJ%J z3BC1hYZK!LIW&h9y8lIO$tSL{gGa2Rd7PuVWF|ybNf>3pr`4!U6z5eTXMm)!i3+DE zhhK3-7m0{=AvWedlhs5f+(-($DN{99-T#(;r57&#$=13UPZN4ejPox6j;rASO?Frn z;ruJvbrq4|YGH>|dL2x2+nwQcupD!|))#d<(C0ZZ@NHOV2QA`#Ecr8y+#3V&g32*+QIdD5OdrMFI*QokFL zzbB`Cx1@YW>en!$(vHgH!$MJiV&c~*u&51ehb|0d%rK@97 z+@S!1B@}XUn>Gc43*V}&uYp&IusC3lHogWUJA(!I8$iK&r2#K!U|s={L)jz{)Js7K z3|LljyQb<}%7Y*F`nlw1%hsm9b&bnV%Ld?LK_NFRrq(Z{G%RF1UCev6R0JdRze2+5 zw#9QG?QezT(50fc(1qtNw9djH4T~^5SKH<;LGiZCLI1tdIv?&(6y%UgaDd}cTEOwl z0QfwS;(H1u+XVq)|^{X6fSZzX5;PC4Am5cGY|svv)4o4vz6Y5 z3($uEF)PNMDGzkL5aC`M=XXU z9@hn*P=_2(4s$J1a_UITZoJP!oYyt{9+UqO1q+uNbW)Am9_O?!0=zWYPHDu>i zM7Px>*OjDTCj&dE!h65feNTqxkrK?At9Yk-{@7;`fz6Sjt+dFF7-+sAA&l;eqa*2` z+=M}P%n+A7lEjAk9RsO?QUN>fB(ODLcvh;%REi1Me9fi_3-ny;l-W9EOZ{$7pE9KY z(Q(RP`L3}5g>qb^7?I0{1foG6{~Ie7_?hn`gS%o#pX2CX;vlIozMmQMl>w*c$lj<3 zz?^$n)X#iopO`ab){Nz4d@m`VdHi(g)8K!5hyUC7VX5Zguv|Bw)(vX4gBtY^Xd+~? zK~YklIN=kY)squIXJB>;G5d8e2IG!c zJr5et2Q;p0q8)!Cy03{1IhL&AKg!SkkY{f(TUspUHwxZuuWcYLg!PByzBCe0embZaU=&z|McCG%o5J;i9ype>`uipSLwE+UpmRo8~iK zEEd0p{dcLh4T(BJ9Cg|kK$ipnbvfuATIQ`{!kVD(8K&(3Y+h|0jXkeaYrc7vhrm~(E>kXI?gs7tDKBV{N^9l z72ti>`((NIp?viILZ4$rxRZ$fi0XHp;r~cTu1|@&UBI|fO23rPxSEsjI3>PO>|0IU zEe!c1UX8J(P)clp**s^tH6U4mGFq_)?kOR82QwM3v!XRhXGMCbp;nNS8fX-pGV*)4bG{`gfD}nx`+n9WA=@`s_xU%PNBV z+EBMOME8~9t}9^t3ky7>j>MLMi=fxORQUY{=5>Ck`vlDM@Zgpx2+7!Vsb83} z2%#|^4BHuiKf}U{cuq?B6DnxF>M^+a%2fb9PpC8q$x5Z4G6C9boU&LaEh&@M>?w2F z4|DQ&U``sK|JuK+EaM8@xLgK==b?neem46{3iJwXxw&c?RvPg5uAamNzztMA1GIQqQ}ur8=*P0J8-b_*_E< zUQNJZZ4BwEMDdaK-npJYKLqUbNKD zXFi$BelcJ8W})I8=odiFzgX1)Sk`=1%Y04iVrBCzkUB24&RzgtomME`xl7G(Kbi;D zCE;`q!6Do4R0hEz6M8P;xIN%lO2AR0{}C(hpb2+S@3lwcxlQTuyUcwv*ZDWL+Xfl> zSV@p?9cTdQNnebnfp{yLRl97W)``G;UuvI8CAY!j-%W}FeIWyw7o2Ympq+d6}ihw z*l7jPcKZJKb1{}`c3NR%N|h+DG5vzl-KeEm@|c;pEs;nr&la-(ZYE(5%Wqd4B=Wed zB%;=l+}DIaXg1&B4UMz_JEANE3vdz-yJKt zGAQ9Scx+4rh``U)?zKng_!HsuPZ+14e4Ks`r$kh;<*gKA13R)&$a;47X5al+Q}^C| zzu!8fNWSjAG2C@c0Ibh0D?{B^hN4!6K&~jor_^ny)@xrfYHz;JDUcx51>oLB1id4N zLpFDBbOdCBerD3XF`|*l7HAusgds^HLf()|$HhWuyAwJswB0E<66x(zddrm7IAyj? z8m&Kc$y1iBNpt%55Zp< zj-~d-MfXyXl(g>X@DC&+ynJGlKPNH4>~7Fz9?i?1x^!jk*}K0#L;d#u-{l;ZlQ=2isDnlHhn-ucLV&Mb1s7|hWsmc3fxH780`yB@6p z1Niei?s#Sp$OeyRg`7?fJed~em>h7-9(E=r=(q)c!05YAhu^2i?NMQNNW8%{aZ8fd zHWm6v5kyE+s9lMouZfx=xn*3E4$XJgP&fnqS6wy>Dqsb;V3p0OE9Mo|3(ATGao&O` z?MH&)N4#u|&glz`>J@i}?UV?R*8@^A;>hE*F+e_pA7VUPUF#(q+f+HB&yQG`6O zk**gA9%b5AV+ng15JMTToq^xZ z^4vglToLNAKFn=3!DUS#b{pGwGaGxz#G&7aW85RSpZ5S0lFhup{jwxfK^m=E&wE^T zX`tZRME=EZEXrS)^+d0oYI@9NCiLRXF^)gs&i=>S`9J>n6AJJ)WOJTzm=9Q_`m~g` zYYiiJUQOP4JAU`|*C0}s9Ny_I#i4~b3O=L zPr$wo^KXTO&{#-bAR)UallGMz14M@N1nMfQLVW@6korFbaSHc?bMee3r8la{5Pf&aGk z|F`Mwti|4Mwhmb>;C(k>)B%Jw1Vl=es87xTDbp7r{VON-6Fmkp6WhaZkNr-cM{m=> zAcWdLgn$*VO|huog}D7{-=k{G5v!k5hQ~IZ!^#M!{{(rhXHqex8P@iqLQwub&CPC8 zNFPW0WCMBT%r6AbZJ-39xvh&vK|tZ3aU@JpQbN5*-Yk&7(*kgo9?a!3d!YY9@xr5q zcAWM>YWtwEbwR_`q;w%lr4(3=yR^w*&CzQ7UxN;F3pi3jey9#{ss#S?Gra{w!Eco& zFw%Jrb&dFP=w2z5PrwdZr)yNJ8>HfTx$J?Qe@7~6f}U=u=r`Z~ZhbTdm7ChM0EZ+~ z{et%Kyyeln@$sVl@q!tdrRUR{X0u<;m%c&dzyM)Y03)k?u@;_=1-J!+{uj9=y_-A# zdbaA#Y~}0OOYi28<@Z>+|MB#|Q|ZBAmwhHJ1Swv7&`F!$L9_pU@Z$x8CKc)rncI4v z^Ln1wPL==JGJoI37+M#b|Cy^C6v6#B`Qaw@oa=NWliAH{85IperEWEYdTH$LnrJA6-~ z-*!guE)H~F&<6pf3T9f@RsIlpi32S3h>nCSjX+o99rFAgGQGD7@cZNppOPfk%*^;p zCApt6s)jQQx*~n5u$!47ZpHDOCIcQ*Dzgi}09)0k_s-0H`oc%S}?Y9sBv3>UO2~MdV+Z1k_4IX<6u@0Al zeCk7RFNi@cfIriSJuKRnXh5E0`#|;!Q* zZcCXmru;A^Po?L7&&r=pPXCdd`y;hr+MYX|kq1@$BRS`XC1c8x@k3#qQW?kPno+(G z@rY)!`&i6ACbJI^V+IX2;?Im|1i6X~{S;073<*l?=&$^^evNb}J9Vu3{Pf-Wr5A0> zonQZH`TX~z#vi7X0c*~%#SXSwg9hy&Oy+9ofQZ+x5&#tTH8Hj~iTQ;=`%EQ$2qU}< zaJ+^+0P2HSkRu_wq(9@ZyZHWxRoH_H+;Ll|MbxS*VMUt?_lj+1W^N6+tqX+ zT3}EforgvE-F*40*^1XQm9J-NUdPbo27Ny5H(<*>vys>qtuWKUa)r;+AcI%6pP zt||UuteiF1%qeS@lvRtO+yz-GVm=usAB*M;hevjX_&&g&tN`&*z~KVFLxpt0)oj6i ze&DrWx7rBTTXFb@=CH-F+GQ{ zh3UU7HfVc7=usB&aAMHD1V3=ISqE2)aEMMotqXGl3}j1`=W3$sMoREWGvTxieZ=B- z)b71g4l%W1hfNIU96>-?dCGlV$|o`RdEntx?0y54{7_u_O>BPdcR=R&i?8GAK-4e( zu0IFjolFY#D|Y+~YS6v-=*JahAM0LE-Fr1z_ipN5%ScMiE7Tv+9=`>7{1)i7CIY)J z$^Ue!+XlYdCIjYhneW+aLEeu-{9i>9nxn%yKvTeo{Q~~a@$|3p3*KH?3j8Y2UB~Q8@!G=mTunu9AYr#BdT)bFTLo$x4}H{1MCEyH<2kM% zdjA^kxth+QUCPdSUzGJh%xSV&Ug~-GBAqPYgXjEPkoUGY^bU^C4mtq)ZmY?-|DUAy z3~IyPx_&?1_c9{55Jn#K@w{mARj6>pNCgaWC|Gn4xtv@BykQ+(K-3j~`NgPNVc*+;QRHP2c@;)dt z--@jtRF;pTwD-`0g=z0((0SA07HoU@Dvht9kmcrnh5j|rIpo?G3f(gxy4#49fXPzy zDO69yAf%Lo{<&K!gLGghf8X8jOTB zu+(}DZ{dy77aIk=8^t~AMcpfvy=$01E&iudq3!ygHv67T#rz4|)KvK3&KuE34Zg>< z0K@nGO@cfmcH7N%+nwa>AoD(56o6?Xk%y8vV=0PRuI@7@eN_ma!O}I^Re1bvND5XJ zfPgOD5SMO9ZQfIL&~c`OTaGB@yaA;tSzR$@Ij z;*r1WgFyF(A(*BxuNFGCMHAjp#p=4Pt-oh}U>24q;Ekk{+#m;9+*ye!EWb=}*MKjg zpA~2WwUxr+7-vDS11V$=IpKVg(Oa2#GLe0TM?Xk2cyaFtvhVXslz#ehULMa=>gNz1 zd?Y^fNF44kJz#GvB$N6cjt7bw%7Fl(+pxlN*%69$AiMn<3K^im7g;!GE~Msp?u&Cf zz;oRdfdGgoXNb+Z=>ANb@E%QKekg8_?fuqi8zQ;`KNx_DWlO*@E`p^B!47^eWc-`7mqO+u#cKmaOZN;7OJY& z+Iqgfc>j0*$X}fU->PcnLH}$_o6{O*)Y>T(c!32|Qo*!{Imu&AB*#rM>7yLl2n`Ow zt`&g#?ZXwbRXrBbc-gv}r26{iobAO8W87&XnG!&%8?V>;$xc8x0xZ;68-E}vc>|Yj_*v1yUNaR1~ zaC=h(knlSw$$qD_evoIs7pFtnzJ-iJfz3-eB-O(q=@q1V%fP$PofbFWm=16ydZqEjkq7m3=$f>tg>0|Q!?{YW70 z5Tp+&YNm8`D~9F`TjjQbo#C4finkHo!e3O4UsW(p!#U}n61H@1Si9B>Y_qiOesrzh zhTVYWRpkp9p}&^&eW~c%D1W+E*|!0~zSvV4*gtJG>+`4C_dJ|SOxQDK-&1CvqbAhv zYM>7xj@Tp|&UQSfT@WI#L!2lB_dPvwkj)!oif6d`&%(4NfKSQ+-d<`W$BIhU#l`E2 zvM;c_f>1(u{|fTING)p&HTZu&5fdQ4tUu86A?oZ^)F1gir*i`?T@7`uW%=EWLER4U zyc2+|3-oTlVH<<7T}0oWXy0x{Kto3wO%qs-fR{4yCOlX*!VeUfj$)NamR&@{wrT@6q9VB4{V0%Tm&-6RjLi$<-JO@%Na31Ce2W zGJ_AqLx`}SL$u#-31|RffPP?CIARac4Kf5l+OeJFwJqGkE-V2pN)D7eZN^{xmEe9< z;=GIOxgGDmof6@m%L=bmkg7t@mEb51mXcAhhl?23{EjnSw}LRz$7u@&ngWQ6oPQ++ zpt6!>{djyw7_Oa0c~V>Z;rip*yDgvVdKX&;Ki_B>@O5FkZN|843h+5d@;S`8vW?}o zM}azK4RE^|;@yhFz9irWiD7S}i2p2vDFDBkWW-Ff5@zD#=OLIIlp6}sC$VTrB7qhR zI;+nH?Pu6ZnJi1z+_g08T3#s>?^KO>ekw6>DwaM5#DG}1I}<)egpEg2#*(5Yc_}kW$-Kqh7-wjX~vj6WC%t3qj%8}V<3J`h?!teCzGOK`8>yAe&Qv= z=4u`;M-u5GR|sG_*k3Ih(pS`JD<TF(SW4`; zlr^PQ%ok=a-h8mp{pznb^lH)r>+qCFB9lZk(Sq z!HFAZ(#8|16LHj!u)-pTzYg*1!d$FG{ig78;5u(3x$KH^-Id_9-Nv-{JR%Qu%YwHX z^i#Kg6EF@epyia+j%Q~M$@tHVnFAbhxyyDc?ENnP8xIn6#0fs~k7Q>%3i==wX%~w; zp^YZodt=4@y-i?*<}=jiLiaexd~zjr;ScMTdb?3}A!*xtWaUwkQhwpR0e?b@?7?70HJOF6!0ESOW7 z5U+qbnU4C?3Q;MDV;Nq@^yuSe&p(V_zw00f80y#EUgCLB<$d-l2Gd2Pzl}?Q{qr2( z_=#s(Qsl3RAp*E;17ug48W^O%sKLBn`c+f$O-7-SZ9Muu-sh1mhSIk^BCsPosE-)b7e#o^z&ya8P)Xd4 zX;_mUtt+8t=0;_uTvjDGr)z1qc%Ip`W9;bTT&1_c8kwz*&=OC@gxG~p4@PM`q&bY# zMrDZ+t^=ZeMPl|*eD>08iSQ028;;nX12+x$Q~57qy7P632hzTz^Jm52xVW^5R2p%j4>~l-sG9&p7PH(97COzkt0r z&~;M~q!3>EIRLu0<4*xj|H8Wd9260lFO|QdM6}R?>*J$39zGhcsGqH=|8%oy;daMV zeeY-(JrnH^jMy210#C6$K(WN=lSTd>_u-FsC>(!7`U#=KbmIGHU|vz-ggOrLrx@BK zH*to;{={M}u;B^JTM$TqM7O9it|&5AO_?jE?DZ_@wx#R&6>B*q>v<(>In`@#n6S9)z&2#p=BV=QiJw#o|8PyG@LFw|@26*UD#KDxa^{K3}bT zy5@hWzz^_`XRW^HaxtfJec+n&C%~UGd`?>dc;$5>-TRcu^QZ=b2$6?`9(zQ{!#d>Y zQh#h0g)&HIjwQ?H*!o3Y_Oc*v1;V=(<~}cXjm-DZpb3zi};V z35q2ee=#b4B8>DB>-89Wxe|4v(ED^D*0Czkxz^w1W(eXQ4*4+L?_sD`f5c_32g#J?piy3Q?91nVxQA@3*3^-w$A%S59i<}_{(*5>lY|qbK9E1w#(W`Z(q-7Ubl9v=XR~- zJXtFRk6|y|k6{12daZBW7ua!E3c&yCdk%=%xd4Ag0@3cz9Q2t&%-J0DpEfUp=O22P zeR|hDV%WaA?p1rADe?2`Bt{KIr%WYFXIbV&PVS1LcujHjiwN3o*>`2-SFjyH@~^7) zo383B$SIX2-vpWK@tS3Z0Qfl*p&_q)(T{x`Yu*1SMx8G3xpLL#!ZoZ5kS8A!d>e?k z<_K&H-mi;-Yas>pLaMtWwpU7Rh(}klvAJA?LF1RM@=E2nXoLto&r=oWED1frBpwy| z*)t*z(iq2*`A$*`AvGPRChw1AUF1|nSu0bDZ>vkQV)KZn*+EC6WhfbTF9o}s;&&k0 zYZuvlCrrykBzVbpLOKt@$AO4FNXG1n@ZJel@f4n?f_|Fm^;>M9dxnc$tlL(s>%V>B zJV8a}QE@kw(r#W{JtMG$8C(E7Sd<+BbVRP;Y2Af~i1Ti&iaptC@vMX6uqJeNkZoFX6lt zz#XDFv1pFVn~@4|me*vEMtlLfh0ko#F)+sR%(ll}jcr>dTn6ipcA zAb##kS2lSaks$0C=l=(&Vq}+XQOLtwCp(6#L(HWeQSOlTxP|U_(MTgd;ESHJBrn;* z=PdRUk>t4|by$=2R$+Y)LJoQApa7Oyz~V5!(Wdq*(||~6quasotOFLbEgH$Tg_giL zt%P;f8-?v03}I)_v>Ir>u#tW#mILGNsZ<7Gqfa3RT(0PZL0T>EvehprD)~(!ZlfTj zk{tr|fW4RVf_FD4k9TQ`ihck#Nh4XPNTURq$ zmQ5{dS#7J??W_5n>xEC&^Sjq!c~#!K=69(i@M5w5<>FAcBHxR)n)NxIhdxyh-EWemD6Xg)Bm;>uwMg7%-R1Lj0S_kwfvkv1Iu)8~jJsHDTepyks4QXL0!# zP4#yPU}LMlYj6Bh#gPA-2mN=QrCW-X&6DFsgTr27Jnx||R(YK&_BvIBJXeLiat-5r z7o7V9zeZ79D=(oplKd>0`L37gbyjA=@Zd1Q&cn;rd7f+^s-q%uwlqK+jeo)acH z%2S-Bgd+)IN8$;8B!(P_q8y8*A5ToWD9jAhCtYT3|C`vs_0qwOm3v8qV5p$MF z@G-kVBEzpJ_g{QaJ85K>^u(z9Drr|TqmJxb7JO3Tb2t&X6YsGt#BC?R!=4DSKCsh9 z>MFr+?&o-@w;9t*b>ZSiuhhTP z7=ez}Z-k15bR+=mXkOcRv%tFpQ<80dhU`M9-{-dF6%5i^fa*YSaE}x&!pbKKWtT(> zzWz?3ph?7U;Q%P0NP5Wli6>s%u&`H!WwjtYo#V7q+kEcdeE6tX}O|h2TqIw+6cu<6Md{m*G=@ z1&ZD2639eApUDFpmdA-~5BR}&K<~0w;k--ae!%E^xgsK@D}wxv&Ki#s&GOBkQZiQ* z1#6PBHDx)Nf4^&LzKW}V$ZEfm@sRLWzQ{WCnR2&d zrGS_~oT@}!s6<`98R+y7k7{CJ>$K$799FMY{aU3M6vPkY3i>PwjcN3z%%ms0m<}H0 z9)S7-97w=yPrk%uxric8CgAqbK#xHy4U(jRr(UH4C;aTklBs#kY z6nyN%!J_EB8?I3y-aCT)973tSX*%mbWMo%T=%aXYYweAZ?CaCeg737<-sqgK>;F{U z@z&j0eC20AV{tr=q$4j>VcZ-1vCj#?K$;qi40}h37>S7-jU!KR5+*??CFaj^Me|@4 zluJHoRG-0KWK3U7%UVv)U$zvkN` zrJ!^*r*t)|csVn7DZ{#$nZBSeCTXN8*qcR> zrdYHI5o^|LTB^CT*75ZF^SA$b_5QE+7vJtStQ1u&WMt1}WXzdT=XB;dl?ulDIWc<* zR$eeOaA@NR#4%>%2$S+Y9*n^FehTq$YgGeMxZtMIA~;9+6;9 zt5Lu4kN~&;g-mcVXBhhnD(5oN-dgfru_@OOzcCT}5}me$U)e@+u}gH?7U{8<=C&W! zUy;BTbKF7!LO#j2l$F%V6M#jim&bXM#OzXQUny*%48uU=(10V@JR~s>s*U|{^M#mi zdFmVBZ^&Ttta+s|yi|juAM#cp(MGTZ^ICYE1|GX!$a*Z`w#p1I6-6Vu+cUaHpUq8cnXPMS9U#8? z3QOtqjxQz{s@q@%y{>Qj0>&k%+|bBSv2=0*amI$t=&4R<9GOF25O^_p6*7+-8#k(WzApeYd@6Lf2phgk`(=5Wv(abS7Jm9 zgv2p?*oy#Ez0bJ{&y!b?C$D0!)POqC`|@o+_lG`i4dIA7vPUb+wsJf+m*Nx=uHVFwvuzr|CICsI#v z@CRcx{yKxdfq9Xi8mup-r3u{RsXm&k@%bh3Mf&ipm1-x%izp(pqvnPA*C4r~_u`|NQ0pM(SBz!=iyTuptTeM8lnj-HfVeb)x9_OX@ zm)w{vygps~X!>T$%>C}!hp!jXYx-PIFkH4WUH7MYpDIT?*M<3Z69Zq7Y){~~QG|C? z0_ZnJxv>-MglQpb4mgu?@dCI74VuqJJ>aL7(?M-zQ){e1t1Yr^u2$2m%h@HX1y|RK zOP2G?mWzv4vhx>n3zl+=p|n?Xik8yzm$Iy%wW*)95UU}a74v4rTzIkC>W-Z>kpj*^ z%6MYb6yW0Ngo#+<1d|Su$WN)}rMq`mdY;4P>hFP(zgnMt1&Vud#Y|4|Tw4BoM$Wv+ zI1Mal@EF3&ml-<|A2SL14QAwMEQ}D84|L*ic<4ZQ=+jVa1MF4Y?WJCOMPMg%-5HBH z#&g@7ggz<(2^;8BkY`g3PB1fd#j+k&yYeICLMAQu@U|2yXGeKqX47SYxl~q}WV1*?&+U`dR zo7$>h0*x5Bvf6&Vv0tX`hb#tIL_-h*1gt0lEo*qCGJ;GC)X}ypl34XrZiGhMCs#iK zU57*ob2U87A@$6*ofe2YrNVXruR|n;F5D*KH}g47QvPF^xJhLh&|Dog+?h?UUog@6@X6~n^Hw$y^kH8pRfHmz$L*9;A7x`s7)G8-FK42|o$#&xLZ?B*3~>ni4Q zE!O3_udA(s;E3aMp)}wkbm0;p>Y&c%U;u}83L<*bUH9vqcdOh%qprl$je$)0Py)LEU&(ZtG=r$ziFzzOKSd-RsAJ{{#*W+u=qPKYa>y&N*68= z6Gj3;USkn;K38fGr^>ue0(`Q{*QEySavSaXDA4PXuUA7LssrcKLBMv>{JXe;9jS!Y zlKA$T_=X$IoAu&`I>WQ}!r_kG#)kBJ)tYOi@^S?^jo~DUI>iqEJuduc9OWc4^3UXm zgE3qWsWmbq{;W{zrzwcbDP!ack-GfQbR*V~6_cyLrBhBOBewXvZ}#{473aPg=VM0- zvL}QcicGk~HAbZ7g=CnqD!_LbFe(E|EcH}8R2TJRS9au8RY?j-m$||KW1_belJ9~Y zjkr?^k8NbvUvcO?k*M9UQ6aeRf~|;Xmf?|GP`qk|ZB^lN zap_87;aYal=j_~N&~IdBFIloa7Z)uTmM!I#e9kFc%*qkM3Y=L`1dE+aia;blbqO(2~i`l#P>0Tcl7Z7$k11~px!Xw2JEF0 z@54rfgUG`^&I6R^`;tBOf{Q_n{!@xRDs}xg(d!ptVn}I0`fx$y}(>9XZ9)`261yfwMQ=GPwgDG4zyVP8&;uur_*a3A`k4*DarRuX~tiU1~(pBWoSdu=ateq!n7Yp0D+ztt^QOIrp zMV3n5tjc_?tsG0g1Mb45)Rr}C=eM*@Ankn3X#bYl_9eY_L*KG)1YKprnznJ(R=kf_ zG>@0lV3vk<+^~`c?YMb0*!{Y%%T0f`8k|cF)~PDku^e;ZD&|rNa5=DN3oz#j(PwhK zPGq?pN`)1c^Bx`K0s|4k57SAef20ANUop?rE{d$czgmO$ud4j3v;sEI-xO8fW!L{B zul^4Cq3Y`I(&De2tTmQtg)00+N*E7`7zprgKwqx*JW=X(w%F@@4aViBx7$5m_eVjf z`ao2(Km2?MYzfA6;QYGD!R@4g?r2=En9wQqyRHbR&0;iHs-70p?pINZ8^u>UQg1%c z-pGq9Un9Iz(}zlVmmr$wLTW=EuPFDYdh#r2fjG<>?1n4>}J6OJd#5YnrO z`4T_9uLHpY)Xtmze0GHR@1#T=q{>_*RwPGJ#c4=Z4utzQQ-d4I3g6`3oXo75DStS3vvKB5%lw@ua}RsQ$*gJ* z2O08M4)Vg?K+o1tzh@D_uc_hhV1#Cn-h+Nv7!SA9X-HTAyp>GyNw4{&)hy|ZOP1WF z^z;?*_GV-)!G*W5Y}Jy#XwCVYnYEafxoEX40_fFRuxc$>%FO+opS75u4HdnZmAjCg z{Yh_{Q)_Jb3moP+E6zrR5^_3OtPTmM9Wq0WX@k=2w^GZH)bv(v1hlNpydX0StMq`wg62D*0Ps63 zuME(CUjc;!>l{j1I6Mfdtyd)d4$_ zzGY3_v}$NtGd8WMAFYCROZR9=|7b;5ziO&qwmpX%R>Dws{9SMPx!r~hlAj|aP?!5V zUd5g-!JI3?o+?D2D?)?I^|;mfNV@Yrqw`)!vM?dfUk&zer_$d?v!{||^K8SSFl$8t z@SL)BdHEN0^)~~&e6RgbU;A5I^Fww0hrIR&NGN&M^#t8=tY{t|I~_~_{RTLCYTS>P zd7r65oxg#0yoqwE^L2Y1fNBoFw1)b2;sQGGf$hP5U18WK;n*iB)F%mHoof0M3F$FA z@K!SJeqvx2a5Yv z68y>W+)nn`Mzn<#@1bD#Lc9X3%R*5*0#G|~cvJ=~JPD*OXu*P*w({zctcvN9TXWS9 zr?1t|-R+#e|7xMOkch*Xe6Mj-W>Cg)0&@bdVbU9?b9T_)%W$D4#hg5zWfQ z^KuESg6ECeMS}^(;6+o$QmT0|)3TVBzg$=X=7rCh8K2A%33qIXmdx97ImLVD}#Dx+4*Bh>7}5 zfH)$?{4PR3R{Jg*ms(w78LYfEceQxfByPo@QJ_Ijdros@6UlWaP%D`(J0hHZ4ReCy z(cXCH-E^m|MEIcW<3c@hn6dRdUMGv)p2F(nr?iOW&mqfOmjQ`pLrT+-GIdx6fM{Df z(x3!jl{%oi56bjV#Xy7x{WCyipZ;@Q0>JxgSWt^0dlW4Ewm9H^pjkrdnGmS60M$`H zRqMK>%089qC9w4bQg9bS*mti;3Sq$=d_lVqVpg~f0(PB%T`!im>T?IQ)#IkS^J$N4 zT{xoy?!sSE+rGj^OV_-vYg*GctQi{D)b(pnw#LUxhK5yb!;10ovH?oCVJ+CJF3{s1 z&g(YD@tTjz4S%;vtm9RnVfb7uL7yu?pDXn~UxYlB<$5H;d7r^)x76ie8tPI-a9}r) z{(;V&j+HI|zfNXZ69WGV1kV*4vf6L5N~quO`s+XRHQ#l$KUCF!OGmQo ze0w5;d-#bXI?cG2^(-m0J^^=+OSnt-G~@n=!~YgbKP%DVvRGc4fI|%Y9}GX(9c}T) zID~Orc~O5P6A#C!J=8{|DkD5CpKOgfo5HvlPdS@t3Ndiq#JIyTsO=#hn}X2WLqqpP zg#hi@T^w^P0r0a7C+4-d?1#+4yGeOhV{=O)G9%Bh^TQ2E?gAEqf18_y+D}95AV9FF3wqU@NjsZvUd%9mHmBMM&*s#HwA2NQ{*zfdXHd^)nCFd} zIkREbk};Q+w~&`Pmy`3ksAxVX`?Do&z9j!MteXmR=h8D~W#S0|b2NoE!e)$flO~}B zC&f&`J?rzK#o<6sF7>4WG-3KR>Qpe>(8j!1#Zj4}N>lyi|K{q5AqlLBX6^ zH)~MO8r4%O>9idFh4G_I+K2e4_bE}sG+0{&za#{`NDOPE;yM9j=i_nT=VXEBL5=4@ ziPN^E%UkIPd$z}(7)VOOo)m?imHX@<1@4X!)2|n#zpcGBRhacsFQ_M-SNNZmQV^*y zC)?EN`;%OE5HD{EcicvE+0Af-`rS@)-4f=tBQofcAu;kc)UTA^&P?tRvKu9$Cs3Q3 z)IkN*FQ_q1gD^`=z})~%8A1sSa1kDc;1vnrpdlIwR$K7q1v!U)Py&o-jqTS`n=aZG zzhcAes9&iyFW|HUTuPayPoe3Pg6m&lgGGygkSXbrOZwoeQqd-pHpv7{+~mg`78G*5 zT+v~)zSdWanr_Zz)GwM^R?=G6t?e78HgF`Z>zmgNaAs;+)xxv4X(biP);2}27#fyS zp^6(;@!r5oza8X#3y-`R>UAT?ttJ3C>aG>O&R5YFiha(Pz*pqye^$_k434|yu7@n% zm#+r~KP5(gjAczGOXnr&w)_Pkx2ww5B^6(lHD6_**{Fss^xrz@!q>kWs{R(2eCJ!% z*|5J7&ruR5aKu3jq8WLv8g;r1d8*9MsT%8X!^inH*8O1ssxc7L8i45v^6d@8b_aO( z`1|yPV4wwe#|cMtx;NRG@3V5I^{PpJT%VZufQ2n4ot8(ONQ^j|K)EOoV6qZjwYcAt z{C0<I z^xEtfa)3%d&r3POiaHn_e>v$YBd0tvTj{M!JkOFl%k_RbwVz&#SJ(22NavXXFIj@K zG{#wiKc3>bgA5cb=WRqcJ2FghPT)e_K><+^3WyxLC_rX&1yTJD{1w2w{}kZ-vtO`_ zR<3$MjqeZfX-baoD|s-JQ8{fXo5-!5s=YsTzjeC)=>lAY^_8!k{>=40Rpss65Q6HB z@P7#^tk{URP`^9|M1xIgM4)b(*GM6;7aqbOsF+LFE$H+R5BgaTk=)Wbr7etXN+Ouj zi6$i68Lf0$Et)ncX3}&sX@)sV>U@!PA0w35H5ztP>wT1+=hx$B3JKuIan&Z4j z?YtL424fw!P~9C^U=_g}29OSq?5M=rQ$if#l<~K6EpKn$oz62oQM2y_pHc;#mjs+u zBlZH?Jrc1$!NWe%)ea8&RHwbMZoehD?2dB$HQaqG(f5=%HlkVpSV(?P3adxPZDp~$ z70Q?DR4863+qY_H!6p#F0vdWyt{;M1FjyF5Mp!c24#5z!qA7rHIj40ZkR zE(X#p`~nu#5-|8{VBQA&`wN8u@`7LTWG@6V_{DR%{JB8VBai@Kr&lEIQcBx6ybb}c znV-_Y@j;n5HMk@rHqZv}eZ4nkZD@T>`RtM$23;qO?6I)ByYQW5$JETVJ0 ze$RA1VDbQIhvVIVfIbrK1A{lgkZkBFVbM-2F*8hy@Id;L)YC5(m>iPJT#>phG|ou7B3pLbgT z_DLYN%Mbkoi|N66cj3L-f+OCkO(T-z0kv$xk~W!_K9ZCDP9Yjfp*KalDX>+LGp3sneksg~u2>U4HeUT|%{CY!WldPm(Sy96&s!hl) zPDoc_)j@kA{dY&AHw8d0t=Hb&>7kHU?HP=bRaTMf}Ev2-)5?0|& z+0~qcT)CGj^e`>-cLr(~$zuxvMm3M!6j1KDY>#x^73l;tMSHs2_DGLiP|IZ3tu{fX z)0QBYUxQu$2jjFeB%V^uGXV>(BO;)=C~GM9)`Tf*B%^A&{LWPQ?eY8V(~o=S>YmPs zvwOWS6k#sj@^@<`20SC;-o%rKlVV1>j4>Gt?ng5+;jB_Ir zE#yzLxU&L)$gw75+({m5Dup>EN*))cK;e(eC6ijoxLH1BQqN==XRT>-*`}Ec&6LGF znP!|6az+xUZxhHLSoF~pP%OuQ<9>`q8jFq?hfe}|N|LgWVP2}O+-Pq7-Zk`}H)H?p ze*N|C<4?6U(8QiH6R*EgEDS-VRiR9Xwz4tzucH2%N&a4vDyx&uNtNV4c+@6*TIM&s6zubroZ2w`O$rKbh+n^^MC=wx*^v zQ#0(Jms9JPO!Z4VkY8!W0*Pd=P@D4ME@bcfT0`X@HL9 z=yT=ROXcW`g~-!|$YWNIKS0Zoi*~se652Q^6 z*ZY2+4Z)a3f1ehdUpqdiD+~u!+=Ih*hhv_^u!ck+0*}6>PI_$Qz0@x2Uj`Oz*_x&{_cvrB{m;XRl+A1rx z_~|R?mRfFURzSK6Dbu=(z3sxo57E4T35vX!Aoo$k{=rDR%*iI06mHUBdwg1;%p9aQ z1nMec@@}&V@1&GeCgk2y74k?*_g_NXH;4Egh{EiSbln=^Zb$I4ry%V?yhn1ki$w0E zyYB=wJ{7eu3b4|i_Mp@ab^Hl;?*Bo${e%s?B9_UXB(PqFAn(UTb(GeQ%5pwh@}UJ! z6x5F2csNzx4PAKdde>x+kHnBhVyL5x@Q-oCF*bctDO|`j zE?+JG($M+!<-7mBnf%|b*Wa$+oy*UIck#GJF(%@T2;)B_(}&|JL)@4*$&oLTsLvB3 zU(o{FF|HLjk9*#yi-S?O{k(2sT&q1VSHRQk%2x4}-4e&m^h-Yx-Ru(}Ed{wZA?S=O z?2-z*ofv!|QJZitE#v*2`*T^T&!p5FxKk36yV3u&9I-df-67h;j_zpt;YkI<7d(DZ zN4aoaa<{D`h={$3k;rUe!b2gihs)_=Gdnr)t$filY5Jhn0yFb_Xu&q99r%BZ@B|)~ z>fXRn3HDSVo|NhaMcOwylPy#QknbwvD?n=SVR(jTvSxq}Q4R*sSpFl^vTdqg!tGcN z-?4cgKyL}$%jY(aKlmLKJu*p$2zJr7uWb@RgMil#{!>1uO`g&y6Ev%IJ!9zFHQNZU-PH`}zYR;q#(!Gy<3;d6Ko<@|HUxXuft!!wUl)$K7lgcn z$K3aGy&2+O>+4jFK7Y;oVkP=)A>wp_=kM7bhci4+6nMMd3l4e~89NfmpW~@MG0jW7 zoK;!Lni8)({ne6RftUlr9qB!%CF+3OtBax`~=5HlVg_R1esj{*Jj z$wH`K5K{Vi-o#<=`XXTY4E?t~)US)+-yY)I5$M|&gzomkJxfXL_c@)0ImivVlq!gA z5hV;N#6ua@ab5h2)Wn7?_5(fRjxw$Z=wXcT@`#gM^6@0vX|~_KXt)~&*b_r{QNm6z zs`-UCxW!@@3HeYo>uhob)0##y1v(JDx8WgQ+utt2*N(z+=V-99gbQ&Zv`ibIp&y~+ z_e97&#a429F)b&bkex%%xxp_sdTX*N84oo%$ruq>{=s*Tgcu_`0>CYuw*d!$=(>~Y zwu6e;Npt>{;<%lJ+!N^zx&k}ug-!U2zu+(bbvJ2_fFsMnoQJmV$W9udNhS$o<)ZbGa}#dVm}JwMmQ;x zNwMP+<|vOlAq9^QcT&cl6hJMrCuD+gDSv{+97~9J8AIuhBfOzu+Swo`kA5Rzz7f-( z#N*pEaeWe6t0i+(C48q>PpZLdpqP|%M|g2VaS;PixHoa+VJ7uM3hg76V54BsBgRt5 zW4y#kkzm1;x>{1Y(cJyx<;VX!F#g|;7aP@8vzZz2ZdYPXfxG z?sYIW;gI7w4;11A&y4Gz68X9M2N}oaG-kZ zrMvDR!w7^tnB;XR$=!~M*d67yH-YSx&LrOy@;W8L9>CgglRHHMfZ@CZAtk7=CUP1hzUylK64~;*zq2#f+1jNj z-U2y(EDZm`AMwcdLJbPGWanXHR^#J*#}82lIaxSNy&tM2G^i6F*cBSo6%qIZ=iB2S z@se*CcH7Ev-VAR{2H80`DeSIV`n0Tg+^ie2h}u(Gy{7oS^yJ>soR>BCh9X%veST+# z9*86zrr~!}LUx8m9bs6=sijeQW_)H6S{3ai3Oy7}Ig?-t)#8svyZjP>_|*@!1sAd> zQtB_%`ASH?N2>i*N_RQo5S{raQ|YP5qL}Z>%X4wrS<%_8Sv72g!W5uScID|q4cL8A zp4&n|IPJ0t@3uY66DYE_r!FMLM3T{o^te>gtob7lzcfV`qR{Ln2x+}>2 zP7uhU0|yv{{*>ru z+r%Wi2zPzJ3~gf52KbBtMo2pi-_8x|io-Wo8sC>#-a7^e#FD}{~+ zG%j{R*gw13#linf4~J+U2fFv3*no55@Jm|XT@=54@g`1vX4d-$cRy-HEivevkaH3m zB0b#2j5wSGsfF&_$?o=4)LuH|IKVj=v5$#9lI*=N=AUmS1z%Fd`j?2~>e#$)k)R_b zxif_WZ_=mo)VH$q_saBlP_1wXhDHqiS7sU#>4t3~utwXo47tE^^)tB|dhRg1e^qIN zprF=gfI;{LoP%K<{EP?tYN%pSCn&*y z7Y(ouv9L=nY>~o6iQ6FMH_C;LazVXV)S^~(NX@Tgd2iJvW7?`oBfN|6elpzqWP0#9 zwQdoHXY<3)CfHZkuR;Qtex`vV;Q6)EO@41XqBzQ8jt3$5#-!VOjV7e(b)&~Hegek(zI^<7=_ zT@B*NsvqJ4;7_iy^-EOFJUw9~DD-&{@{#|Q3W!odUnoakz5(_ztQ!pQb-~C6JhmC< z+YuJf72?}P^zR7sdlG=_lV!iTxJ%@;opxmt#cNlh-w}0!Z?Q?*ZIM08QVwP5M>U$s z)co19n(5r)g~G;-1WAv}Q7(FS7>9rD?bx1Z^B*q#n1U)7yu`RqSEC`2<2?0`QECk7{1f?Sz9<|E}Y1@K2`Q$>Q>`S zWA7|{z+-r$btGQeiE+P8^zDu!ypEv^#!&{78Sj|1_wm#Z!hZ~UFgXiS0IU9yNgId? z?qG(u$A`B?p_XVSyJWrNf z-Y&edoryjJd0S@0L8+^q2)UP!v`=u`Mh!dxS9QA2o*19gY{F#?Y73Z6l2ZAPt$E|M zH%C>h28vr|*kxU$PZsXH8hs=s;3x;RhYD+dk6n?_h_7sg`+F?%U?TEhJbWL5(r5u9 zvPUM1dRr!ZA`6V5 z^rNnF!caS7(`((E*WUY_b{`5E?!U|aaI*2d7l^(Wg1#4kxEJ7g3x~QB;C0*I<+`8K z4d}oA&gB>v*fQmL9?M1@%R-+m@$q;>B)*`=j!-$X@k;2wp9R@#!lDgfDVP_&Nvpm| zs=gYlzk&W)Uj0o8{$Eg37Or#CR+CkWk*qmV^v96U7XhC2m`hcD=So2?;(e(G<9OTW z@*Q8#Mt_gTf!?h_VBYt85{&M|`?ukIo&@-I$40jLxKujsm0sQ&=eU*OWykbACelV< z*O6;dx%Fwveog93aqaTGs~@v0lXWkC)PMf3zGD)fQjI;46zD+Uqa=JMk=Hgq@2x=r zyF%%Qs793fT0&uQTz-03D&H zjDSCq(R;D~?5S5a8LWv@d#uPYK-AGJ=G z-I_FKj%F53mR_H#crf+2bEc(t_EGoroz98cruT7@jv(X%68>o{H?rhDY zg=?B#kKQn>BqyV~>I_Hf-Gf6yK*oHV3E z6xyDKImxHG8T|Le1RiFYq|JF(Cu?g5<+1k(j>afNMwFK+jtZa?PO=L z^KXlU%aO}2y4#*4m;DKjJ4jAjNQj-(pwqHsQiYV;Dukc}UN<+TgDdD$>YnS(gSyOj zQuDBl{|r!Q7^DpYeEpC}KO}~vZ!i)XheT?4;X-QCpwRF}VS*jkkls41GQE_T-Uv)@ zVW}lC45^H^-zYN!`wk9Iw#t=g-Uu`hF8rFO=$9&AL3}Vcl|-@^5KbzU_rm5G1eS79 zt5DD=m3GO5o&O(6?->+jqOA-6`p%g><}Bu%#w?OM=N#xJ$0o<7>6`;i&OtH)3P{dL zKoAf`93(p?f?;%2g3j#OXP>(F$G3XlsxGR55veKHyViQv6XdcUIRrO|dX%D8c}%-T z(Wy##5T7<~$ePyQnoBBwm3Zg1zGgALekG~-eOlXRCZ?H9Y60+>fo@=6n<=OU2CjjP zt7Rao$+nf?sm^dLgIh4}YA)_V7UpCM=~_Mo)8x(@^$u9@6E6!j@1xA0Vza)e^4Db` zKDxaQmm@{_hPwQ_;r5>p9%?LK*Osko^4DXM{)pCp^b@Xdz2-TbaXPk(bn`a(QX%nL zDcQP`Vt1F0sHdPiS%gjo5$wvl*t8xNrJqIYXOsKs#6CI>Jdp2`u&o$O4GMY7X}^ei zCYJY$nsQX?Vy%s!<;P2Vs;cL+l@sxKpVRKGj?De};-CMw^WDF-l{47uiiqnmoFksd zZ4B&gXUDB{>=q_-w@0jl#7s?rXlr z0-m(!o$ln5!MKBP-Eg(v?&Yu>PD_4{+kI@dvXQ&k_W#Xv+)QR1=I|U8I%#h}K(7nt zc2?%2nvOS8(}Fqs<*lm4+eialq=0$xtNwjlPyX!l`b_<+WvMbEpN5qz&QqrbOx z{=xnC4~ISuj;{8PZ8Qw5X5aoC8?z{ic`X&cb*KKyXHSLr&$>8Ic`zqkSRj3xv&e)xFWP2jgw6J7q!kzk2^;~d zhX*6rDeUnfos058#8dY8(T~L#Ry|Td4!B}K1!f%p zYAFZg@;;g3zJ+5c>QKbANTWIwkeLOg@(x)4oT%iK%wn`Ws!wBpM^e^M!j*1f@ z2oNoW>E4OWzsF>Mg}`6w?G07wcggJyP1(Bf?uPo#4^uhh|88i&LiW~LRPyH_^+&Jh zWmoTc4tI=-ZKc|l5-#NvE*253OK5f=A*^FyVHjwoW83JsUOM3cgV;^QL)rH7$sNEm zVPm_UiT%#ZJ~y8S1Z0K%VZGf^rNhA}``#pqC${2!~cS^`R66Aj-#QliC^HfNr zwbc7ukjsf+?+Z~PYjMo=SYU9KMrG#*<{B``D(8d-bBPkK2Jam-L|$5X5-qN4UW^j~ zWpTVxZN;P z4@+FmDdd!lri8}vzJ*5*KR+B?9elXa(X)Q1WmT8_K^VRe?EI94d*tFaYN*))rZw1 z4j)dHb_XGEv2BeW=nP*>isubO7$UjO)Y)1+S5XLX_p4x+Vcf+MhXWehT~Rl8McvpM zZnG=GZg+^yHcz{q{&w5JgU$oJ-Gg{KB9xFq-y6U@E6GV7D=d4JmGMOEevk7@OaL~~ z-NEdOPGDY?VvYfX6@-F-!UF;5gMQe90>plQ^67BYp&+~6KEUfh?DWL#6L?`$V*(o0 zs?k{am{j^mCK*yGM=kf<)EQkmI6}`r6wvN7CN#C z&cx3(W_SZkkLPMYr{ktU7c7CRu^ATU=L#d-o+d3{{Li;!MxcUB#u}%fHLLZH!9-eZ z99BZO;eSl@vEoxy)Y-F=6rdg?I*K4}e z3B#tO@r3N>aYYM>m9N>@b_S;2nNZKg*VB-7Ok6Du)x?ByM!`-B`!Bpo$@WF)E4RRl z33)0VbD@-qYISjW;sOT+(Mp)^y(r1Te};r#FsxJFUR9K@>+ix9cwJHTLjn75#k#&| zU6%JvocK9d`_Vme$<=>>aR3Xu(1b?l9WLLw$G&9i6RCF_g+|3~L zGD*EubQ_b>#lp8SNgW(gJC^_ghYmKmlS^)=qHBpa%F)M+=&ga+V?ssRP)U3r|GGJZ zS**=ku6Xj#qK>tc(%+@2??cQh{vLg(%Nh1y>Uc1UwBH}Oor&4XwCu&leZ(jg2pQZi zOR0PO$h%!auZ9I)kM=qn#X05|Z7cCS8OYx49dIr@+dKYF#4Q6h(d3fYnN|^EFUNx9 z5F`l)+(?##qdR7=hZC@Ex3Vx>IrQT}CeO4;v<|(;54+Ecupflv?#Mk};C)9u9&~e? zyWKWVhwW|-pnBWF!tP|CHq&rN+~w~1;jZOAh^&N|uF|quecWWa@mYG(NLlfd+Payh z?$@1z%UuuOw+?~QaH+2UMYw6ipIPTd?(uVZlh4M|uBdqq3Eb-m+_O@DTYYa{$JF@p#M4isPgi?}SK9}_WtYB-_8aF~ z-vbt$7ylUx)yKg<xE^D+r|8<(_WrW}n zpdU`hjn}t_+3XCwzQzCg<^a2$p*GvRkXC{A+dUCGykWM%9t{qorI5A;($2)@WIW9; zf1R2-5zepTUDtTy)A?6)o(MhXh8%Y^40j?NZRO_#v}Y@ClojNF2M~{kU=IdC|3&Wh z09!N69$%nLhk4hEWFxV%u_(!7v2X~^NjmVEgp!0?FdTvtXVgjanq;V43olD)o>Ig; zmzaQ{^(&xKFgyb_%i?PXYp-z<)?1}{77oYqxEVRrd%`p{XcUo2>&&p{g*s|rC2Ek2g@E|RHs7N zERAgyhP5gp>t#_5>eyDjs?%s3OiUj$=lsgVw{USlkFR$jG;q=Pn3#JsL@f(b%S6;r z9IIG%m1OJNB->*AwG!MfdFV5l_!}iqP0lXkUcoQ?M2nzb5Q6o0<~L~xq;;<Hn3U&%+F`VTqqY8g;C7!K8R zrv^)!2D+7o>4X;@-wrS}IAt;Lt#n))m(mIcVyI{qzJ-QpCOI~c9P0^}OR;;^#OulV zCC}yZC(iONQNd(x{YrkxqA~t$lw>hR`7TV8osPI04)3_NAWlgOeP3zaSW!Lf8|` zysXSge^OHMDl_qkfK};%j0+^DGcT#UPzJ_TIqpOx>0~5wpT9lW-|Z7P?Ds?L^+g;A zfQcG$z!%&IftOA@>`Ol{3u70HBYS1a#}fII=$J=x2?*_aj5_}gBPWx1|exh90wIWErH54Ov6zL&crIyjKnyrG0&>vp^B%ZCP1EnemSKv z!x4E(1Ru>aN?5BQip2ySd|Vs%1a!n29IL3dcj5kvzgkSVk&nHYjXVQ!JjHZEr>pxD&)}E7!o^VCd*E-#bH7ST z*5$?Pa&XQmU6q%>A$VO`wjnQD*OqUXZ^QokB_i%qsOG(2^oq0Z3pVo+15r)7n1?=> zgZl+k5|C~H>f?J1R1I*zsBpbPHp3)O!FEucEFGDGXkwt7==eqox|NJ+rZ}~b>{{@4 z^*EbalJ#Bcg%S#`HLrR(tLkHZ&uVt*Ta{`yFnlgj_FJ@KDOm9yUZI+m7~jzdudXQV ztFW*c{82ggqMmd#oVbgI+rbF}=p{StS%M$(i;;kSSqO+OZZ z-s0}G)djK59kt6BSXjhkJ}4__$9#ufE|k+Aq$8e$ovs`pcAgh9twMr*Yoj&Ko$;*- z(O`4`axz5M6~E1>St@K;yj{O|x9Mfa;7Z@v$F`xB_Mvxo9(=6sf9)2~LUk-5+E)>- z6xbb%N9>Pv*cair)gQSl8h29Tj4gI?Dsyfr_cdf@i5!0QFo9@l-SpY+d(y z(2fgz@bMC6i7BkU@%CI{%7mY5H}OKM#hY$t0R4Q3?e-9d{bA^X;fQ@eni4qe1$Q!E zhs~}|yZnOCCfdF*##ME0`jfKKmzl;9UqXW?D#ITU&p0P!UzT!jDoJM|;oyt3$bO-T z`;v|dkOwV41dPid+8epu9lh6;c+i7&Cd!|XEedLtO2=X)&t$UESkaI~`ULh|9YiA~ z%_);#sMBT@3A2i%c~#PaDsdJ#8|wcsqE%)n&v}_~8Uj`6~(ri;!p`F7WP^ZKv?)Ix!Ci0*sCQJbUT;#*f;crw`e(B z`#v%O!Uw;`S~9!W6h#|~k_|Zk&X7DKil{Abb@lTMALX57d1O zH+%>eO!{ETg(2h8@G(zJA@7Qgd`gPm3hXHgd%qiFuZxT*P7BBoV)eMq9`plVCTG2j ztw+Pkyoo~J%a5{G-ttaOpr^@5rp(Zs2&{&B2-FH3!T}!i2=a*lxak_R$Rn>{hMoBiy!z#14qxMU!mPq5z^gg+0u+Hi+|@NVvK1kt*c!a9sbbW{Iah6NrI@Bc{$#3S0w#X9M3wBa6Z$SF%<4O1*Sdj>?tt)2ot;o z^)4uarNVbY(XvwWdt4%^dr)e>O<)VT@L-*>KN@jBh&d4MxGTtU zcc2559^}<-<{|d_aj$9VR#EgDnxw?Z(mSscHDm6mVgVuB#acr<8$&!B#kbQ!U>V`O z5O*}xX|Di?Td4hhPW${(N5BRU25IoZ@&ST6oaQO}{XFc9;hyzs$!M(lnMgV+6+MWJ z1;xRy>XbQs>YOU|g#t{WljhaQFi1nv_nb6g8mdxdISS9o&C@dTEZ|fy7{mMj*Jmvt z6_hrt%!yNasC3gbRIAK91-KU6q4Wt861XK(_Q6p|qOPUqJ zdhko(RFG_LW3Ly17b1*jKv$;W+P&RJ z-2z_`|Iy1K}6&%1cL|NX4BiB3v)CpwKpVS?Fq-Lk$g8OF=eLQO#sTD}Y*LL<`BW zg=wi=Ai6ivQ7sg^deHlm;qY|1hIOgZ-Fu|^;aW!Hx1^ze%ZC1!8~W1Ae^wCtI#99* zip411N|fnSh+@&#eOM9wFeaqmk66w)CE?$QLmrMmZ1*5-;oyI!5O=cEJdDM{{0M}G zbpS#My>omLJnbSF2l(t`ULvGghSBSh`dB+vwV^OAFq3k`!)Y^(u!}`H?dg3b3crg- zIq2zoF`9NVpiG$Kd?^+Lzt}w|#LJZ3xUT9&gK-p3UzCX_6vl`j@lFXh!Pwhk=!jxM+N zFE{ir)pRV?47|;2enDg2MxRN?p1XxQmF9R@XT2@dX?HLjKy7xz^&}b;0f>F!h@D|h zTfLCG0+}acnP+q&x5DzG;m-PJB}w-qor_85WHwv8Zf^3l-QsS)ErfhIhsPTW4FZei zd4D%BT8AK{H-Y}k!muS#>^r6GolNstAO9sOZ?(8)y`lR@x2lQVT z64_&!cvvJH*64wE@m!TLr^;ARCCx#=iY^(d&yq1JkDrx8hlQ33MQWVZm|!)YQ9$SY z&x9-my>Rj@dY;wkqsI6#z4eDFiDjoP3v&k){XpJ;?UG?xfonmfi?^vjT`dN$IsD}UAU!e&-8|l7 zkD%WI#fyMnMJ0R|r+ty-Lg3(WgaQBJb0wCI~q4OAzX>YM4fP6oD{gzA72 zhI1jw5jfHm(Qj(u#L%a6M#JHN|$umi^*ln8F!Y7>zC_$R=P(%G!H_2 z!%~CAvSX#P>upxu9F<&#I++XtZRGJpa4LfY2m4(ih`mt`yCa<}2bxg(ouSrS0_?X3 zIPDNn4hHkC#zwf8N_{KcQ5neNaK7(l} zT<}I1{#F{ZEQx(DlYh_~eveCmSf#as+Vwl_KWZQR)%xI{Ef4={8Tso@|9W!y8xQX; z)TspYK_T%-Fz$dq*2pSd| z+U<$7gDd~efScPqowm7Pce}ICinNQC3w0Ea!^PC(?a@^{z=z6t>j`}{3Wl4JfrO~>xwf%l**GEEfRp^$^A z`-n(5Bo+1ocmfha1EhPWENIf^RB5yFWKcBBK=Fz#LPGF}o&iw<6ei$WqJ&vh!i)&& z8fr5Inl*5@ri_WO0?$FIs#B*8$VPRa8Au&ZEY8v(Yl3jYxCur4Q++&y zgFgY`aAM*UbK(=7@u@lf|1HHs8vR2sp;c=iDiwnoEp%ZRr27@}0iC=@BkR^FI+e06 zOJ5duFtAO0N)v|+_sWWb0Dm&AW6^5!zR>uq~hkW|P`E#7+jTi-hW; zp*sM)qM_QUs7~n1a84pSwh)}!U=b$SG_jo;JxMKQ>1b-gWOmyM$TXY-W`bhh1j&~| zl`9g>a2g$(Q55N<^PwE%xW=(vsJ^fMX#4~p{L^h#5<>ggde#bk{X;Hwz4rlb4XjbzShFx;9HsQ8LP3V<-GF?dCVl-MIVFXY!sNwArFSxS{^1M+kH@>VYWNM5xXN1mZLxn_GA=dUyS1c zG5Vw)aYSmnLtwv0;IQ4(LP_23%DpJ&9FOt9q-N#JSCqa`NA(HVcRi44v`cd8i3qs- zI$x2KPetHQMiR~nu}6ZPc7p8{2nl`BRsx4zK9m!|Sjbp85{NzE1x$71HXi4STIg4& zQ9Y8v6bc^%x6l4iB3bMnM_z^s5;sRuf=307T5Y5-7r zTAKhnFN6qNDjiB&1_O5Dv<7kv!Tv50h#!{WSqZTYi5Av}D*mZD=~uW5gEPD;@u>my zQwdKriR0SDr}~5^hJ_(*FWR_liihC!`%K(Fi9>W1|C0i9+* zt?JP!yEM{nmCS-}ae%);Ze-&dnZRAdTkO-BC?GMmuu+Xnd@~K-&Op`CQ1@^*E5YuS z0Lw2#oG>1GLULT#D}TvSnC89E_*s%;$^4ZR!3e!BD+Th#nyh?XR&1G{_0Wj(S4G)t zv58+o3?KbP%dUbKJnkdFslaZUay<)kCL4V|AAcpEVqHPCy93V(2I3A2-OR+aF|hD> zvCy$-AhN)>QGl|A=_WdLGLda$$5voql5w3Br&cnmlY?sEpjyND-HGCUvvN2m{?{nY zoJcYsCVv~MT8_~#$7+{jRZB6N5AX{|=-vxLXWf|a;C-pk{igBmz#UN{_XPvF+Tmw5 zlqBmI-}jnt#EmG0ol=I-7l!8M_+;^qhI$+eiM3WG;N!v^6q!EhKIfxJJ6YJREVuJP z{@0=-5h~_k0cks*e9A{lj|1l%`z;)YpV*kKY=}ezSFY@!)MS@5k8`1r_y95Sjyqjp zM{@wn)4hH-x42tx;sCM4b~6$A4>tC&pIp|e)Xe!Zdm@4#+-rSpC|yb_Tudrm%&lCi zY1RQbaXlSirMy{(tfwdVZYGPDgtPe_K--sI~-{xL>&@3 z9TH*=%h4xwn3HDgSp$3*2;@%N+?_VFoVK`eE=jm&6<&m_yrSPKO6L{fo#F0PJcktK zB`GLG@F#*fHcHCLNTBo(&PHO6N5TjVC^TZ9ANCNyS-t>7JM0c5z!-4Q6TQs^v%`gP zHY(D!TmdP)^063Ee@q0(2?r$7F^%z=K6L?v3{bzClzCO^oGxWnnldMa5>A?y!JPo|EoH6N}V>NNS_909tcN+&|#T*Tm>jr zJoMjjumS+z4^zpqo@*C`<=9QtpkR@}@*wE%OHjcaD(8olVvTq4|SfR5F|#y8N>4J;^O zWIfrbmSlgIVgaI|z8cun0ax$mg3y;Cl9dSUM^VBjVdht5!Me0`O#z!PNcD?1z_VRi z`dtM5w{%UOzb4CAl_vcWY4{!dW(6THxb$Hrx)y)2i1JGs`9c=`CiLGD%8hb{Z6&mO z4iZr4MrUjzcng3~luhUWMh6Yu4u}>V-wA|ID!PM$?}id4JArhxlYxh$QU@Ck^7bAt zdV7pZmsrrFiG3UyH5Vp%6Qf;}nwJ#DMVWR42D<3OzZoFepcYQL_*D$J%Ig4qBhoeCiBbhZW{%U-WHj{Ai_@t`)wnJ0?7 zKExF*B^16%DOt>^S-#x`E%^72k(K)UixqV*@`_&+RJ;V$f6LHfVeZzy(+>JuS=}ZvlIi5>%xR88(kJ4saw9T1#6ylD<*_7*B!<-JQ5r;K2`=UVi zK^JnjH?7~#ZOYqa!kq;YqzO;X^FWW8NU+O`0d3K;-tbXx`lQi)HYb1ifAe#7>-XZ; zAC=wT?{#fdw5;E0UN39dC}~_xEBeEr2i@^hOvq?}_kfQ_x6}0^)U|YwD%kFcwc8_e zw2~r^n@~r!s8dGdv3Sh645wpB_zOnI<0{7;-j3Tn?KW`%zUEvOu}{PXFp6%MzbGl3 z4DsoV0nmAEDAQtL5XBAHmX+`(kT@WXyTqJljrs6kPZydDhtZA1tpBr z7DdC1E@4^&r(qb9Q|4qTbBe?{aLocB%d+8`VbTT>BA7^n8yGo!JB7Vc$4(ZkU9>fs!pENr##g|7f!aAftaBMCpbf0eN5aZS^BCXA1=SEs={@3(T2Jh zUKT7GmS1i8cU9qcaqent@@JvxL!e~ICuGiz`w&dGs8{nT=hKP5q|+b+;(95~rkv?e z#X?p&V{19MW)8j;9wsbwD+dq4s16pcoq>aAOBV;%1~yq-Vkf|8bWA%H+X3IDlRz~* zz#tFs$h|J~9v->Roi*Ysn2b`rl|cTic~PuclBgG>Wh5a)P~x8vcvTj3S`>Lv6y_jL z@kx;)mFP`0)PFPizXT_ErutqJ5_a>6K%_h+5F!nPeZI&YT*PJ;ZX3_%YLu3nsw5{m zZg+Rw=4$)1tMz8E>F{v`m<3V;w!6S}1G&?kcR4iVy2$#!ATpThu$LDmxFd_7_2%{j zy0(|xo-Jy5Z_ImTDtMDsxm?)1RNMW&W$0tWgXNO?S1AQ^Svj+%l?zoZuN#M!$~#`T z2Difjj*9DHQio}T2XtIFkYSj#K01BSncIuKR$;$K%A&Q0%VvWFPf%BC-Km|xc=y7$ z2f2*+b00Zl+Pzsru7m*>O1~Sf&y74H@S2eb7fqTao$kHL^f@l+cSGVIN$FqG3s+04 zS1Vee1%I#UTCZ-~xZSu>-e4)=@`lxnl5ggW_X_!Zu;*y7dryRCw=1g~5}-V}J%pRZ zWQPjE%>pW+m4v7V190@EOv2S$nA2&9qbmAkGa7KGT^^w40&fJ?IT80nL=dmE`tHK5 z>^Wih0|Bep3z2BQ(-*zh4|hD!<))l?CX940l5|c8qc|E8Nca0Xfdp)iKTOwvU!e{K zputr3fB@Kf_yYpwsYq}8WT~J|8S_vgdngm$j|#pY8P+dRJ%zDZleVBuThJ#js8e3( z65xt7FHeAWJf}^Vg;uLco>M2zKyWa?$lyH-d=CZ44-=p@Ki8&C>5?YpX;UDGP-Z|A zhgtf$A{h*&e}y^)Y9;Kv;OPMnG}u>a62{GtP@g=mOBvUvOd8TAO=*+nl!??d%XDp# z^BYG@<}rQzSX|<$$vk4v4(fHiYQ=r6tVb{J&`LU#Q7trdn=7FaYJ^W}&lWMe=g!hrL)Q!qXxf!u-eO(&wJ|2HdGcoAUylo4emOJY2fl{n}4E2I>!I)?;tC=U#4;-kwvT!LtJY`N+^20e_5s^G>*QPN9FV zS1)_J{Tksv>EZU2jc9Yjck)PG499vF;x3qxGHt3{5cfP7{gEMa`nY$d#NSPcACpu6 zh)eonPK5-tuX(rEN@~89)UH*uu2r_dYyD2cYDMkZ?Ygzns?}Q+tLYVAl8b&9i>JNV zy&Q*1E~3JVd@qvU=1pqycWn>g4+Q!>3JRKH)5ma#4mkazFBdo+Rp5?F5PO20z)x&1 zAJq5GXN9x_A;J8ryOl3GP`e7w}P?I;YQ=S3ws}oiij%ixZ))XCbmdnLJ}mhW2W?`9km+B#?sk z0rW@O43H8}Yf@%mgjS_a%hOWrTo{%^m7e5vs_fVHOnqVG@GxzC?LnaMuz8z{=CnTuqB+YOURz$XO z2%SJ@0{tKt4;q6$u5|B&4U&KZ>I%68Smx+gfU9l*Akgm zleoZKIvf^sEk;X;Q#dKOhXUxkU06HaLa#=qaLi_`0k_pFJ3QIIH9Kr#qPMUK`}i&w z1H7$8{Bses!ycYj1u#yBBNRfMfpRR6bSS`X3*UYd&tV(iZnHCT6Ax_JeC#8nWNmdw zy4&es{9!K@T94Ysv;S`rViVOJo2W_z&(c{h?tnUWu)1|Iu587WyOenQO+n4u%J!8e zaH{Non^`ssX5*%~sl5ETx~AV+yMJpRd;`=Db^5p~1i*Pb4e*%_3w|LIzZJ{h%49FY zeWqg~=Hug5%t;Wr@;*Em+~A-4c|GMKT4;9FAf?A%ggaC^_%?03I6`)Fh!DMudGDwhn) z#1CS_yTqYgQt?Aj8yPI~^Gjp)ZyK;QNSoItEf`bgftRIEhNIF9_+`PUY#FNma}QDi z(=z!v6e-+`!3s~GI%!IVpD?9KozlXungZbSb8zW_5gK&CI#_rUpXpMbLCtDYorJ(4wm24r-@0AE&Ff$V>l(@x(mITM6 zP6%XSlX{@-x{%vk$sI77vdAq=OcNd3%)~W2Q<~VgRtmVOBO2h4#I@8fsDv81^at+V zQ-TO6ibb*Ey*&A|JPZ8mAb;VjIQP4z2paCH0_YrY{4Ig}?saLwx+;4uGX6_|>Z5<` zJK%5dI1d=eD(dAN;x7;#p3Sr8F~V*w^? zxIpejH*v5nTzm@~ek)w7rG7CTaAV>U`&g7=&+>)R8dp#ET zO$3L}`iHy<2O_0;DMUU&xtfKt5<2ekhgeVY4j1NWsb0`*Fg*{BnxkPmIMjA$WF_&K zmSdgZZlA?CB;*|nlsGD5@LCDUK-}ZW+{35su(zXiDoWWBYba2z)O~XJkWlJ>&;DEpi|oZ#6)l9F-`>;NbylO z6ehMJ$TpmFE+FJm4E=}?ZU>jJnTb8<5h18HCd>*v2fXR^IZ00{+n4m&Z{lw)W>hSf z*R51_fvE6Ze#1*s=5v$&*W}FU;@dNItuI=-erq3Cs_l6hS2E-6`y|+7GAv?2CVH(< zt>{!sGRcxg|3Rl;R?1;Hoey*$cO!SP9ILQ!(Yug=K4Ee=ZbqL?1OqfTdS|S7%8;}S z0cS}$pHuTcC1-s}&HW=W_mAwtFP2x;T4DWKX~V{ymW}e3)jQ2=CG~5!>%ZM;U%S%= z<-Atfyk6P)qonbBUc+iq=^vt`H^H&b+&p?&_)3~xKBQaHZSooRrA)^P@=Y*1EkmEn z1M;@*b^&4+Fkaw*?hayJ&gp349)T*Nrl#g~CWv!mM*Z+<^b_I4LqWtN0^W5c^^A~h zts#c!AmLaj{%A0a*3<*Ov_nClAl8P~ zD`lgQPAHAKA06B+j_i@Eo|sambXg1Pw3k{a;q-ZJ+Po@lUI}HJGNVs^4jfB;+O$4( zN|FxcJPFxnu>9&1CbcjFLt%m|JB-2Ule)|)Rpw+I^xQ;9CWV@vurN20Ce%q!)$nQ3 zI5c9gqBSK$ng{of@%Zv zb0dpB;0J=!$k(CrrD**Jk@=GZ>Nj^)S@2C;u%;{703pA+Y*kjeZY=$ec(8ColC>6< z^f|)t$ydDW?mNq-4KVDhs8?@MFQl?BXE3hjGHnYOH;UO#cU*DzSWfqNn0f%O_@pLh z80iVET%2XL=fQhgr$vhds5p!bgiboPn}zCNkvh4g9uBFOOCNM|8F6Kg@>x&#ya`YK zxVPJcug6nwxA8#FiJ+KQsh$56Wxep=)MF0CqV@|By8@gx@p0P(oO7nQz{XP3u<6eC zh`Xy1#+N)=59xd^}nlm_umZ19X#|77f9N2J|66OHNw+6lz!9~f7sjWS~Mscfc!%^;1ALyAQNJC@QJ%z z$om5n*f=#dj(;TF=R#1ZZL}0AcRnHTI4fWu@^#!q#BFCXu1ca}?~4snd`z8yU0a+x zom91K%zK+y2GYXCTlI_8y(?9{D`_S3Ci9fZJYA4ITV4ASAnW$-m#uxT@7;e>ST*k- z`B>ogG(7NEnP@>QdZ7}%5Jk@l1IB|rANq2;+zB<*8`+4XCe$hL=TE?1%;93{yqWh! z(Npnpi;3C4XB0!Ve$9aRmD^u3%OJtwkEDW6>G@wXi@z1zT`j6xgKDj6U$5@?TGqT; zbZ-?l-}0t!WzFli+cqk@*Q@*gth)cBy7zm{z>mtlABC;oQc6F{6JAC}J@s)P@}R>J zq>gg62zktiv{KpajlH=g$aWKu#$6FRdDvYb<`TGFQjvE0E2Eoh>fh#OP06AMI9K(Q z!(rI{{)Cg^^vgQpiE!G5Xu`=*%Gqep@)M4SVGaq%#|6ZLeolKmLCA>$UBiK3;wg)q z0q(-s-JbZp-tIPfPM9S8et?(pEPAonKNb#SV zxIX!rCjN;sWkQ?u3@|HI!nisKFslhu!dQIrleok&bNnN7;%J;<*cA6jZyeU@fJ@o0 z)ePvA{R+(kgSJ-*{0+!t5%(yC9V+myjOhma*_jB_GK{7zY+Mrn&OA~h58q5hfi9_y zMTA=t#3D440mgKwrXi~7a3*F9c=|l|4t_0^E=K4+N|HW9{-6phbc)vF3fFXiIhU_$ zfIJEKRq2L>j+MU_l?~>Tp93@>14M7Ro-a780pMyft@CKVBtvdE>*g)S%|hz6QkGo> z-SG|=RmDcvvyhE^LL4*_Q|^S8khhKGZ1fi$U$Me62IdO73= zT>21?J?iTG*cBq(Ipbc=PuyI`U0udK_|JT~zX~E>H2?a)l9CT(T#NmM1V_L>w{R>S zb2ETWZef&LMXHgOJM&$`?-Sw{pnWqDtt@m66IFvhY@qKFaE=Gb(fTNqIMqF#xPwRC zUkc%$3wGRONgcJ{Ms+8~ z8xo%R1dTYOszN<`@+;<3?yVT}mJ*AWbML+_Xk4o7S;?F@FiKHsW!Znv-BY5Q8<`lYxYig&HFW1|Df5?D(y?Ib=?KD+Fv__o#x)7~ybyUL6nP-XVjc(- zRx1#Q1zPau0|NYkU;@}`?c@{pdAVGahBFG~p%4rBSS25n#`K9px@E#4Eo63Q%s>m) zrN2;Q%C=EsuCu2fLTFzPMy@Gz?%te@>4^~V`cKVA<@E|G$f2ACJvk9M~#Njq_~Gh z!?02_pjG$k)xf13RKZI&s8RH3fWo2Zhx?IQ)}F}nA$DIdk)|D5{?EbKIe z>pB>oAqc5-4T=}C2&JXpBw)Ug{Z$zMIYRw0K)C4Q`-0Ethq|C&&!?TYn3yrH=Cf^! znfA9i=(`MuJI<(T4m4bH6OY`+C$~A{TDdSYTjUju@Oa^1JK%xCLDpNgbzB#p(CJL= zg@jxVrQezTn8zLCu*Y3FPx-uYp3Ar!=c%*HukO4FZ_b3j-$Y~2yM%!s9=UIMs%gZ9 zRJ%=_o16F`M6%!NN4*@c3Fs+_?aUT+M+?RReJ9;m5BRih@Zh3Y*HBJs!PH%38!Nae zHgWZ=bAjleDWok7_8~75$6PGT^S=>g_up*WZ9MuB*sc7iCn5>Qg7H?s{`Dao_NN{S zaN6mL+~EpnD&?RzW|tTKpdZc3&wjV3=S3mltHdpQ@*z(ZNt4b@ByIQg{3TR^)quVU zx6j$}XEMr)A1$beHBNfD^?PEg#lZuO?MtRR%cjDmguJ(z)o+WN7mMz`ipzrjJ7qFV zrRU7mH@s}^ecRsix~p%ovHNXR$Lo^DxsdolryB*>^O+Re+dSl5A7YCawbh^79pX9? z>M}6u0H4-v8*_kFJ&_|f|C zucqO@I)?vl8U1Jd&|ei@-_xts^y$Axi(fi3Mx4&vA{+wqx=4rJ{??m395?ao{=vp< z<72EsqL8VS<54Bqqh)n(lj9%x)9(_GiLeL4X{Vy-=S9>LK|m>IoDL-)52K$8=UfB7 zSuyic4DxU=a$f-2${z&+Pq-!RgIPKdeIN+G-v_(T4Zp{Yc|1&jOOFj~k%)(5#lzz0 zzKD=MVPv05J*G>ZR%OhaGXaL0Gp5e~FItxd#Hv~7r_h46*)#I=X-&F?DhaOdnv7{v zhQ+}{mo;O|nbv2`#NV1VX3dy#EG4f`ngr$*?8PuYL)+D*JvAm-E=N$dri2kSfK;YI zfT}e5M<&xFvk8clkBr(Oopw;Ah7j<6t@^%6+pkj%=u|^$MW0$RAeRpPM=3lc5kG{U z%Ote{(o4s+a)`|wTs`Q2IfNz}s+kTXC{#NO+X$F5*}e`UiWqix_@oABNRn~+e$8~l8dQ^JP3fQV5H}f+Ii4?$xq4Kk;xIcXocp;ZC@4 zC%s)BhX*~6GtbH-Q$g~VF8UX!Yb6M$duRZ}+{c+wlkg8X!M`snpe_Y0&H~3my(T~O)!pCcdi%PbVtLu8x-1V}t>t##VtNPa8s#_OInikB(Pnq7$ zgq!y~iJkt=qfvsV((oyX=r^6}l~MmD!Mtcre3y~=AwBE&{K8Ke1)uYZzhstt%fG#v zQ~WKX_*;76A4x@DvrE^~%U1I$*K@1ZZ#S&nZdtABUa#$0ujyJV?^vyATQ6@}ukKo_ z?OCh2|GnB<>u~wmh)(QNZn!=o?x9`3-YR0_q1=RB@@>w-;e<1Zt z6zz04=R!F3Oc4D{D6p^?zlfc0NU&!jQ9#$U3baU&_IqKD2B7!(fq4S)ID9bx0imw@ zTo^}!{2Yy9?@DF#eVJrbCLWPQ^#PXyVn(&#L z(1oWB>CfY`Cly&hnV!++%*N%;>htE}b7$aXx;2xKJ!8&+u03r^o-#m6TH2&G1B&+< zG+$%VV^#cPt$9=n7b3%;-Y}%m4V!dBTK#`$liG(`4Ji7D)!HGYYFMRwpp@TNYM_b- zm5Lz{B}ru?QrRQ9;*mu5M4=uBrXq^~fO8ua4Fuz6cS1c($TUndX=ToblW?0hYA3Z+!zmBz2`!OuVZ9y0l!it{jSOStStDVDEO+*TT>OTsY<_DxX`y( zrI6)ax-Kq&@T1k>_|M^*ciz#=a;gG}lp z9&?1t8gb>1aG2xZQp;mKJT%LKjKH>5w*xaXX&J#TDw2xs)Uoh())aNFcb`Sp$ zS-fFv{1V_f8NwZob8pY^Z%7F1l?g^e+#d+IL;ik~-n1^tFA1cb-rh(3gX~0kKFOF} z?&!@F+$Os7S^p|gRvbBwWaVxB6PL8t4Y|dQyvvP$Ix@mmYvN>tmHMsDGuH@k#6Nzy%%$vb_Kn_Z+BX#iFP!K2)RUaUPX z$juDqO@&c9Cr_U##Y(nL_;v*?I9wfv<<{U$CBVtg%0E2*g; zQ&ZmO0Gbt-e~CFsOeq5*SFE~aHH|TkGcncwU7R29sR5Q@!!2q z|GxkDpCCDG8~Lko;ICWvzN^fi03oNLdTAF+2uF+#yMp2WfWu}kYPU0Lhb!rLxa(P6 z5ILpr)^x?)S0?Fzt9>^8oS1PzK|c|~z7)Z=7BeqIV5|ZNN5cpwBPeHuo-MO`zk0H{fW;CN|I=fC60u8A)th1DF+i`ppO;-oz*uW6Udxl#i0^ z&+5D{%Dg`e1>Y2)j=DZ{#yWq+3sB@BNf4t8*W)SCFj78VLntTrwd=p3C~LN}Z6|C99A z(NW*q`u|_|cdRWgg`kB36(}th*Rf>WH9m27otezU-JK+axVw;q2q7UvCx%vNDHehH zIrp4QNN@Ct~DONJxHI#R-9ow%C;Nj zaPIQBGaT-`kUuLF%n5k&eEz&hILqgukmn_WS%GNDH)PRGKEb(MDrdKOMomW~&*|c3 z1k_1a$$YSQI>YI9mQ!1fUstqKhr6gxA)R&=-&Rl>=;soc`|Vw>`6BfUuT=BD+gbhH zR{WV0atYnP3>BaBpzN1h?PT$exzav#lAraFo%D75JS1C^>0%TmIvYTRegJ^e_XVcA zMXX~UB;*48T`0KV<7E+L^`5|Hx5)cyn3kgD9aY*Lw5J}ICP_5p6RzgFxnNVnnq;|$ z<3vkV2lYDhZc5CHe8laA`OA4X9>=6TPRe=|pZ!>y{ZN&>o|L|vQK&C(deGSYb#u?d zn=NaNoevvZ)+%ZiuUF64wJhgV>cKil&V`_8RTJ|hKH*s!V#|`Aryz;5*LkI{a!X$47Qe~G&tiYax6LE(T1Vb?jsDa*_H*~-uf2DF>A(Bit$V)>PXEz!_n$p? zi77g#_HC5rxlFiBGwq{Zs<%FsVz$r4=pRCpU0m}$T$?>I+m8ce=i{8IB^AXhbH0>QUY5r^tdH2E|5_b| zfx_8rKekv(a|1W1qs{k;t#?c8j=H+oq=YD&Fq8rZ?Grc}=spnOI~W>0rGmUUXEinx zmAe*~v#LTN=PV~>VJo$mkh2(_g^s+0fjKsNB|dK@zF7auFv&0uw6e*B zS)OWwEmkYb8rJ?s)Gy^)Ehuvwt5#fpMA9WkuSZ^?-+0G>pYtL%_jMGSZ}FShVo0Fh zM3!$N3n{Q-JE~$Un3$j6`DI~$_1Zo1xxEkkzsnrP0Mopl3fu2znUu5Hl#9i7mjQAw zV;bJ%qyJjg2q{e*OXw$C1lCgS+kDoTh*LdBnH_f(ogu2 z4?A7^hrnp3hiPIu8QiCufJ%UDUtQexFNF^Nw!DNo{39_dmaq-Cz; z6s%U%KfKxTq^0{|P4k1=wud!Mt2fH;=cSF*H7wP(tmKz07ZfaK=Pl_H^=j4AxVUF{ z@TR6cPe}S9CE;0W;&+*usN&~Y*)MX7US$>{X_UAYVgFoM`6ll=zVPzhsA}7|(Xx57 zd%L-JyQ%Lj`fok9(EVGOrJDw}T8G}^&D(bSUDxP#`{=vwJHPbY`K5pAm%*vuMo_=^ ze(#_7y=|0u8t2~J4vBguj0ISY zG)W66VNK$UN_$tEfW)+kDD6bJZVY;=s5rtTsEQqp(v0ZT!{L~gqi#n9g zCaQ6(ttFnoO)M+0u6xRAoi-on=(QMetFy5*brBf=Uy;a_lA=F$716R^8fz_^e`{xsY6LNV)V zIs0lQ+q8~p)&L15*Rp|2fb}{ce&%8&PVNDc0t!zq$X7OfT!8Gbc7tZy5{2ByqxSP` z2YEowGRCFs+X!o{Hv zkbM$p`JTw?Z!EhLvV2(z_o&k5eX;MCKK%3UltW_DK6{hD^UZb$M4$TGe-gq!;~hoP zxnGN;9CbB*PXv$-Qms7 z%{uCE>F?BQ|3x+YFDmo2Lj)@|Ke9V8e$~@;O2+I7_a3h(SybhI6Pfl+Y|0Z&+Cy!| zqrB^n%i5kac08$RMF`8I+V)3vO$!zIx6^|gYpP~$w5(TmJ}ItP$t{{sOTQnVyqKWH z&gz@Q_-84)Z*{t7x+DZE{GdyJo|*SDr{HyV;fqv+eHXvVEZQi#{yMwjP2r8rl7=@` z&CpzJqvtmFZnpHjtsQ*VHME7wtsU5I7<$`2{I>b_yVlXST@&xR#((L$`zz|Vck0*v z=|2W$ejmF3d)L(Oy_3IGb-zn1+VlzfM##NSfEp0VaY}0m^!gsY$p?JX4+Iu_6!L2^ z_E%HXVO`ft*UHM)oLJSI^E#UoZZ?O#O~La&;AD473Hzb>aZl1IADd&Iwr6}9XMLz2 z``KL}TCmv>XM#(45Y5-Y;+WFxkSmf3t&h5cPHDPJMEy`MIv)}sDh~H<4GJ6ekGSLK zKN;Z%lTNF7)2`Iet=oCRQG17Zi3eeghkqd`;Z<1n z>u@NXi{Av5Y(^jjxcs%MbRz^V2ACR(;S|^o%GeA@d@|k(-ZcEcdJ*GQLr*HXl0E4U{%JCDwby{w5K;)4sBgy%nDallLj8`(&g8 zGQklC@h3hZ7O_@)M23H%nf!lLwEHM=OpYki>8ds)Y}jA3t`Ltq2}Z*Grb=%-h)w@G zF6~KT#@9)OUl-IqEpK^xv-4?f^P{G&M|k{J6iyZ=bi}#cxOx44Rm;Q9!ACW1kMhe` za`WePN%M&b_v4`N)qJat`7S2r`=rF@@d-bqr98{Z{xQ4YWk%kMtb&(WWv{YIUT2rS zDy(>ob5dEuMs@o}10KBHTlL*r=)X<3-Zl1PX5MNUe%Chgw)OVg&XJ!wZolgo|G9ta z=fUY;hNpfWnE7>h=C>iDet+w^hxhNV5N_$xUV3{!Ws~ocueFoUmy%9Iz+Ygwmv6a? zXYxMQdX6qeTES;gNzuc_MXQDRt3t{R+fO5Hj=0(!^)lNbBO|}nz{UE6r_~Wpn~%I` z=lp1=yvfIWD5pHBr@gI?ds`ZKTf)C^$jS1Mqv=6=Hx}eK6c#-dmocZ!U5+b!pv}SBN{Xi8C7AT@`l7DkL5bM`}i562@XRcT~D@ z(CXBxabT}vq9>LO;`!Oi2fT^wGmcED6&FJw*&Lv`e$x}fZ-PY%-!#)+)*!L z4}g_t_eBBYvvjB^85i<-#-&`ta+X>3pBbkA=U;#;s+D7j-y~3Ow6lPnwCd&9^$025 zY_ROe&|kqMMSRGz?q-pC*`!-y-fd5hX(9WLj5{V^O~|=-B>Y*iU`EKhFPF@T`S--q zX?xyXF6)kvdq>K?XV0H>N_tj2^_xS?w?fH0v9h)v724fVDwiCTYe61*H~Sf1r^Nu} zoXUIFUvb-0J}Rd+(ZB&a7-YTAQF25HQkIUU38lunTn>R464zui`?g{C_0WE?=#K+LZ_Z}XwVf!TdR!!W+$hmMaE8fg#rjU>g_O|9yOU) z{x~Y_Nqp|t=@sARUVob32=UdoH(Q?6wLh$FTg}fLu1{%73_||}e`dA0^HKZI*EicA zl~ygK6)YyEp%Krd<*tUtK2^nir_w&lOna_Hv}ooJDB<*cbY7@6US}1*$|-%BRrR`{ z7WMn)X7^Sl9=~nqzi%4{-Zl@sZ5!M|*|v|p>m=&;UEA2t?Gr!u-ubC#@@FvKd++=* zH1o^g?C&G9zYop+-ZS~nhLK-OYqw*x&s|*}u&hS`@CQG{a-YBTev!p4j@eE=%v{z- zT%5j&=UmbhW#7*)Su4n%mr~0a=i^Oxijh`kbJ)egz{U2sht(ku@^N?C871ksyX8?g zD|~X)-SQ;*Zvc_2a>&){sEhdl1wroJqd?fG`B8T>10_zw0Hj#&k-XOYev(b^@a{aCUJz zC}4@;24t9mcc)6Yk0=%bnUw$<{48)=Y9tgVE&`Vqq0xtF7em#{Au)?QJRWJCeA_O* zT?c-^{LC_IW8v~^-T@Uf&8!jcUz%|(EQEGOwG`6^s1~`*+YkG;G^8ESUokD3x#VVI5e-5nZbmjZN%yhH-Ox|6u+F0NKwiS9 zKtI+kpyKC#zU?TVJMJPG=P>UGSrc5wu#|sSEJE?3vEJizr%=B*B*}SqSvV6j$Aq+T zT(Ofz-!~b|UiV`n8?JGVX!aeC> zv0qFjTB;XyA0pM{l!NxnlWw#FO3Ho(^_a8E#Sk=T>H!7mAAD;A`z%%p|D0E-vC8q& zAp6h!s0Sp}1F|U3gsRYT!AGu!f3Yyx!E@yoN2u=y2F*DNZ+nPFvJxgQ=Y1`q+l*5f9Xc!!|su9x`w~5XkN`O(`RHa z<>oGA=g;TlFGgz~#6*9s(tIDQ`7R;#d1}`4#H<&o1wUpNzD&=3l~(qutolt^?dJ8C zjk@m5n(nQJ-tCsY&Bor%*1_$jL9Cj$yGDun?HqsGe)}il&3osUfxEw;e*5qJ+JFDI zThqS}&ivkgAF%h|Y6gDFtKN!;`d%VjrdtfzT&y)UNCor9cn8a92g__X&vK{G_Oy?) zq0Zi>@MiIRLGemb>>Wp1wa75pd=JQhKw3$xKXkD?f{+w%(n)uKKFBAPB!D5xyX_HSgGOw2&;=v3`7x!{2^ZV~toMp2M?9RUInkc&QIXT( zk&{7ya`+8_%Mq@=r_I3g7Kfo#9EswH{=1?oSX5(v&c^+BAujp8Iu+U~oP_R0CruM( zeBC`&!o3)jZNhYn?v5%Bgjm7`2r!OH12zuQz45A@jEJ34#S@-=O~Nds9dXGsiK%mO zXt>a4>K3Asm*V2@N5jmRNMPY(lIEg_qMp-$c{8YGBV z@V0Ttuq|{jO}cFHy0mIx*no=#pd7Lo>g)__c;rSVfEbJkzDzImeB>DXok#5Vfk{7x zg8vM{bKXWs$rj2swsb2DDvqM<;Om=FC0pQM1!ivf>t4D<{^;QUjly|e#JvS65$944 z<9sUfVlE5jg|CWOm#%Zre=VE&mJJYDv8{+Nh&M1W!@SRh7|aTzGWgHv$k3ehz&XXT zfG7)c%3f@=5cw?=Ksh-sVo&hcV=~@t5qnz1pAmBILV_jcPfB9u!b#c1qYd_&AnG5n*2y&Q_ z31{TCy+W%Nd&^qeQwi1wJZ$zm+Zs5EKZion)AR$L=?;$N4w2O^sUKOZxEhN8Z;%fw z7$=leWHIcO(T+QcKJl^It)Lu|<95mZ$dmk`oMIs3e&o*o$cwZ`M*cu3`ou4uoaAd5 z6?`Su+bmj5iH|o^M_f@iCSI?MEaQFddF3zGhJUjn9kh3Is02dI*>m1YHsT{4F3QoD zA*(L``^3^`6%F4MwS0S{;Za%jwZ2)2%0E zH&${Bmax&vF4CuF&FAILN2u4LBcDdAzKhpBOGtdKNqLcy|1u@_$Ap|0Sx|ITy+QN6 z(Y#UHzE#_~)zG!ojGJ%IRs;Gk+AdzcWAEC=-?d;jHT+Z0IBrHi-Mae=R?S1iqsX{MuMCkQ;dW-3Ml)Z|pO?mi}ABq+tDE+im&DGhSX`2?)F zk{1$^h!`d<#2)YkC(g$pUL43QteXF9zA?ImScD#`mcljq7&Yc+J&V%Cqj&O|y^wHl z?b;v@V3F|h?chn|ahmhIJ#wq>gMr~Q?d=_Re14M2ojNswxSBR{4%x!5??4IpDR4S#_dUrJuu$6mkP*d zk|<{~X_pG&c>!n|FJGo{9nYp&XhTfS5I;jd3AGj9wo_=^$+8~cQK9zigb|o--VHhy zLX_Chf0DXbmVJm!a`0Fci0%v6BV4p#&K&_~9A82?VZl2{~`nNpeT&aNkWaAz@FuyUzK$%mzEJ zcsZ?mN~Y!1E_-UbgH65oY60V14DGP9wE^HxN|T);Q=stnD#!<2LTnR77lKXxE`Sb! zklJ1h;haVgl0E;77v-R%*)B2dh$GEFiAxhy`s9NO*(ZLK4;{HjTm*-eZeIk(*(SyC za?{J$>oi0wdJFNKXFQlt~wKDyO4ehjhfO|t=^16@vg0pBW+;yy? z^Z@`_AaxYhep`(au2?TBdQe>YprT;vdUSnF&PZy}YFg3qjpp@+?#FF?k2{B+lsB&C z7V7g#mx@XkGfS3oisp0j=40cQ!y+E5RnOF#XR*mI5;9)svR4vAp_qS<~y< z&W)RG8?_x9&0X6q-CNB=+fBFL_7eN6w;dx`J7a&f)js-D$M{b@cYhwd`*T0~@7>=9 z?&0hA?y29pCVp)i{^e%p&k4D&{k*?sQ14k^YP305V7Ncr@O|;+zuFr9g^jnZg@ICO z7|%NySgh@@$i1Ieu&R!}t*|Kp1D|4`q?~Z#eClX;0weE+290^R-wqCk{dOh}Laf4NjLo`?g=oUXFss2mHxa7H8BILwe%LL~=pbyy zayV{ErMn*$i>fC+)BqA2KNXAbz)NbU(NE)&F?BD+q%T6OrNIU)bD5~$%%ym&vLW_J zT}nn3r|RQzGKTR#c@bd{sNaa>B@EAzFiH^6JZ!G!W7P{$Dt$=wB9GF`rC|l#&9wy} z9cv<3Zrj;ph_Bi}!D5k#EF`*l6V0^Q&iE$Hs19lAT-LbUVadVkiEHpPU(JvH$Y02K z9a^{%R=4}kKE*yegT*f^!p9;L!IrIs3wUodF*2x2)K>#s>Mf7)I$;mGXeT6B0wMx5;LyE!i?W%u1A z)4^^lp`MGr;sIYtj~lbu#k!PtIe~X6g>od&c(=j^s-AuB*1Lq{-BOByTf8t+aXHd- zj}VRq^SwgeNA8kOLvcT%f9OIzoF*nw6FVb#_%|SW;v?u3;JNrXN-T_B1 z!|+@|ULrTM*eMTrE{xq0+G*Fa;5=ue;H!VNGklMJ?LD%|dla(|sPuE*;o+U(Ne{d{ zX50nCq3&Z9RS$D+ev@DJIKSd)Zqb9}?Df*(hxzG~HzI1QbH|Ds*GjH0R8`KwW(XR5 zbN}P&mi2;CeM#9;LCI24g}$h4A^*BQqj)(neIX=bJv#iUI{tZL#`E-?A5*Z-%70l< z@$!1Z>#DXlRZXue8@Dh*V+GwdNa&m!`?p($w(;_9AKC60+Q#t+@85w*6z?yC(?4U1 z9+>)d2;vQFuEu|@>Hej(@n?0)D;MQcI(f?a^E$H=S*C{q%=Zb9Z*Ke#L`pf3k9jzs zk3)Xw^|-;@l&Qk92RhZbt6ee17)T;*j=NYM5CIHpe$W*sA>@4n9&2&blX4v5RWI5Z zALYcc-z zb-{rn;o(!kLF0bjL!m*#2uHw78<)4D$yp-Ald$>{8Q&Od@5k!y#o)4|BQSJCBi7xI ziJgwtOl!0=#5f&48;$QeqKAT=rNSX81tQEPE!@Fr_*H;ue2G|sW$97Bsw{mX6xUFB zr7!BzmJungNhE9$@FZ#w=8^y`00FdACoZWHmI0?lIcs!F;i`G~cksXzvpNJ+Osee? zI`Im|)|W-@qN9GHfU;@?*Urua=cIb3DY1WMv&LnPOKt&AT*JQi(L4uOBRKO#NdB8p zh_6aEqKY>I;X*3efDt&nglN8jCGY&Q-v-3L_KtY&=>3ho^NNTu# zCh7A$(&t4s7b}s1M7~-D{uR@*nPJ|9voGO1qI3#uIwW>&LNX*+kZ>SvyqizzVOrp? z*TyzSGy|+sJp!vfF}csjeJrK?DO;DNW-C!_hh3pX?h!dha4&poZykQw$=r$c<>vpC6tw7ItS698e{e4ep zmgHlCYvryM1+ptCvhz`#&mtVm)7cl}tqlT6r_`KFnYJe*$-CsF4;|F(H0Ns?Yfwyg z@-6oW$onP2bN-yuzP86*8IV)%l34GSA)JeO%$4$?1LLHUd)iZU+6^Fg(P{5+E1i}a z&pz#jh+*a)DQBN@*`JG380JGp>m8UD@I5cHmZPI@aSvSOqfWGr zSkLLIiicoyWEMY7$$_ZyQD*ML{N%~X;2U-My|p)|s!IkMODAeO9ya$qZ0uOAXnI&& zv0PBJR8+i_U%FCUzL;0GSbBZA@cIfwyiw7sYV~7P!VgIqf6mWE&ofG16j#5hY=m&-4)PS0g#-@7 zMBniVp7Qq{3iO7qa!i|eU!A^^fXgoe&JyPnlIAoCSU1h+;_gSPXE8RbHTR;RtkB(8 z=`c&**CfovCeEvonUV>C)`ANE#dN(Ub6J(OmXNO35~pDzD_otmq{~=|&(SAkFD9oi zCZvNyOC*VFVf;@bda(*Lyg&0?;5&xtNfi(F?6M|lIZmg?|Abnz5UE*UQ`-1&3c$9H z6hcZD%=>IgH=o+UKu0D6*4oOpLH#zsO%MM9%j70eO`K7CrzN@1W2Z38&(DIBUk0SV z3C+g+cOyKXu<*wf0i?4TT=q7iXd|q2E1>XQVCGx*#Fsv?KREb3b8uYeGsl@GwTv%v zEl(v|eVRc%pND*K%B6C|Eio)==q7L(H?XWA!)_r88F5IK5I?uGEPL=bB;LQoIt#|A z4!%_zAMgzuxcGaSmi@@4XOo9~T*jRo?{a9jQM>@<;Sh}a35mbTTJsFu3@Lp zPv4~fSKaFWmaYA7V(VKzc3iA}s5(X5aVcj^&bcLI4oSH~LTZ=Ty3JL5C)jVv#c|F} zH0dCmaTeco6%R=a3;0)4g@#$ut2x~B3AB@u%ui!jUuZx&r5$vm>~Zw8j1Qxv*c?z^ z+bM)?0oEj216P`XCytwplirqyJliLw9Fmcs)VdJp@I?r*>H64y5Z6O~mD3!9%M7vN_~4-Uv+p8d$Ts?KGfEiZ$=g45jbMv~yhUC1rFvuewOkW>Li=SEl(KJ>6U6>4_agLc~6^03n8C|ci7gJHN z?R;7rn~eK!E61kQjxZl}u*i*EXerH`$X6Q3C_3vtE_XuixUBGgI$?R7otXo`CHTis=)tNN& zlR4I(7m+U%Q!kd;8dmbmZo+HKG;Kob#|RBcHp8NmhS#n&9=x3l%N{n)zUDY5A&#&e zcWMZ+nB;yAsgH@sLWnBuZgHsn0>&sGkW9gpL@>=}-U03dQ34FwC@LK^9)W3_PtLQp zwSSi`{lBuc|H&Btg(sh5l5cV816;-}A!`8mFEMA(fj=l^_qvL1IdBI9UB^6}=CQ?c zby)Orysvbe6`9p4S)Cs2ephy{3#(UR*&sB#A-7Ja8hBXml7TSna!rN$WtS=Xh)n#2W3UD@`yu=z=S^Mm{{ zeO{41H+w!W=U!&+OkVCxQQ2%IB-8Ed1vM+!+i2n*>XM#in=pMwAXu-erP5ufmaACvS zq}&Z3|HmxaB+alLXj9|;A*LT7Ba&ymPhxH0%fApKJEvA$OU#NMEKMA(%Du+=1 z7q}I4UOa&>?~)@T?b;rN(LPrczR7OLMPv|iu#bBPFU9#QYQlns!y+aFgGRB1_H`eK zjU3g+--C>qc=O_*qn(b_;IcCx9fvTZdpekZlNV5En#`5BELf110l$Jq3vb()>=jkk zI#6118TfaoCr}<)5KgaZa@N#YtJ-`l#E`GFto`%liw3Pr)hDOTYm)Wa6umBW36EuX zoxtkBcQpaC#a;11hY1 zRErinOJaXTHExF477t08gI?zOSQ+{q{J(+mFJrS`tFU}7*n-tJvS3SHv=xmNR?&8N z0mkX=$ozMKsat-!*Pc<&o&CS%%U77TgSN;g{i49)bgJbiIaZ$**nClJbFm2eNr5$T z!)w`=t#)Ru2o?tzlW7KHGO>Kdd7AJq;4fp|33xmBS4$1x*g`~ekR~`j6tp~ zQonEW8Mk@NJ0kWtn{kI{dz)!D!n7S`L2PCWjag6T;M?}K{}eC(zcT%Q(kK2SkN$?q z=qLI(O9Y%cFrTi~E5L9aQzL<8*$Jk`?_C?_5LzOaKcA&KG4Hh?-ZMZ93?GNn=lorUU9Z-^Rh0D_v>k>SkV?d zNzGcx4Q#0JF09KRYwUbnRQ;f+`Vpvijr~vRdXY@}O=a7YqRO@0B7J7=Vph(4QrcW< z=6rVkY{m73%EslY*0ti=wdDL2b@FO*>Nm-`xCOt;EPZ*S;Y~%uMrGTZ+OCbpURd}y zYx_3Z28sPu`|xJtpBpXcH@ZgNb&vksGxl@eou8n^>K*$TMGZi7&W%k#@Elzp*jWwR z8r>v+o@Khz4T25)%Q4?AXMGtfxug?(9Oll1V%r>dFG`0~(X1M$pESsu_3?kU)cB&cg#1-}X$x24ac0Ux=Us`(Th;;v055;m zsyclQMIDQt3qfY~S{$MJSi^_dj76hnvC$$jOc&#mvEqhNafSF9pdJj;gfaw+tob;U zFld%|Q^zCEWid)MFQv3e>76`kH(r-ATYz+c%>fjylTU8Of)`#w1O);lYkjSjYE(_V zQVYyGpEIriPs#U@Q|R}e>L2}*UWR16i7MO(&EE*acN~AAg)ZC-L+nBUl7F|u^0s}_ zP`|H~5kJ~{e=Cr$@L9K@1|ff1KsuXB{xsA2lUx#F!M`kJ8dV7_YuKi>NH1ksKuH2x z4mxZbPSWraGQk6}fDssyP5=k6f(8q#lVR40L?jluM~J*{@&K1Mz+-@4hn@2{mo+A3 zjdEDyJmxrqHjEn?Ecu+vt$e}VnyFuE^#7??{-2zge;4ZiC%AswjypxS>ZV)v^BA`k z!Z8JBK+YL-BfJjn|?qg9h7)+^K~&}flhs1q-+=Rb(L#(_4WDd#qvpQHbpuZtdY@izd6-|loLjt@U2s1sVo0Y6mA)K3q@AP@Vg$|g>S=12+i|bpgGd9=ZtzL70%fj_0cX>QqRVl?ZH}J zV)=pCWUqtNG+uT^$No4l%(<#qb1NmJzbt(^J9RNGY>a*}&1}Dm zUVGej&G#e90rE(|C;d$gd`Wnu9PuU{^RYb@K>OIAe8PwHk&o#?XQO>`NXo zU|)6066BP)E5*azkoQ27yQa-w(-p4k3Rbl_P(iOIWG~15={i({-9eP_nii#swwtpa zm%XmdUDxESCT3!IhD8zcvmW|t%+d+T*k3KFQANqrj>P27*^pmfGvo|7g--H%zVE-J6Ei^GdBRS=5c=21m!k_(tI{l4Q$SK0L2)XTLtpBIomM)*+{>1;ObYN_p|G8~1O#+aY$Kn!46Vn`;wV@~El zHDT2PejUfE30e+Bs1Wxfn_jvFD!P*iF9Sj08|2swu&K9j-UWq2%pDi<$0Y1w0c)7c z9HEo?gmyg)<2L5SMw!!G_3S@O_5V{h|L@e<|EXH}S7O_*JpZRGYCprOUnCfFlux<{ zZ@Uw`(;+9xq_=#+OEK(V+ohnixv>X4T^EC0mwnt<13l(FoELo@?kRZF9?}VahY?5X zVq^`Nei&|ZJlJZN6Zx2nzlBD8F@kE~2KW{EkQ9q(@;HlpOoiTQ0Z0Tbv4{#kH`Y-Xd=p1ZgIfL zh-l~{Jd>~fjdk@O42uuw2h z)IBMxe^S)^xTNI)c(ZjKj~cojRW`4cHmv5CE@u|br)A$y$y&&Q(xYImxNM>HroO&) zwe03fQTakj>b=a2dpQ~Nd8H3ZZayn(cv;o_y1x5$bI)eeATcwy!*DeGwjImo!Hw45 z&AP5Pgs!9iZR^NSsOy%YpPGAsnSEE;u$i3m$|vL-9&?sz)J-{GK{~BA-s@tq-^pr^ zn0hu)b}d2rgtroC&DjA%l(dKsNxSD zaRM;h1Gber!WJ!$c~L*|p&a!El#+SgmwLvJddi3VXO_3=K4+6Xz-~)TVQ1KhDcZ&4 zu!kA)Mt4iB_et#xT=-u`c=Aevy?VnU$NYmw0=>F@mE8eegE5g~K&)eptV>@cwokb$ zFbQgk(MBI6<^r~}ri1@FZ#^*|pRB602;<@Z>7_L}D+&2{{OaQ|E$6Pq;(N{-G$F*m zjCXOmo>*$7t?1HM;?wmy;ChnuTI4RJE+(WdYk})YA}-FFKi|b#T$~Z!cqN5TvLyf?TXg~GXy$8YgwOfgg(+u%Q|FhZAZhZVi^P2cj-zIKm(;phwf zm7d8MvAtSL{v_MxR0`#jbjs&>R3M-)modSgG^@4+#oZDCrY(2{b1hpLX3cn{1BOZ9 zK`fgIyq+1Rf?hi$nwd7*nRK8jGc0UTBY*f+zG1NMgVg~k%)d7Kg}}Vq9d?p`9vEn(5`7x%{Dr^E)u?Ez z1cwX3c84W)1`?;QLM5lXY~JGsnnY#Gvx_}TRrC}HHjMX3tPUtZhR3{z61Lncy#}-Y z0g34zzR^yO(FaWP4_I&(yP7A(D{GzkE$q+JoJ{ibr6q;-xxF`Tr-pY|RqOMbzAmYG zTw3?IwDD1O6V#Ot8+#trbv&$US}&_x&aGHV&znojUMMV?&o7%VEMFkTjKJKx~t+t9b!+`rL%d!uEDcndf6Z8UXn;D`49 z&Gx>H_Mvx8gi>p}w*MVm4|!D^>a14*K~K5#S<;m*>gR=&Gb%h_VdyhCpir_h6sAco zmsL_TZHj+WYGAuMU@%QJsfk?-3cM%g^;&-vWx5y9z*3W)*e%G6cZ<=8A*aM|0OLI_ zmd8DDMY05K@`RTe#Lp*i7xpB5>}Pe<)9fg6+#E z43B?Y&KfFOowFR12k_3SDrY%1b4`U&Id>Jwq!^nund=FKYii<;Kmn|(GFNrjVr8OJ z6DMG8njSqjAwwUZz8seZmF5!KEYuzz+8edeKh z?wR~DDCbRR?q+z=Mqu7HK$H`dyIhShf0>RFIbS_1T3Nffq40(rn9S zfOLTBLjQ$H3fT}$#F<(5(Ji}SO=42|SRm>!h9IMYkxqQrCMe%YQWK|2u!-KR4(9l{@iI?cg8b%|FSazmtomc)}?U>7=7%+!eN8!LYBO z$4fNgs+jhW-*)B?d5L=6*}dM9AwS32K;IQF_lIt7>t0R^-trl5*_02vUus(HZ{Oj} zX%m~?kQf$oKS_4@Qm4ES!a3#6KBlxg1h6EZe#jB_LodTvw=crvXM*j|1t`A^cfS}T zI^)GX>TG++-sj5*#c?mnZeb=jJzbicB*^tPi~~&7Xs3io5I%xf0f{*RF%Qa6&NfHv ztv^&4@8*LkVY!oQwUZ}4>mEkQRXa5}lgnKUQ&X+tb)<+}c{dB9>u%-^=2t9a7O&-0 zKPs($Sa$P4W$k)x%lggEhm|c4D^R4BOL=8Wa1f(@3n~|jtMuiy`s+7V%j#Fk>Q)QO z^_fMBB{!Bzs`Vu|=JN~Z%1h^KptUAm!JAE8n=M0IEdXBiY_?*f)dyeFR@=ZvYY!?H z0!-hot^QMDNx|D&7RBRi`R(D-e?$f2DMrW|s%+`$u?#kkw$%D&RbK933! z7pM6(qy%;r>TYG~rsLw~{d{I6oIcAli6*;T@O#X7r@;7q@wNBF#=B&=7aQ$H)F7gc ze6hI#|H}A~hs_ZmtK&Z8Gl)X=qn!4Ezyom%fa(}w5wTNzWtZ&oP6=+o<_756&NfhS z9Cc)#^uylUOHdK)+7$#Yv`=q{N2ixlSCGd*bkr33Z&KQ#j&KXEB@oT`VFDq|LLslE z7OrUX*P)k=Cp`XWvP6->JFLt4vu4qtGgnk7^DKCj2(!Ni4L6lIOC@FE@w<`?2UFTo zVj31)1f>>;JXNxucoBm;jXidnJ`R*iEWpuulNMEpb1_I`(axf5Ma)3~v2?}$8AgUK z4z&+Pe$2@*2yn?rt|3Nf+1r7-*UIo8Wj@~u9hO;)F{)9m&DlJ&6Y*AO z(I|AKtggcv5w(zYfoRHGJ}X$!-o1@~V&(^g10 z=tK|$pd7tSQa_tIz@!Wb8RG)xun-hzsGxbbILuotaxVZQbmWs>susD;)zAKsv+(b# zmH#f7_#=JbkL26`N^kl(uyVuOZ^>CY<|3bVkWc$MOeh&WVv7bPtH)I^;_o`MZ?60p7(vcR^1$zgIyQ>6*GZgIbJF7Q}p?|%mhk@1KF*D^GUo@VZx7n z9X}1=0v2)1g>%G-W8kj15FAZP@w}{dx)_Viv+RryK4%`1bB;*3CtZ~nf*j5Uun)WH z$O-Y(q2Zpus>DlD8Wta(sT|EQ#L9pzcouvXEq zTG6svf(*yuqk;Muhsg zOtNZgaf@NnWP2fj^+^om-?WQ??zD6ViwwnA@vO^{slIioJ}s$1J=w7XMTwK@n0wxC zP{8()E|;4ffcZ#x?L7f@E5vL}`;99R@HP;#xm+O0gi^;wdBGTUGZ9c-nuq#U7hUuK!w%GBtenY$)do! z*8w9E-3t1v29i-T*%%-8bGg$pr&XE%Q)T2cckN4$#Me0fLVOigyb)Bi6d+)qhf^kztAm(KcJem|_ua-a<8Q!gpKaCgefjD$THLfr^qw?5K%oBqqVd>SN#u zOdVm7M`8FCv4??^W!a6;se=sK0L{9aI7OM%a=xgR1}xMr|Iz&TUo}(zOd9$%Vd&Sy z!9U{Lwu3XimHRw!P|P?X@S-{*@Y0rg#gZRXLu4x2gHnnLc0SB`B^Xf&-@*~j8KyjB%cO& zd>JbGEQoQ+%?P4>#Io$MH`?Q1wilVyj@E|}Ac9S-gO!0J>`P|2zq~ILo^|rL6yorC zfZOFzZuDpUH`j{l9~a+zl3lTWqjCLu<9b!w z!^+0B!kXohvc*Ujyl^<5h+J)12(Z`!)ITd~L*0HgBljc(+sya*2e zM$DPDHR`bYB9C)H12-1kG&IS*Olg(sW|buQEYwGolM~UAXBO8sr=Zv{2VhhI`~!Kad*jk(wN|Hzgdw?iPpL&5?I@z@Bx|gMG$VVVvkAt_t(* z2@M$Z_v#C9ZueJqBBMbSI~A9{oLsmbU-S_5n^e4_DSUvPRT9?DIcxFxtBG&~XDzF7 z^Tq2JEjZ@^`fnT_%ecX15|^X+|I<;!=1(ZEu)iWk@wmKI;ybQRDBF}p=%Qn=uuA^( zk4a0=Qi7+4KvEzDARviJoQu{#D}syj9GBM5g&?2a1px!swhIwR$SA>Th)wQcfn5Xd z4~AINCPIH@f`V$LSr2jHt94pa_;inm{3NGaqjKECt z5Z4aJqgy=YFprKwGU%c{k8;(t~}= zT{Pfq*Xc^@3YQKADyG9+=VRUG)y^}K?lU^qoT4HEvt}C`S4-NS6t{j;T>rGF_R)=2Fzy~z zwX9!n!7ghpuY5VX3K!({ifYuXKJUg#&W)9#x@ENE;v0HAhfAxL3$8DtDc@*Vu5Q%d zY}8lQE!Vd^>S%w~-0_Nd6!*M=OuDg$7^j>2w_!?ZxwVZCuQ$JpPyXK9XPs?z8*$HK zqa4}i(TvLxv985R%XFEs#^p*h?^1YrSW`++Yf3;3*;rVbUn>;_DDZK_l{Cb1j z+x_tbcJB%czl-;2LcxQClC{+02Uu0hea^jyV=!7)z;TPfox5UjC0Ip=bg0X*| z1vg%k0=onf3=!q97#lZ>`qgS@#CAP=+dcukM`YV0VZegaLGYHT9dHfc`N<%fZx`LF zm1GKvT?fgmmq{6AaPCW;*QDNGD}tW~#J@!NQ9%ACvAHVTh%O+U3(>_Jfd$*}@B3A} z4KG6dzVl0i{`s{_Z~4+i4t0onwHiiRtFy`0=hCQOQ8aME3O7k0; z!#!uks8iGv7gxQM4V2}i(tg}YHs&rIbzpV`IFAH7P5Id0^LL$%RNje@_XpSy1v-xU z@O%6u-EoecNv`dg%7HjxV=SXGhEtX1(wu7F8BA~Uw5pU}h~|Cd?`D+hd@)}7d8D^d ziic5ruw_OBB`unotoS^DVcptGRvD?BPWnZWW3q*b0bc~Topwv% z##OpxC9#sV!Gk41&G{~+5!9@b_<{QJnf986>m6TLcKuM<`E5n(*VP?g*Ml_M^#GcU z%9aNejceB%R;y~4tD2W9YL+W%^`%WKI0P5mSjxGsFTANQt69!1U%`{Pp?$T!ZS6+O zT3z!}ZR=`n(`rrQqx!ZVYMNhHw{A4FylN)y!W&(KZyI`Dls5dBUH)B2=tCKMnr>V# zGR?QYl*+S6(goH=DXzQHvz#oF6lMvL?sZww?MZ z{D>QD`<4j!J`Df9lgS>r@dwgtyPYf`|Jdtne9+DOC^VLi_Fs-(sA0!+^9i6sx?3m>EvV|YemMFV|6e9v7WCTEl|4n}#P z*b$?(HhVQ8eNB_Kh9Q~QTxBiCr(tV>cMkSfTW)c0oWh<xeJtkPkqW1j_EUbYGoJDZrEtJgH~=A~r+m!Q`Cg=QI$S=S z=zBZM|8~0btz6};5@mmeY%opMnc~zLE*#RhOzB*v{1vl)4wLq_gCf&nfl0RfT9Na$ z0?GL#`}5Jt^P!%XAka#SVWqkoM{th2*d7FngKx8wYyA(N?OvJVxsVijevUHV0^r&A z*k-_L9d_a!b9cHBBsv$wJ>w()EReLvfpx;;|0n4!VBR;%*=KYW6f!$N>?+$t}I*3DTSxya%JOcb?Z8A#1(a`<*h4C?HlFI>!r18Mb+CC zH3t>7CylL7o7$e%bv&)^c#>Ch9GCJ?#94r{%vmqr^T%l08ztU8oi9qC;e#&1jx9l4`fNlib_sQEdk`|)H@H2sbuaS_VbB4NC1&YM9IXp%P^0y(U{vOVb7chC!UYfFbrDJ5 zUboLN(0ujZ=a51CxZr920n7R`zVnaae49KV&njOyVh#B4n`P`KKT)qnJ%b93&fJL0 z-ipTXoR774Gdg{hU~%9!l!9Ko9tm^{mUl@Tv8fxHlr3P?F{!TrYBb^u0<$7GlZi{H z;)o=$trh?*N1=G*Aw*h2a056YK(5r$0IUEz&xOVzmvCMaH64lP7=Tv`$QTWYn+w$} zI9PPpVe=(p%jie zbj*o-91#Chno3-b0`r~)=e$zu=e&H?e_zUT&J@{a^0b$-#22EN$IQTEFXW^8}n|ai43rN>1EP-F?RD)=3g|S(;-pR1e1`{$Y^-Pi3jc?LS z1^LPtu>a(JB(XgjmbX%CUTbL5_Hu-i9?OKtg z)7|iapWD`d&s_L-+`zBurvHiWe5omY8dmx&yzxv?aOy0cc67h1@SpQ?oq=Fq#+#LM z=VZ)rF3>95cD`df*ZnRBKIfbnDSJ-JnpAjB_*jOj;-;#S3go z#I&OF*p8OYz1)t&>cP|MzN6}{gWB!~^}YMm?K@SC+tp3$rHyMP4J-L|tGU$+`L#<} zjZ2%>it344&MaO|&Ye%sUo0$ND6L;FuU)UKUa4wXt87?q?AWMjU$1Fht!mxKtKKT9 z*)FMsnZT3!&gYfQFLDYWM@H^=+VspV=MrT8e4`Jb?w9Ca5$XWKy5Meb-bL%2 z6D~^NZ)lzOG=}B=hu#+Nb0}9l9KTdJd>Pi_k;yap!X|4?ol2n1ktrK$ti8$W;kX&40+im=parLF#H9kK+8`KN zXt>1ltD8{*Rs-~36f#C-q8Eokc7zg+#wSZ^)NI0hI2_<%bA%jH)Gr*dqGwg%GvN`l z&KCXl=DnDoovk~d(Q~nGcd+QPqaoA)`oTsTl2eSDElrxqMx9g>i2D2Bt8DACV$axc zmpo(!oJcf}#YxY6(_bjEUnn3!0`ocjr5~8j1uvjH^3R1S)|ouzXJO0>e#BEY@MrL^ zT-RurpKp{>ze_dwD&FYx6!LfJ)E{%rekifjEw_Mv&Ss(Q2aTL&DHY)or69zZ<#UCe0vQ(o8x)(y%b=wIX#{TJ&1NX8=jTCha7{CbD)7 zbsZA9jwxJ*1x{nW?xQmI zF*$D)FM;C()1sG6Zf2WS$!#m8v|wl_b+tgzd4w^1rr{>P-+70@2Fp;-Z@v& zd!Cl>3+S-O`$R_mP(ZuLCcOo{11H)cN~WzM{l7?Ovni0rv_@snKDK9k$&0ay%u-b; zIc?r%dBL9bSqMaH+N~QrspvYc>p!XOMG2!3@0GXiR<&GZxq+Bmo=>AS70h$ zt3YFIUM*?Dk4tGKD;ar98AXdlsOx&bU#mq8%fXdKT|1Q>TlJmWRh?Vqt$T&_ zyA=%&>YERWYmO5$9w=qw4mxGDukSb-W{7MuJ${OG(2C%qcxlOEa*{VaB_*^ulv5JO zEDrW85n1L&NZV7RCe%S2p|Qv6)YI^+=P|`ElB>_My8oGf?-!r+B@^u!+`)CvIiiFi z2iAJa?dF@#pf}$>&(ggFjS@%u0yxqfSlb!D&!>DUF!@A)AO^tru+uU6kfDXC`%Sl7 zZ@O#0gJ>i!0u4) zaQ4O64E>P?<8;D;8W2|ELMR~wUR0xg5sMbH5Q&&V=$;5uthvz01th#gfP)=5??ml( zw1fn>9mBIbxE$sh{v@Q++z%%hDbVSz>G@K@1mf7ttT8@SKJw!?(#?Mpi^P= z6G`$jN!FQf&Y54<3*XG=0eH`NAlp3)^DNdwc^2C zAFL9HDX{Q%;);Y9@Mo$)3q`NZ!l(;I(636k-<&)^BlTKS+u@c;(yOK3EVI5|>=Lw6 zKL4-gr9V>^{u9;rN9x%BL=-+3M?F+!p9JK+h^mA0z_BD`8AH3BX_J7vDqy387scFJ zj_Wv=IU(}8ho~=(btA|1uE=weB@AH%r7@n<*LakthVWiS1jP;G! z@e6O~&v|C>eR{*e^{P15HI=6uuKT8){_A!oZ_?o>>|}q<-k6yzi*8>rq|LURC=}UB^ac%SHvrlMSn7^;<-f zty(RwTZQXRe&uRbInz4Qrfiy^J{lly3yvJ`CH%Ci0CtnqOz zP>X6JS!GJ6qQvll^vKbmP(*ni`zJjPNqrWY^IV7qqra$Yw@l4*uD#{1 zch33NoAe+5ADdgRIl}Ga_M2Xam^8S^GC&ny1|v&I{ut)ZJj!?Q=-`t7PMGTGyyJz8 zQLVRN%E2^vmyHsJHKoxNcnrEwaOwNfmr2f2dN(7H!Cx`%rx^2-j|PbEhK3_BWg|KZ z5Hv~{$u-;9YNIeqXKaS&Y~q|m+}QdE7QYaA2ZG=EV9k6W%yS4+tZ8-BOh7c^aux_* zM?`}WNkizlQ2v5QiCZd?vcZ>VhD{9u?h%J%L24tJbyH0TXcjYePAgWPyB_jGX5a}g z`l*n>uK-v*SL8oaWW4Z$3OMsjp79*CXWuMPI9~eV1e|y#ih9CS9+t@_&>w zz7#ut#>NMj$!-O>-0+XGi?ssBwE)kxt9eyx zMU5Nzb?d;Qv&)t;%Lr;#PUT8b)e^48h4pJSotw3tTXh{@x`;dI9GWzEP~xPoaUrn%t1a0Jnkw@8UR7rP8e+ zTvnf^9#jX-1%&QIq#q$8AP`K0+_R9}=P{*cv86B5ntv%6`uR@BiH%S9t*i1I7aVWA zZg=Yqr(1t>#x9IQo8HA&yDi|UcL(1PLPsJfab;^%=>=XY4`>zZ) zqb%hAJ`c=!5r81?>@yUvG~;J^Cf?6PvCnx?PgwycuEGZ%UQ4!?-PGIVM&D){UyY}H zodO}Dl~w^N+Qy*5T({iXpo*$jW1|cI*aoULkpY1sH76(>fSp@Wt;kSAgf~eCUAP|X zEDIzg8a9)SJ24)Bc|s%i6E5_oz_{wnw5!dpl~`RbbJeWXF8x|N`)ktFe}X#x$h!N# z0Ym@sD|)GjIS4Fx8eMcMPJW_H+_&RzFvZJ&xSdVg`JUr!_Zb9_@;OTi;gU?a$YIU% zJjdNE+J$btV&)Lf{l0)T&GwiTvL?9B!+h6nDLg8Xy5cn#J1DmosO_Z-y?9@X~lm$q&agK^agf>(-awo4I9+Pqd+vsu)*S%?yb zaYxl!UiE5T-CBOlYFgoPQRQk$<62$Ec1_o2P3KNY>t1!oensm}S?7LT?_Oj7enbC$ zVfTabo(*YIzupgiNEo#JK`FA&_O(p0{lb?^&qz{tMhVNLwmB+RX|PM7ziVL(V7Hjb z=(x?unBBNpj)rmnqGpJ zpo7la$b4jCPS(4~G<+AJG!QMw_Brs6)xjrM5T}ATGuExQ-L%fR8(zUi?4^APNHsLt zp49gkl=nO=-euc;8z`Wc_)7-D17|~m=7apFm40(Us@af8=>FC;nFKZ!o3@FtQJ`3w zG_W|Y&be^+#GQNhKnpR4I^h9sNGJqHb>ykh{*+JHi7h-j5=vQfVU`K~2x*wSj=fwAW5y~pr5L_PANo^X?%NmB{IzAPI% zFA+5e76%T&K0vN=U;1R63A27i|K+HkG5q0wh5ONxqjeV*QvK^WhMy*weV0rE`RZ07 z!i6n$D=lu8Tk9jJw8qA`o}yi6saFTbS_@M+$zvX9fqxyv5T;m-)?h&ci-s1M)Pi4` z1E4l)rI{hcsomVD6U{Ry8ix>E2-f*S1iKj7d+|ja>UmZ$=+E>jCAvlB(B%|$yYe$7rdzF8D8Hh3c0Dt z%(M_nd@L%SihTqXMo*Xc7_cUjed#JYkC~fz4NM zu>V+T`C4}EUQy>!_3&v`|3Og;WDeU!H5*xF>t(f@Rdwri&Fkezb7u$YDn>`f$*H7iy@G(Fx2xKAsfGtuU(2-Lu+x5>uKk*`*6WV9 z-*z*A%;5?PrAkmWt_a9rM1R0CLuw%|N|#u-AqRfTP5V3+XAk|$Y-5Bded0y=*qwUO ziS~iJ<-1&_NwUJbCoFWqKWHT=V8P#SAy73H5VW9<#YhaI@=jdVRw!f(7@N~@Dq4jK z30fpDI>Hmdjs}pm5tXqsc!Ho~lx(&~V`1GHdV zjtmL@hB;LH*TWH#oF`oJrIT*^CC_qNlz6iFXY*0J`f+lsxBSQ z?a$-@qBCB|vhd+cdD_pC_%rXwCvJWx?)*J_k9lkJPP1DjXuC##Pau7hO8GI1@>9O~ z4TS&JSn5}s8-lY@O-1^WeuEX>jXLl(ERh6(Z-U5L6KE@%iEK5Z?KWchHGefl6KOA~ zToQs%JMf*+lud3{ntfMj{&kU=MQ_FI|76_%J$2#_Rr4PSo&Su#_eVheuQ5IU6I^>H z4}T=fIQ9!$_LOe~rXIR+mYnQH;0)kw)x&og^m4o}W-p3`D?;yOsbo#cnP)S`Tmjk} zH1h2G_>4)sq|8x{*R+&1g<}(sIVE-n?E8IP8huzzQ1kKZ8hG|SJog!2??oTc zMwn_dP`d2n)a$9AuVi+5>LxpUE_D8Y>-Zs;ecdnA@{YtflJXuH9SmU3#upsP?|RyQ z!ZW+V)PBv0{5He(9WUA?_b`g4%%?30pEgbfvsaH$6v7cJqTp0Ou#E+Pf?!XF*fA&-9)Wu|@)=gGGgl zWgU-d22bh-kBd4V<~QsWH*FWyZ{}9Ohn6tDD{kH_X~T7C6aBZSZZp5?)m+`UnOnD6 z-n3QRyi?M$Q;GU*->K}}uj<^#L8_`_ucGHc1JQ!_TKo6fhaR#@Q$$LX*kt(FW(zDclKdKy13F_gt5Hc0RS72n2~U-YC(6{v0ja0{ z$tS9m$6?7QVaSHaKS?NfoZfg=jL?Uv7wWuu<8M?@RvNrzfAcj5t-rxAhk-fS2#m`2 zxyD5J0#_R}t#??)A0XWfawLY~MX9`;B0wM^%V& zGB|YEKVT^&a5^YpD#(8(Py<=e8i8V^ZQ=3@RiFkla~kx&TevPk&H%IuJ8vw4S0ETf zpG{qjONPjI0RuCk8HDgZaRpLAJVeFMYcNO?J$D{SqhaxjFqK923LYY(7lLBZa~C3s z`!CU>)iHBnFyDw;42hU?wSaSSyPZ*+Ba#kGTbyVuC|)}XVcBX4)&vpuhuO6g!gi|B zT`StOt?h!n$Eufj-wpUx@UeHqsc+&FX#y~-XY#D4atIl6p7~}!^T~eUn|`Lq{0F9J zdCHl8(sQ2r3Df_?Q@m&IxMWT4FxM_N`!3z+i$s&FNv7YYn*Wq#@{_c zX=@c`*NUiLZ6`?ovyf0sA@p4RoxprQYWQ(pMzK4wK71q9BxGiE&% z`vK}LN7s42Y~9s$$l0caLF;y-gG;#}6|74n%Y5FVguf!-&GFdNY{wBNa;wax%bPL9 zb-5?w&4^jkV%{8=F$$%>ggeD^8l4{>}CBNfk`!R=fg+)H^ zYH^uqdCrafgFKm45bKt&@hIgP$2)w59ASp_6}I_XZeCxAO8Kd3mt=?#6*rWAMqz%& zK^O@2{z|d9WJ`I25@5m&afwKA`C35>PBA`6KMV0@9~& z*I}Ey2QD-hXC}S#9)^S|G_0W^3}I`5p+!bQn#a1H{-yK%py83DmRvRz%IP5PK5H87@^~m*1>j; zNL&H8ityZk!YB#nU06**s<09TU&^@UV9i2U^t>8%9Wx&hIj6=uDmrcf{0;E0i13BT zMGVh?ox_pKK&X(Woh@3OsKA^7UUkF5&IZxgB=9#nYym+N)=~tP1r!&^m6hp`mBpBq z?UIAr23Nl0>36^mI$=jX5#4zrO?mE<^<0?w%rE1aU*>aZ#tUi2bDxZtewi<%@UKgH zDTq7s4u9$yaOy7Hr@JlMTXa!x7n8nEGy68d?5k8W1QA}#H~p!=^i~B$x1Od4@^g)a zb}cv?2w#BO7Yix*cC9(|`=+SbCiq{Wa?xSoGj9%cKc$Ui&`mb%rWrw`&}44hM#4I* zQ)POq-1O@_^J^8sO^+)V{>&QxT|M$|P5rOQcYh6R{a0k$KZF&(Fai&xK`SowdmQn+ zDso34T=(>Q5D>Y+cIX9d(%!g^f_T<(fYI49#zd)aibY#Zh7 z1Ku9fQuZX)VXpfEhcPYW;6OYjLV~c{5X*j4##>MbR|NcJk#JQkT9%5IeFO^uf+@Lm zvw~h3CY?cQVi=!Qkxrl_ss9KMlSf5x?ZpJo2Or{#NW zV|Y`1z_q!^q`%`GZ<|r3D2;V5Naf}Q(i6d=G=1Bh^t!Xvc@K|o#g&qjK=Uxh7Xlx> zz&MY1nNbifQ^s%5sDCB7eeIIRjg2>yo1Zf$U$Tql z7T%VviVm#6`}N&`pm!_UcWb&}SG$S%xv_t@b#S-7Z?9$OQTx4z9U~7LhaS}q9i%m^ zNJ84}bfP)rXr*(8+$vKeD8Ccj8mnyg6ZHFewRyXB$azBo;doFmZlK$$!~@@qgMc)& zF{Jj3cL9yJc0)m#*|-Dvnf&j-Pa;|@s9Fq?(QcM*guFef9R9E^iC2kfBX zA`9?pE+AqdIC9#N1b5bUa5mhnkb>RmOom#p6-W`lXXxcEOxvvpr93ziLv*u2OUkH& z!@QlxwiE9G%-g+#PsNd^idXZq3dmL7Q@`w|e!0&S1dw$m2cngODt;kJKa(ds7eqh7 zz1Uf>M|WPZBDYh))3}yt`1d%|uTxCE%b?!Kx6&`Q(5gf(FxFLbg9a)>hfQiJ`t{KL zQT6eyumTfa&=y85mZroMO~ofzfk6_31*Kj)S-*p7h$|8>H)t*z3~yJHzAvMGkw>Pt z7ft-LcKOeszJKQq{~9s)?~v+$CEoi@koON!!m*p?)RD2xU@S^_Q-ML7EZLSSe%Hru z$%8$|aT>8Vspi?Wu;_gr7X572yjZl#VXcU`Gi>&fR5H)^8s{+XdfN7iyoN>032(@R znbSg#2@!u*A(|6$Ci!k7EXTWCmob%MDL}RCD_WEYkh%-VXwi=~DWWz>XvHCtsUYF3 zl0PeRzAvTJ$qds4HzM5NW%rrX`#b+2BaOx?9+R-!x1bXU$?q~K7nv6CFm2!QwmJ`| zJ5`!ndaK#4HZvO!3%ifY zyN{q6&Z^ids>P9Lv!Z#cqJ0}j-kSE^s*c_Aj-A@B2Sr``n6y#RRUO-tP#2fl{n|pU!`nKEqcUp$_I|ue#haR>L9dzG2Y#TkO9^8*EoR!EM zgx0wnQmk57nHbO*C}@?qwm6toSsKCCS`yE(d>Avk|_%^|a2A2}(wB=V~tT2`zdpUl^u>08E`3GMKy+|dw9~!a}61p4^ zvIH?ySm1PM7(Ce5p~sKS*ixt9khB3kFXTmZ>Flr0|CBN7PXcXZ(hP$*%kk%%pL z4Tg0%^~NMF;)QiMig3_cP)9Fd?Zy5Jk`>{QL+rdugzXjFEP+D9eG4wKFoF(W2#G@f zoezyzaHe%Q(BMCVw3JR%E1a(&hsWj%sRE%KL}|dL2AVzQTeW{|#5FoXX0J1CEGE%l*XC`Zter7nS4(RAyu{E~HnL^V+K8gYyUZ39+0 zFxG>%5#TdUNMwUH8&bQual4r=?$oU$J>cYxG{aW1P923@X7+tP?b|$_dah>Ww~W5u z6Q}+R?EWKR=wIRY{}bHvYhcYw=b*<-(WX6XhcDS-N;ajUHEH;+gfq>SZ3g(xfi{WI zVLPK*wtYLtrjO}-Ps*DYdCzkN3rgvnguBS)EUH9PJjVg9LyweoU*a|8z88ZPi5XeCOp+bQEJsmR?CyZ-p7q&$HAGS2A>GwNlQZ5+(l2_i|&S(Jxw72zRWU0b`sLPLFBmP zg;81iEmy5K9dSrPrV{NF)ujE`4auyQISbV(Jm78o+8 z^ur-(2CmMq&WMAmC~XU9b9^Q+=asPJjaZO0?tl)xNt81|$$%vewqOEV#@RO-8HI#5 z&b%gmDH_M$gvIdKMGe;5gjfEPXw8rf#;%0NEvcdxgJR}T;Odx#;ArBsgxFu~!pKz# zBK%{aRsdjy$r<=_hb;x+p@4wU+7Nz(-4oue9hT%lE7G7jdDO;gl4i5)#M*Y^?t1!Q zem)jNo=Q`n_@uw^frKIFg#`YSnP-apGrvMY_AAbU1=b6Qf5i#J{m4s+`rUPOox`F^ z(ke6gCd2saWYh1`$=~FdeV0%Av5czKNHxSVTWhXWN7%-i0i^1HT95|8K8!f{)@y|X7{9eJ=pq@kQuW)(IxVKU&7|ASrn*oo)RKNGrG8Ur{%x@$`$6Bv@5;gd z#t;0KJM%|K$Dc`~f5eUcAxVA7jCt(9-E(uBWiaN%s!d76L;s*n7sk3IXoKlI!DURi z*$+EewYZu#y4!Yo!q*W^)_X}TUgb0Aq>@#MXjvkfRdC1QG%IlH6Eh~gT&BIfCVhlc zBKEADKjtGCm9WQ%jo4+B&zV)qS0v&UU-_~^u&&@P$s7l{?loCH>RxLvl=EJ0xuCDc;8eT_4*-1Vx=@*>~*eXi9f-VUD#9NrTlNA>6k8Zp*yt8o>E&DLBS?L$p>sN4W8^oSH{_?x(;Ms_Xbxq2n zl#-MD)@NmX&niZqH%^|&gF9~iA4tJ))Q4K|94w4Hv>`J*?_qM;+vpwKk2r=PXuau) zXm7nsZm43Ut7zf*T|O-D5KUzTQrx@FHXph;ed{B$tq8y$gmA!+rQpz|uz;yx)l_8E zQheeHEOg@2H=@%vH89*r1~C$xs|^h(8Hp>QchH5Awtx>;!KWguDdSecvHubZK^R-T z!mn^hidl*Tv6;B`E};ttLu3@a6s%baL<@#s5RS4~jbrA+06S|Iq7ZWiEmG7x-LMfR zla2^aF~fDH8Fv#KGR$L}&2{ULxnK#T2w{Ja=8^7Mk;iPzr)=z(UA%VPczfRHzoDo6 zn8*CY=K}DY^NIXW1?m?IZ`w=HCRJI#K>Vx9e4#-7LcgGS>h6E)?7i#cGG#+)BmY!s z`c0-W{M&y>qW+L=_G3OttAeHjVPK7oVGUWk(ZT@WGeMOEPKA*Gb~@;=h(oe60b1UI z61GJIuo>vtT{Pnk5`kZJko6#QXf)AnFx9CgT`wVhU2b->A#U*J!tvir=l`v~|KIq& zf2B|Ssc8Qrult{@{9jxnPCb>o&h|@mqkC-bd~o!RguloR+)+s89Bl3}nR86WeGi*X zC*-7%YuFB5Z2Lhba|(<~k#J2aTk{bviX{tj-lR%2&T{VYcJ5(&On5UVI9@XX?!1gY z<0G5}kR=yQ@Ys_u%4x145UAl`}!UJv0;sPZG@3AfnD*yVWm#KtTT zhv1l{m^h;OhQ=&~YE}R^V^j{0Sq_YXa~&brhmAZuuZVO){FiXi(JbO9OoWtys$q)a zZLy`b+E80*gv~O-L&1Fl<*A8I>!wqB%}K*F(gck};t2D7VT;*E5Z- zCYpYmPQIRFdcBaQQ%coAzC#t=q!QW$b3M4%qQf>&joYZ$YO(6RT6?jT!+a9FN*KAr zf0Akl^Y(TMh|s#&e_Ktpp>u3DyxC;>eX;r1#bo`?@`-<@&;1!U{Ac#$@1ev0jc)rb zX7sO(a@mTW;`HDiY!sD*Ukul0y@|Dc-cr!d^Kf|_*?KaBvoD{RC#QX)oTnf>G zLNqC2-{-mB1C>j{osr8|{p3qh{-TV(->XUbX^{55-itNGQJbKTxTf^WX$jQR-buL zuDIyGX`}PHrS|KlTK})9{_DmzAKC|aq!vQ6(6ld)Ui0-C*947LX3teL?bQr`W_etH z|8ev1QGNemL;qppz#*D!ZQn!GZ+-t>eeYgn&wgDus2UF%M-J-x9@O{jHTU83-MU`% z-<_s@0@P~h-)$Mj{QR(GV6Sa(A1GGu{fC`nhh1Zbt@n<4$4>@lpY={Y?w)$+r7y6|pm6|~<08xOq8CxW=UvUN zFpQuhexHMM71DD@gShgHXk>@UO#Yy$~F;^eS2u8}VWwAT0HKVAOI@)T%XP@}NVQHqeRY zix+~!U`^9tV^(KnRBM3&75qu$4N-?}sAHDqh~QjwaNA^vcNxBqJVKvvVxK8eo{6$v z0H;zBR#zC9{~^zSf8Ec1887{F&lCtBOg$6FpNTc6ynquo{+_kVGMpaC*Gi4QNHzRC zne9G#*G$7AJ9HF&o2UV{f%njgd zRKrfHKCzx#n1GwzNi}LG>ouF{HX7ZkGrL|&`?{FMpDAAWwP@z|=+XbGTYf8@_*dBQ zf8)A-jp_T9nfSsx=G2+DYi++sx0|r>+Mv5Gdhr)s?eBUxjkweM;CAI=+2cj;^Yoe& zdkxu`)UfSaICh;(`w<0yN-EkA3zh_2RN@k!J1+zPC7AMb9`Lg7g&7eD_c^D)_lcFa?ddtwJgA?F_3dVL@^&Eo>hBw zsqFIoZ7ae!{Yw5Q*SbSWZHRWLNtKVJayt?|%K}MByl;YeKZXWUBEroyf}25VyQFkU zVW@qY{8l*knxD!z*#2Xd=jQ^}r-Bgkh-`kE++0QfoXh=ID7hwNeA#xOE?C>YPd9ws#7EaVMVy>J@nrGq!=oenf z5qp$%CPDsS=1U^QEbGiK_h&R^jMIK;Kg$xIdq+Ix2ONRFVe33^O=~l|UQE6Q{r(-~ zrSc;?YqJRsiYM#ei6pEH*vPF*LpoB9hO#?t95mlM zsUJD58#t=ze^k|b*f97AJ+}&zbMK>uzDIQf59$Yq{@c*ESJ%H+(+NexRzvT0%ivz~ z;4UWTwh;hUk2>!?XdOOiA9>Vv@1XM@P^?GQeGl<(LjUw>-^5AR*h$~m@$mTR@Z@RF zs)$SH?&J7-*MLWGQ4D?{idBEym#QldzpoElJWcSlxFB(_A+}P zYqAqeiu5lcO-W$*F5B>J2CR+rU$>-OaC7=8Qt8zcpqz|SFQ`Li0|I6P{O1DvW`aVN zBQ@Yw5e`>TsVnix5GKH05?KuEQ3-2Ufz?2v6Hvvgu-}P@Un5YjJCO0NM8+;@?kogH ztwbPIFmf&;axq*(;8e&j3)NsjCKw&K3kM_7TSLSu1w|3o98e_r$E^lLt$^h3NN%JN zN%t+7SLr4-)?}DWR@<7^!efeV)C^LkHK~VUIzlJkwX&F`+pjpdZ^4G$Q+db_Jr!x5 z2$PG@UZj zFEdTPOg8#Fl?3}x?7!a^S?X2e_-koc1)o@REy(t9NNNUc63i>QNefx04XR{}%_w9< zFwpecETIL4LziJ2S-;;zXTbFTZ@${irZ;P--xgD^mB%(csbBh6?)<;~+y6`${xz!q z-+|TtitYIy|GHn989(zgo?CnEdhj-E*t?dD4Y_95Mf1X*vGOY3rQ6wZz>PlSg^&gJ z`wWk97HizqzSlv&1S()}=Rtwns6qxi#AShamCIQc3YSFC9QiJZ1(Qt20ijzTk1;Os zo|51S%$}1AXQjelGm&kS$}>!1ejmyHQt5vqB-10Y*uNrQJ(L$d zovZAt_OGo}RTTPGXzVh@I^o=(e0=l*#5a6gK4wa9%VQlPb2urin=3*cn~0H+{!W|Gb6%8&uObDEKcE{VK|F8|pa0%BBgQijP~W zuGnmD-6`*WR5N_sbpNzw;IyLmuw?{|_@JTZVPp4R14ih9{f5Bw9*gNv!MH zsqfru27WcL*YpZ`ZW(#hb@yS%-AA4G54uJlwU0b(zk7hAaPtV(;p4%{lm3aL&e5ZR z2|VLzmkc{js%y}+^5$93tV zo54jF{qruyV0T>P8olRj{2@>G0!#mGXT!JX=I^*!e=e8O^Hk!Y@ZjZejL^aJq5cbj zeqdzH#Ap`LYBdQ!o1raQ!?iaY1M{8r&;&fJ1;rEn7nK`;|BdmhA<@8=SJW}EgeAIg zSma7j)N)wV5>RODzqln4fK}{bP%J^%K;;5$4n|*&CS0%r5g{706co9nid+Se7-s1- z(*|pU1~gn-!v-f(jiYHjoYEaBO^&oCx>=(oxedB_su^+(ChVP-T|9Rff`<(GF)Qpu z5Pr%<|4qT>`!WboWtrG~U-}giRZJ|xaM1zzIprlc;b&RoGdI6e7w(=NeG>Wz%8erO z*QrKdBpF`KH2xOmR|WWl2Cbi7CG`7n+%hL_MyTH=!pVo+1{E+#2bfi>BMlM;sF2#x zb1_0w4BD*>J1K_kB%>ZGbo#oD#y6|TKbBIzEwZ^?SvK%IfBKKS@!zs0{^MW!XJ+p| zf(QSUmi-b`{hVL?4_^3@OZ<@wZ`WD0!HGX|mOSL99y^4dI6KZb&_*07{Z4dvxsSTp zjj(KoxvX&>Z`#wj$JMl&>CgkIpqM=-Q>^eM>k7phpSvs&EeeH;a`B8%H0$Lw#B=K6 za#FqJvx8v--3#WeWZ~LV`vAX18e%aafV=wAE4wO&atp4t0_6C)D!A5SET97)|(DAUO?L?Ek zql#WdLrF|nt!~;zodRxZ>_4vQJ82j=svpKW{0N+@>aKmDTg}43 zuxIpWc;awy?9tHpVc+P{(8Nji)YJai(~99^O~p3+kXh1u_Vz6#?QF7Ey7`S%^P2^h zdWBT&B4^V|S8{`r+nb%fQr>jfG4-@}`9=Hek(anc=S}O|uUTllM!)d}-RLs18yGO9 z1O-bA2~(FnZvD;Wr@w*DK`4mz-}g3#ebyyU(gjD#MJM|&Bwl)Vd_C*K{HH_0R>Q+q z0#ys){xd2J(jiM~&02WU26kQqqo^?+r)=MCW-Kt!~+=7n%LFQ*wqNQvd651 z#jb(sj2}V13d4u-s9BtSS3;s!12w4JSIMCuPlEFt3w9Rr2T{>WLBOT)5WTF7TCp*$ zwKb`;GOUA5E1gtlZBl1v49lrnSjJfzBgm}XN{3)DQVshkCPTK=FthJ4DLs!KW3X<%OTw;q-vGY^uga~v@w7PmoUAt!Wr7A?G;tB3%wY(U8+%s zg?@*Pakr&mr@0B{>NYcj9#FF=`rT%F9c1l#gP-b5u9uOn7E-io(g)6()_;#4`aQYt zf0M`lP}ck!*Y>ld>3{j@PlJk1+#;VbB|EIN6MNAkiE57(_ry_j=pxv2@L2b-9|I|i z?RnqL;U2?wnBh3a^B5PhCxI$6-1^v-^<0lGmg9g7UUq&PeA%X0vCI>~4tjyhTaZf^ z_?$T}x4V3|Zl2o^$8$=+nE_u*Dwy>VrU1*24pr!~9pmf;Xar z=0n^Ed~IrCg&m=aF|}+uRJNe-xEIJ6lsWbJJ2nf+<$Ows*u0o;lp?qp>GZKQo{?J_ zKT?^sR+PG(k-U?gw4LEUp3bf>-;v*q zRSaf^+za)t3$o7@(b9#wu~uLEdKrZ?zLGJtLVVo|Rn%y!Hyuo`xFiI0rbSJr#?0mx zgHm;rQiDWqAgCY>ZsZki)wS)Fx9^v<9#jpU)D9juj~vwu9KeSM;b=_*51aZQH1}iM z-Dw=a*t}oUvjJ&v8^{~@acH+=c)#Zr1q+pn`w{WFk0}~ee9%3L7JM)?dDJt0)Or61 zKlY9u0i*7_f7m~cx;`D4d2)C0S;zF_{I0{qyfr_~j7Wap&Z))hr&P7s9Qs)gT-HQ&!AGqowLFtkwatXEH zX6jynqTgNnO;;^=TD}KEX>T+5SR$G9k~`^wGwll7{aS#?vLIME7!imZz_qZTr9hCP zmGfc2ixCkx@w}4vf>cQmHde#XcH`DU6A21sFsN1uYr%Kcf}__0i2e&p=T)SY!K4nS zq7d|AVr(XKg+aizq83n|p^?joO~EY*bPi;uV5kn#Ea6uw%{(ev6|rDzTxVxihfx^{ zSzFV3!f(p34&HHeqgpE?;97_uYD9LJC27FIWW<(y-+?~m;<3o!6Z!>@z!Sdau_X4X zC=;!gpg{ZPyA2oHt%Mjq-HDD+Ed%0HxcUdp3R_{swp-X0y1H>6I}Tg65{Wa)pJ zVE9F{!8bV;T7{HbxXzbb8r5QKwlZo4J;TNTUjVy#189@bDd5O!1yr2y!)c}Iw?b4% z(FeV=jcn9zW87w{({8K-=2bmOug(;CI$!2fjq0lIzbu>iJ#X&Mz}A1qxBZ$r`iG$4 zAHF%qlALGkh+}Eysbl1cuip+1!3_TsQOrZ9pyy7^9WUo`y6vo&>#Vo^T~CiGcc&== zlJXp9xlQtgiy+}R+O#q(>yaYLXWW-ECxwa)U&$KI!EzZ$8f!exJRdp*|7DiPT`#*X zj^~&d=oWiS!JG4y&L{&GBSMxT5Ei(N1juFr{nvw0!eLuc;Tv(mYbwEG9|D%j!_)oRh!~J z9PQP5Cv?0meNgR{l_;%B6qU$t_*=c>A+XHMj2=siosajs7v?jQUb5(q2Ne+f_8rvrqY>{m;7r`J4G6jx?_E2M z{o8GWJB_^r^4vXw7EDwwQONi3j>^SQeb7s^+C$9GJ!6O6_YZr=4*JK4_rdYQp0T5z ziIbt3)6v<-!wXM`myq~y5TCQG$yyJNp7!MT(2PsKsHfddu+`7E(k*tORAA)^^cgR& z+#Q&B(!c)Cfz21eX+yVOb43#Rt=BBIh!`nnt@Cb1?=iK`1AO+kEP`+#YF1#TxyyT8jkwc`94jgiX9u&^aCvO+^wLsSca%0)cG^d<)MW?0C^ zt%iWV5rf`}5?)2wqL%R?dTw~kT3GB#B%tOvgn$DZ%&R&z7Dhz)pp_{SJmKI9 z{zj{XX%~$&U~Mu0{V&~i%Gr6vjkm*49C!vCOEssWxToT*=e{6ZLAIX*7RQ+%VV*;j zu#})SnCUUbV$ONFPa{!9z?xxs5)s});k-&Y<7M9q^0U~h z*V}ni%$@e}Taha^rSdI*-z9JUib70Koy9)OGWo2hOTRC(kHsKbuv{@07PzSNT~P2A zIAX{mrp4Sjb>zAxY%?@yEmXPXquLCT%?3EPu=FzHoJ%z9hG=1%iq$EkH-Ie7ClxRa zGx%oNeCr}#-mss0XP{kal=5yu@LX!*QZkmW(7PH=xrCY~XEph<27_gHqcjUi(d&^B z8!;K1X(>D5fs^r}-RU76sj8tc*}ZVt-HfEQq}Yv=h~=D=je?M=Xm(?ueUZc<&gL_@ zzjteL#6*H-F*kZDR52bGF%=y+nV7VY+XS@vIJw~3EO{or5iH1!b_N=W-V26xbfd+zSGju2aLJ5EUV z9(4{s=(-PF>#*nk!N9~p&%_aGwrliZ-`HW__;L5xAqu&F`u`*8t)tsYtab6<-}kkh z4rDTuf%f*b@3zxUX(*Y*%*@QpY{?+WmQk`~*^*_MnVFfHNqCOPY=@KSw6C{x-}-$g zT}vy=Q5+{(&OUqZZ+~#JxP85{cfES_cxopJw*XZSC0){+9#N-@g8V(}N$l!#fME_}?OF z?&BasIO_a}+KXYV4dJ25r?DpYq7B~ zNkPUTlW~ApF|eAUP+)=W44x#9%;yoA=)62CNR(Mj#T%jjg2(}$Gs3uY3*}&OFu1rb zDHw&gBU2@e>Sh+ARMDVu|2;+(GdMEvEm<&fM}#-V>EaW55hn0`7c=mO5jEJ45gMu= zs`tGKJ8(4Vwl(en@yW>y@X?sP^|Uh_X{=W59ru0wz6faW-giGHj>Dc*KJmQuiaw0JetxHV=DkA3@FlEny!vVjH{+U?&UYc?g1E z&?&)r#zqV}rLDn`>HThi&vw7Ax3eDT-u_eT(LeH5{+U1U*W9JQru6@JCVb}GUIwzB zuv>3}IJXg5=k)SRf7&IoV1n{)!V~n~p`?q)q5Y##gcU;G8xe639kd$}AqCDH6Ll2j zzZw_1nVEVR5qA*mHW3KjLHKHj?^;6i9-XO5N>#-roW#b;Q<7v!@$#4id;r4aw!h1K zLdaTb+)irZAuVzd={D*O2DelwjW)XJ41((va@mn;krzN82mPQ?U~EurHV7?=tApoUDCz_ELU$OY$RL zw9h~pnq#T9SU{F=)dgi*u29Y4lEv^t%i0jKmW1qm0f*oU)LcY@3e@~EvP`HfDkO4Q z$|B}5pMStjTc@Y3wpL389Jv^1Dq|PaAYsuio3@^ty(1_&tnDFNr>-T_k1M+LaFP)= zsGB?W{gY=M6X%0V*8_{!o!E#MZ@U+++9yw&M`u=~|QDMsO!3W;g==}hkgALyGH~S#a1UVP)_&&VrZ}rm{ zv!BMBei(w}8n<6iS`v?6r38J;V}*?{GY+%aN>;84y5OAbW9-80oRi!_Sxyl$j8uTF za=EI!QZkpX%E1(kcR0#C^yOk%cAaN&SV0G$qX0pb&|EN9bRXR|&h!)_?(Z6N{zi4moZ zE0X!NyVWf83!d%=?p|`=Fl}(sc@zUP=aYEuQ@RkglP}SEGixCG#TA%Zhckd>!8u3# zJYMiBiTg4t_ir=5W20&XJX@DRT%%W!t6JdlzIENEzZWB4h9{L23?L1 zVY~6~DH;hWc*4Ly9)B6g3H$8Lun~_?$^|N6e8>t+X%sldY2zVlXo0`&w?b6JA3Lb} zHSTVmf6d+aXXVDi_lF)gtLdbulh7z4F+mj*eViP*h4A0F(EZHVt(2s__?TTd+QkRX z#D}hhd2Xb~AJH>aaY>3KC=_Ck>FFo2iSop_le9$0y^mvjR}({*(?Zvhz>ZEnVCEqZoaG}VM~y;-N0HFrq5Mm&Pmuy z<$0TRg^Q)E`LgW!qR3uB@=!s>v>A5OxQ*#@Yl`ZPt5nbQHMeo>Y%iQJA z`s1P1$G9#vPv}~pR~l2djH^4wiI!0kl83$tEpAD}Gun|^{m86taFMzTql(9u(8noV z(&XmF#2Py9C3fCv5VWuYZ(PrAT+FVX&SHuNqP2Csymz~_ce8SEvvl})di}PDw^z#F zs;re!r&7iioEwAFc76P(oh{mYEt_Jz2D1~EsvF6vttU&mSKZT6V9pPJY;W`<$A>?1 zHNWF!{*kxMr$LTCkEG}v9|l=}ikvtf!#n=aI5>Zv0KEfB*!*sw^#{SuKaKJEH6y{k znUT1Zn=51Hkr@mHD@&T0b&`<@aUWO~AU`8dP{AzKGe?OqGQ=on;a4#g z1GD1FSp`xC5H0jys+<+9B58IJN?S%1Z;2FWA&V=^-~#D7Mj`{2WvCl+pw|!RMblQI2Vr$diy!CzM_CFaDf5Y)8 zW%RFEHP1OiufxT!viVn$qNl0s^N^e?ue3{_NKI7knQx3TH0s#d{m98;&e3Mc!C>6( zL3eb>LS*boOdOdIbsXrq6%_^b!69@;n0wPwjxZkkyUaxTPDS{vM0u~$laJC;NC{oWmttn&SCwp*ES@II&XHj|X3=DlWrl6Q8$|ZAiRJ?9O$9uf1Ue4I$R!FnWKo&ARH!N{A_|IC#TDA( zN^M1zrWk#pgp^dFqLpQpL}i6iAST6Pg`ikg$Wd0+C?rBz5$hN-RSExqpSM$(yIGvS zE0jp<2Z`p%^S0R=PSdHlPF>ZjZ5}y=+hjXvSF50TJnmiv&Ev9m;=d^>k|)7Yh8vp0GCgQ{i)yYx6KbE~-Ips?~JvuHmkY&Fz# zA}xAB$Uo_sxR_VISdm>jJC+&zz}DbxN7HvaOz*oqq+oej>y%A z7e5Q8>0`2V9ufMm^i!`eji<-HZ7aQWU>(Lc zIzDkb$ZattbOjHA%nT*<(9Tm7=N+R*foaXq!r8#=>G0C| zz``l6!^88ZV=JfQYiHPe0b5N{5EfonGiw*Xr~ysSuASq$G>>^GPe{)*Cl$Nrcm$g$_s~X#SvZ{MkT0Lv>0q9uv zM&NS1<7M@skI_AUGu(pTM~+gE?SF=R`>wm;U2oUlgqwd9YWkB1^G~9U--k72pyMw> zeLs)${{t(@rG=TklAkMOvt?P37BWsUQunfGyLoJ|svtO`s2X{ts7)}hl(|@eG25U9 zaXBhbWEaZ|xTt73Y8D)61Oc-+G8Py7XG+w7%wG)5n5#4S(rg~=u)x2fcIO=As&J3+ zKCVugT$$q|Xl#3cR@pwnz}#hr7i#ulx089V4c>X!X#)#5OtX)AU4c=XPdM7Fdj;(I zMrwQ#FQb{a(VQo7rN}>eN}Y<}0$qU=h8O9==gE@SiIUf;qVJO62wnLij`J*naTA_) z?jND{^ICVa7;-jfxBFv_&1WLJFKg`nSm*Gt&HjFy{kM2}^g2T!h+>4Lq%q2N2suZP zL81TJgK&k9-!LbUhk|%SJM#%}o~=!X!JGsy8lH71a7$QLLi_(ktNs11qLHWNoBv=> z{3T=TFNy81S-mgfn_j0CTtw%d`LM1sN_0NST5rFTK$dAfr?x#RA<;$c7K zVK(JrIq3v&+h8m_;2=6io<>*U)SD77jRt2ULK+>m8ymHk7`GoEcL2AXP^YQzknN~| z6$b5ymZ_lA6cMq?Y?g|ZD@%wuqF(9pZ2D1j`eAJFN>ao|MjG{L`GpF4HXhn1v~*cS z=sqn03GW1ltIg$WvAQyHGz>PGS3u+y5n|Y&MkLcl4SBC$qTPYO`55*3%P zDB+PMlGEBMqC}!?tS7M%*VK>#E&;#s>I$NiD=*^8`Fy3Mj;O3s3PrM#;uB%DLR29w zE7-}++Y^@T2+H?rT2)|lbk5%h+RwR7>WVH>G;&_ob~-wH+BthQxNWs@(Z?$%A|E2N~8p4(zkM1+hrnIxr8j0 zs5tpY_$T*IUrZ@pj4Ttj_oI#9u`{^?E~SUrJwJmF{S4oyU}tj*#R{Xbpi_Uw( zD3xU+OOzu+mR%x4lXABl0BzC@A z;IsV}@tyt7W}`mN>wZ4FJ`p79H=J=BTktftSEnOO8RjCmW9cI6wb2HDunYSi{Yi_PyU&3`Sj`h&#kk4QdhwKr;k;j^=8H&VIX z%qi#$CoR~};S3E(-0~4REb4mD%4i6A#6Y2)EQTE|$8Dj!utf2Wc2v$DuTx zi|e6>(~7_Ax|8LYyWO$X{tnw#Bs8?xRbb;BS6#9 zhz-p+N=w`Ia-K>Go{kM!iw@X=x<55Vo|vvorzx}P@~Ai&`fqxwEH(}($4Nr6Jd3^? z8?wMi-({w3WoAk9iisSSDl=1=ku1x}IOcE(UWuY8U&Y8H3k4cMsfq{TXC`(fQc$Mm zb4YfjR@9{93xIdYc!jE>Vj`cTD&nj2%QU=7t)N6cxsVT(0IA`*`mR>qb{cqpt; z71nBm)!2CnoqM2BauH5Zq@Wg6OmKN5S45UosKiyu zx@J{VwM;CM^D9&}bxMikm|J{MAv`QA+-BwM@VLk2HHywLebd}c{p3w?qejw3RCW=y zL+G%l12bpStLH;&I5XXjt=|r=T@5T>p-B7YDQZXWly+cBJ2`{mf~sM z$kN&5(&@x9FspMc#c!^|=hG_~tB z0grbiu2t3cXo?$%_+R$mRy}yz)%YFn zhi~~BeGp*$kw4^w#vcXS{37_l4?P~f<$&!JExcFfvaVU{q!tvsg#@Fv#Lzkfw^4RZ1X;0pm1yl`O83#i6di7=uxU z`5dY#gHf3ab|s)Ho&tv_Y`Cadtiuex41JcOQd74l9E&Mx2bdl-4!)Gk0!lseetUEL zpQivTTcd6}Y`!KitLXv$<6zihYuIaJ*n@2pf*?n;DNpAmU%vz2NL6^sS!m{UT;WYD z|2D4T8BO#oT>=YqxX3=wr0}cf^s479==b4bSNc-RhdRC!Db&93r?CPhdjYC59;z#LR=+>YlJ|emDG~8BBi8BTid8D zt=0$xgg~OJswFC_NnxY5p+j5WNLE#=>g$x^N(H}C+1^1mG%Cx>k9igH#`+V!@I;Kd zmK=+Ddv&6Xx>i}|%th<+V{Z3Vex0VgPF6jls~*q~OzQwxO|72K?_E#sJRaS8JidR3pgsBjjvsd1AJaToyKaste;*#pIN_{ zTh-5DkVYfky;|J4ncumd-oEafJImuDBxtWxC@rrg>$*s8qbfdbnU*roWNeBm6g5rS zx^`XX)b$kTl#Qzf|DVhKA37Mk<$nJMUf;e&U6H`ZviKy-=pINN$Yu@v_Q#$Ecl-^( zj=mdZ@P3%V2cgFAAZ#w!^Os3Jzs`y>6w&?r8T76Ed~8Fi>?}nV{TR43ld+EgqdcgP zczD64lHyVp;KnC_(++hMhIdv$k+gs#!?B4?l`ZySSrJc~&4*5ovkw2EgL)CbswpV6U6qFmgc$3Y-m_&l8P zI3V@XJ4E5+y5nLsX#GvI`DfKuzY$veR&4nPgqJm08FV;(+im}-3(8--JngUr_fb_)f)oO~r<9#>Y!z;}qz&bcTw}CNeW+i8LuK{g^V?p-UNgio!fu6b)imx3%Jjl&eO0BpqC!)G_bX9xYMxNb ztJRj2tBXoi#f1cmO_tW^sv1v4~M8+2?%Bxis zRjMk9vQ(n2Y0;I{>sy*M1p-xjvq~gVRJW0>1KRdpO>Hw#*QBbbAOuy4x_WtIv#PFH zArQ&x8x#_etf`S`ZBx}WD8%9|ap?{xXRShX(B7|r@@Q!JrnFlxZYSVi**>gk?AG^9 zf}WvY*gTtnJYn;8bnSX%<(itV7cbx#-#HAvhX#6K=$QJ(DYKo?dHvYJ`N+a44#ZQd zR1*h53rdHnwX>Pk%Sr6QD*&P|7k96hwy)-PZorOS*uAdmAQ?pm9L_$Me_U3lsvXc& zw5cLvRuWAPd!ayUq$CXjuAXb5rTI0 zDiy=Cm?B~Uxq^^CL;Nxm=V0OUSpJLHk|!a|+hEjh7~$f&OnB=_NNoC67~c^f7s- zUWupiG_`+}&Ob!u7q9W~le@cY<5K2o+yg5=oBKnyU-o#~Pq?{mdO9t6I4*fQE_+)} zM+DBMBp=4dU<+0yr^sUBRB`dLgouNL*ptK*DLd~tHhww8c{0L#77WSwWL%U~u=Sv2 zlG$u^CJPhwPD;u_F8wGYk7bq}qGcym0v-g=fQg*tW#Zb_46uFr)HUq1Z zu1umAq5x~oE9!LoN?o}ar(2T4BRN8Sd94l&6tgrIUMzP7g$NnZ7FKI(o5)f=kaJl;|DXoW&n@lpx(2zVQQ6d{s%|Fgo0T=Sc*(0Oq!rafSD&h-pKNPYRMsAg1v{A~ zM?%haaq*70MGpU~&gIL7`RlSSU1clT08@AL)(P$C9Go}wQ=n(;+>EV1Miqnj0lwwH z(na5#erQVDJE5i~>Pa;YO!&;vIUQt%;8jj6gDHImIBR?v6@5Cj2JRN@vo02PuIARR z(0}K)uO>IIh8Hhjzf3tQ=VNO)E^i=UY|E`zMMSSK(pGt;(&k=x{+xHN-pn6fN5wQg zdfV0Pju+_AW_P`9e;#D~QGnyG0a%4Rgq`diM4Q2~1HK$S-@Y6A@J^V~M-c`;_BXv7 z;P46Du@VEnh7*w>)w_e8vXRS>WiymuVP(@!veJ*?_g++V1f3u{EW9{!N{NC}e1jAP z6p%%*xu8?RQ3u~9RbB~^3*;G7G?rorl%PxE%W?`SAPY_%*<3|F1#?l}S=oTH!REs8 z7f%4LoHAcE?XxxQvNq@ef6^Y#QIC4yU;`o(7G8)5C?g$%HwRY3LBwP`*)Dr{9r#8l za6gJuFCp1BJ0np?7yh7ebD4$M8$Sf@d}T6D3eKKbDIu&+w?n9EDq2qDKlG& zbA>P$BT%wYzi7uuJB2|Oe6c2xykKKK4XT*6$&|g>l+&Xgudh0MQ}!l^zj2rUP8<1a zUfrv>y6-~rpGW6C2`zr%AFhLircd-)P`utNjKn7EZy^%w1)cH>Sq z3(h7JK5lcq9=qNio8E5Q9(D_^ro*vb^NH~%>1nFuR7GN%GC58f7J5R9-H(lyWn`XU z$O#W$2(%vpa2*qIL}w5gS<1|8lEotF3}r_4NqUYfH{&2RLs68Y0192eRu*totbA2A z^N^mjOG`S;6_AzXat3`bDe;)gla>gy!shd;=JWDKUAa(OQl{aTsWC+h>(%9z>hfwe zw@N3hB)D8;R%!(e+J<_vL_n~LLCjF0JEK$QipX*>`iclXe%eGUZ5|rtYwaeM9>xMyXA)j-NcOYFan{*w5r0XVV{hn0@5$^ve*VyMCrf za%J>PISq?&`awSHgj0w+FG3ce86@*jbOMqkz@!9(3bl;kip(hnim1%Pj*LAQ2V&4K zsh*2QEH4Bc&7)>%CWH^v6M&LD&^d1^{SA*A_2Pv7Yu1P2b;i7EG=SC84Mb?PUFtxC z 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 RZfl*Zq%Z$)#Qn?s{{vS-m{kA( literal 0 HcmV?d00001 From cec6c0a01760fa2f011db2db171836cc6dcbbff2 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 06:36:55 +0100 Subject: [PATCH 118/165] fixed typo --- os/kernel/src/drivers/vbe/vbe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 962b9b5b..a82d6fde 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -160,7 +160,8 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t machine->regs.x.ax = 0x4f04; machine->regs.h.dl = save? 0x01 : 0x02; machine->regs.x.cx = requested_states; - machine->sregs.bx = buffer_pointer; + machine->sregs.es = buffer_pointer; + machine->regs.x.bx = 0x00; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; @@ -168,6 +169,8 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t return VBE_OK; } + + VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) { if(!initialized) return VBE_NO_INITAILIZED; From 1ab4b9e16bbe02ac6440a57cb4cc79d45b204a79 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 06:47:31 +0100 Subject: [PATCH 119/165] Added display window control functions --- os/kernel/src/drivers/vbe/vbe.c | 42 ++++++++++++++++++++++++++++++++- os/kernel/src/drivers/vbe/vbe.h | 3 +++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index a82d6fde..54660c17 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -169,7 +169,47 @@ VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t return VBE_OK; } +VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t window_mem_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f05; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = window_number; + machine->regs.x.dx = window_mem_number; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} +VBEStatus VBE_display_window_control_get_16bit(uint8_t window_number, uint8_t* window_mem_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f05; + machine->regs.h.bh = 0x01; + machine->regs.h.bl = window_number; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *window_mem_number = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t window_mem_number, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = window_number; + machine->regs.x.dx = window_mem_number; + machine->sregs.es = memory_selector; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) { @@ -186,7 +226,7 @@ VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* by return VBE_OK; } -VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f06; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 8bd79ae8..06cc75ef 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -53,6 +53,9 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); +VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t window_mem_number); +VBEStatus VBE_display_window_control_get_16bit(uint8_t window_number, uint8_t* window_mem_number); +VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t window_mem_number, uint16_t memory_selector); VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); From 5e76c44289f9218e48f98df8e602fad20571b933 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 06:54:01 +0100 Subject: [PATCH 120/165] Added set and get dac palette format functions --- os/kernel/src/drivers/vbe/vbe.c | 29 +++++++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 54660c17..0bb2b019 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -240,4 +240,33 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length, uint *actual_pixel_in_line = machine->regs.x.cx; *maximum_scan_lines_number = machine->regs.x.dx; return VBE_OK; +} + +//set/get display start + +VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x00; + machine->regs.h.bh = primary_color_bits; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *curent_number_color_bits = machine->regs.h.bh; + return VBE_OK; +} + +VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x01; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *curent_number_color_bits = machine->regs.h.bh; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 06cc75ef..b71e67d5 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -59,4 +59,7 @@ VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t wi VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits); +VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); + #endif \ No newline at end of file From f5cd8ff2d41ba79ccf839da4e05fcf3cf8c30be2 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 07:00:15 +0100 Subject: [PATCH 121/165] Added get VBE protected mode interface function --- os/kernel/src/drivers/vbe/vbe.c | 17 +++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 0bb2b019..3b577268 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -269,4 +269,21 @@ VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; *curent_number_color_bits = machine->regs.h.bh; return VBE_OK; +} + +//set/get palette data + +VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x01; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *real_mode_table_segment = machine->sregs.es; + *table_offset = machine->regs.x.di; + *table_length = machine->regs.x.cx; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index b71e67d5..d319d876 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -62,4 +62,6 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint1 VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits); VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); +VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); + #endif \ No newline at end of file From 5045cc5d795bad7f95b8f74046ea7912a052b9c7 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 07:06:42 +0100 Subject: [PATCH 122/165] Added VBE get set pixel clock function --- os/kernel/src/drivers/vbe/vbe.c | 15 +++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 1 + 2 files changed, 16 insertions(+) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 3b577268..3c92e0ee 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -286,4 +286,19 @@ VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, ui *table_offset = machine->regs.x.di; *table_length = machine->regs.x.cx; return VBE_OK; +} + +VBEStatus VBE_get_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x00; + machine->regs.d.ecx = pixel_clock; + machine->regs.x.dx = mode_number; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *closest_pixel_clock = machine->regs.d.ecx; + return VBE_OK; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index d319d876..c26ff46e 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -63,5 +63,6 @@ VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); +VBEStatus VBE_get_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); #endif \ No newline at end of file From 1dcbfdebaa8495247d14089a8a5e1a00d0d096f5 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 07:18:09 +0100 Subject: [PATCH 123/165] Fixed ax register init in functions 08, 0a, 0b --- os/kernel/src/drivers/vbe/vbe.c | 11 +++++------ os/kernel/src/drivers/vbe/vbe.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 3c92e0ee..509a9a35 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -247,7 +247,7 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length, uint VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits) { if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f06; + machine->regs.x.ax = 0x4f08; machine->regs.h.bl = 0x00; machine->regs.h.bh = primary_color_bits; int16_t status = v8086_call_int(machine, 0x10); @@ -261,7 +261,7 @@ VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) { if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f06; + machine->regs.x.ax = 0x4f08; machine->regs.h.bl = 0x01; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; @@ -271,12 +271,11 @@ VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) return VBE_OK; } -//set/get palette data VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length) { if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f06; + machine->regs.x.ax = 0x4f0a; machine->regs.h.bl = 0x01; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; @@ -288,10 +287,10 @@ VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, ui return VBE_OK; } -VBEStatus VBE_get_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock) +VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock) { if(!initialized) return VBE_NO_INITAILIZED; - machine->regs.x.ax = 0x4f06; + machine->regs.x.ax = 0x4f0b; machine->regs.h.bl = 0x00; machine->regs.d.ecx = pixel_clock; machine->regs.x.dx = mode_number; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index c26ff46e..52fdaf7f 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -63,6 +63,6 @@ VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); -VBEStatus VBE_get_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); +VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); #endif \ No newline at end of file From 6586ba5e4955204ab5dbeba381afef6668282208 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Wed, 17 Mar 2021 08:09:14 +0100 Subject: [PATCH 124/165] Added VBE set get palette data function --- os/kernel/src/drivers/vbe/vbe.c | 32 ++++++++++++++++++++++++++++++++ os/kernel/src/drivers/vbe/vbe.h | 3 ++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 509a9a35..b06c8fea 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -271,6 +271,38 @@ VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) return VBE_OK; } +VBEStatus VBE_get_set_palette_data_16bit(uint8_t action, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f09; + machine->regs.h.bl = action; + machine->regs.x.cx = palette_registers_num; + machine->regs.x.dx = first_palette_register; + machine->sregs.es = palette_table; + machine->regs.x.di = 0x00; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_get_set_palette_data_32bit(bool during_vertical_retrace, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f09; + machine->regs.h.bl = during_vertical_retrace? 0x80 : 0x00; + machine->regs.x.cx = palette_registers_num; + machine->regs.x.dx = first_palette_register; + machine->sregs.es = palette_table; + machine->regs.d.edi = 0x00; + machine->sregs.ds = memory_selector; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length) { diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 52fdaf7f..748945a1 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -61,7 +61,8 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint1 VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits); VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); - +VBEStatus VBE_get_set_palette_data_16bit(uint8_t action, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table); +VBEStatus VBE_get_set_palette_data_32bit(bool during_vertical_retrace, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table, uint16_t memory_selector); VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); From c174cd5c15fcb0e33278d5675dc791906d888aac Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 17 Mar 2021 11:58:44 +0100 Subject: [PATCH 125/165] 0xDEADBEEF --- os/kernel/src/drivers/vbe/vbe.c | 23 ++++++++++++++--------- os/kernel/src/drivers/vbe/vbe.h | 3 ++- os/kernel/src/kernel.c | 25 +++++++++++++++---------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index b95f7750..209e14d7 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -114,6 +114,11 @@ uint16_t VBE_get_word(uint32_t seg, uint32_t offset) return read_word_from_pointer(machine->Memory, get_absolute_address(seg, offset)); } +uint32_t VBE_get_dword(uint32_t seg, uint32_t offset) +{ + return read_dword_from_pointer(machine->Memory, get_absolute_address(seg, offset)); +} + VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr) { heap_kernel_dealloc(svga_information_ptr->mode_array); @@ -148,27 +153,27 @@ VBEStatus VBE_get_current_video_mode(uint16_t* mode_number) return VBE_OK; } -void VBE_set_current_bank(uint32_t bank_number, uint32_t winsize, uint32_t granularity) +void VBE_set_current_bank(uint32_t bank_number) { if(bank_number != currentBank) { - uint32_t banknum = bank_number * (winsize / granularity); machine->regs.x.ax = 0x4f05; machine->regs.x.bx = 0; - machine->regs.x.dx = banknum; + machine->regs.x.dx = bank_number; int16_t status = v8086_call_int(machine, 0x10); machine->regs.x.ax = 0x4f05; machine->regs.x.bx = 1; - machine->regs.x.dx = banknum; + machine->regs.x.dx = bank_number; status = v8086_call_int(machine, 0x10); } } void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - uint64_t l = (uint64_t) y * (mode_width * 3) + (x*3); - VBE_set_current_bank((l>>10)/winsize, winsize, granularity); - mem_buff[(uint32_t)l] = b; - mem_buff[(uint32_t)l + 1] = g; - mem_buff[(uint32_t)l + 2] = r; + uint32_t offset = (3 * (x + y * mode_width)) % granularity; + uint32_t position = (3 * (x + y * mode_width)) / granularity; + VBE_set_current_bank(position); + mem_buff[offset] = b; + mem_buff[offset + 1] = g; + mem_buff[offset + 2] = r; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 81bb061f..546874a0 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -51,8 +51,9 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); -void VBE_set_current_bank(uint32_t bank_number, uint32_t winsize, uint32_t granularity); +void VBE_set_current_bank(uint32_t bank_number); void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b); uint16_t VBE_get_word(uint32_t seg, uint32_t offset); +uint32_t VBE_get_dword(uint32_t seg, uint32_t offset); #endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 9a4dd33d..aa05c14d 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -497,6 +497,8 @@ int kmain() itoa(max_bit_per_pixel, buff, 10); vga_printstring(buff); vga_newline(); + + VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); itoa(mode_info.mode_attributes, buff, 16); vga_printstring(buff); @@ -505,26 +507,29 @@ int kmain() uint32_t seg = VBE_get_word(0x0, 0x7E1E + 12); VBEStatus x = VBE_set_video_mode(mode_number | (1 << 14), true); VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); - off = VBE_get_word(0x0, 0x7E1E + 10); - seg = VBE_get_word(0x0, 0x7E1E + 12); + off = VBE_get_word(0x0, 0x7E00 + 40); + seg = VBE_get_word(0x0, 0x7E00 + 42); + uint32_t address = VBE_get_dword(0x00, 0x7E00); + VBE_get_current_video_mode(&mode_number); uint8_t* mem_buff = (uint8_t*)0xc0000000; - /*for(int i = 0; i < 320 * 240; i++) + for(int i = 0; i < 320 * 240; i++) { - //mem_buff[seg * 0x10 + off + i * 3] = 255; + //mem_buff[seg * 0x10 + off + i] = 255; + mem_buff[address + i] = 255; //mem_buff[seg * 0x10 + off + i * 3 + 1] = 255; //mem_buff[seg * 0x10 + off + i * 3 + 2] = 255; - mem_buff[0xA0000 + i * 3] = 255; - mem_buff[0xA0000 + i * 3 + 1] = 0; - mem_buff[0xA0000 + i * 3 + 2] = 0; - }*/ - VBE_set_current_bank(0, mode_info.windows_size, mode_info.granularity); + //mem_buff[0xA0000 + i * 3] = 255; + //mem_buff[0xA0000 + i * 3 + 1] = 0; + //mem_buff[0xA0000 + i * 3 + 2] = 0; + } + /*VBE_set_current_bank(0); for(int xx = 0; xx < 320; xx++) { for(int yy = 0; yy < 200; yy++) { VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); } - } + }*/ } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); From 5655d942ce0de5b80057c408c1d305f0ecd244a6 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Wed, 17 Mar 2021 12:02:59 +0100 Subject: [PATCH 126/165] 0xDEADBEEF --- os/kernel/src/kernel.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index aa05c14d..de760acf 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -505,13 +505,13 @@ int kmain() vga_newline(); uint32_t off = VBE_get_word(0x0, 0x7E1E + 10); uint32_t seg = VBE_get_word(0x0, 0x7E1E + 12); - VBEStatus x = VBE_set_video_mode(mode_number | (1 << 14), true); - VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); + VBEStatus x = VBE_set_video_mode(mode_number, true); + VBE_get_vesa_mode_information(&mode_info, mode_number); off = VBE_get_word(0x0, 0x7E00 + 40); seg = VBE_get_word(0x0, 0x7E00 + 42); uint32_t address = VBE_get_dword(0x00, 0x7E00); VBE_get_current_video_mode(&mode_number); - uint8_t* mem_buff = (uint8_t*)0xc0000000; + /*uint8_t* mem_buff = (uint8_t*)0xc0000000; for(int i = 0; i < 320 * 240; i++) { //mem_buff[seg * 0x10 + off + i] = 255; @@ -521,15 +521,15 @@ int kmain() //mem_buff[0xA0000 + i * 3] = 255; //mem_buff[0xA0000 + i * 3 + 1] = 0; //mem_buff[0xA0000 + i * 3 + 2] = 0; - } - /*VBE_set_current_bank(0); + }*/ + VBE_set_current_bank(0); for(int xx = 0; xx < 320; xx++) { for(int yy = 0; yy < 200; yy++) { VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); } - }*/ + } } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); From ef05df87ce1afea3429763dd5de58fc9091a2998 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 18 Mar 2021 01:54:41 +0100 Subject: [PATCH 127/165] Drawing Lena works! --- os/kernel/src/drivers/vbe/vbe.c | 24 ++++++--- os/kernel/src/drivers/vbe/vbe.h | 2 +- os/kernel/src/drivers/vga/vga_gmode.c | 22 +++++++++ os/kernel/src/drivers/vga/vga_gmode.h | 1 + os/kernel/src/kernel.c | 71 ++++++++++++++------------- os/kernel/src/v8086/v8086.c | 8 +++ os/kernel/src/v8086/v8086.h | 2 + 7 files changed, 90 insertions(+), 40 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 209e14d7..15b9b116 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -153,26 +153,38 @@ VBEStatus VBE_get_current_video_mode(uint16_t* mode_number) return VBE_OK; } -void VBE_set_current_bank(uint32_t bank_number) +VBEStatus VBE_set_current_bank(uint32_t bank_number) { if(bank_number != currentBank) { machine->regs.x.ax = 0x4f05; machine->regs.x.bx = 0; machine->regs.x.dx = bank_number; + setSkipDebugging(false); int16_t status = v8086_call_int(machine, 0x10); - machine->regs.x.ax = 0x4f05; - machine->regs.x.bx = 1; + setSkipDebugging(true); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + /*machine->regs.x.ax = 0x4f05; + machine->regs.x.bx = 0; machine->regs.x.dx = bank_number; status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE;*/ + currentBank = bank_number; + return VBE_OK; } + return VBE_OK; } void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - uint32_t offset = (3 * (x + y * mode_width)) % granularity; - uint32_t position = (3 * (x + y * mode_width)) / granularity; - VBE_set_current_bank(position); + uint32_t offset = (y * 3) * mode_width + (x * 3); + uint32_t position = offset / (granularity * 1024); + offset = offset - (granularity * 1024) * position; + VBEStatus status = VBE_set_current_bank(position); mem_buff[offset] = b; mem_buff[offset + 1] = g; mem_buff[offset + 2] = r; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 546874a0..81f86e35 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -51,7 +51,7 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); -void VBE_set_current_bank(uint32_t bank_number); +VBEStatus VBE_set_current_bank(uint32_t bank_number); void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b); uint16_t VBE_get_word(uint32_t seg, uint32_t offset); uint32_t VBE_get_dword(uint32_t seg, uint32_t offset); diff --git a/os/kernel/src/drivers/vga/vga_gmode.c b/os/kernel/src/drivers/vga/vga_gmode.c index 4cd15cf9..8a7b74b5 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.c +++ b/os/kernel/src/drivers/vga/vga_gmode.c @@ -4,6 +4,7 @@ #include "vga.h" #include "filesystems/filesystem.h" #include "modes/mode_13h/mode_13h.h" +#include "../vbe/vbe.h" #define peekb(S, O) *(unsigned char *)(16uL * (S) + (O)) #define pokeb(S, O, V) *(unsigned char *)(16uL * (S) + (O)) = (V) @@ -88,6 +89,27 @@ void drawLenaIn13H() heap_kernel_dealloc(buffer); } +void drawLenaIn10fH() +{ + filesystem_file_info info; + filesystem_get_file_info("A:/LENAD.BMP", &info); + + uint8_t *buffer = heap_kernel_alloc(info.size, 0); + filesystem_read_file("A:/LENAD.BMP", buffer, 0, info.size); + + OS2BMPFILEHEADER fh; + memcpy(&fh, buffer, sizeof(OS2BMPFILEHEADER)); + + OS21XBITMAPHEADER bh; + memcpy(&bh, buffer + sizeof(OS2BMPFILEHEADER), sizeof(OS21XBITMAPHEADER)); + + for(int x = 0; x < bh.Width; x++) + for(int y = 0; y < bh.Height; y++) + //mode13h_draw_pixel(buffer[fh.BitmapOffset + (bh.Height * bh.Width - bh.Width - y*bh.Width) + x],x,y); + VBE_draw_pixel_8_8_8(320, 240, 64, 64, x, y, buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width + 2], buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width + 1], buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width]); + heap_kernel_dealloc(buffer); +} + char vga_gmode_get_mode() { return mode; diff --git a/os/kernel/src/drivers/vga/vga_gmode.h b/os/kernel/src/drivers/vga/vga_gmode.h index 3ca832ff..be3c6680 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.h +++ b/os/kernel/src/drivers/vga/vga_gmode.h @@ -5,6 +5,7 @@ void drawMicrOSLogoIn13H(); void drawLenaIn13H(); +void drawLenaIn10fH(); char vga_gmode_get_mode(); diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index de760acf..b8a7d9d5 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -418,8 +418,26 @@ int kmain() serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); + #define FUN_1 + + #ifdef FUN_1 + mode13h_set_mode(); + drawLenaIn13H(); + #endif + + #ifdef FUN_2 + v8086* machine = v8086_create_machine(); + v8086_set_386_instruction_set(machine); + machine->regs.x.ax = 0x13; + v8086_call_int(machine, 0x10); + drawLenaIn13H(); + #endif + + + #ifdef FUN_3 char buff[100]; VBE_initialize(); + setSkipDebugging(true); //VBE_set_video_mode(0x18c, false); svga_mode_information mode_info; //VBE_get_vesa_mode_information(&mode_info, 0x105); @@ -497,43 +515,30 @@ int kmain() itoa(max_bit_per_pixel, buff, 10); vga_printstring(buff); vga_newline(); - - - VBE_get_vesa_mode_information(&mode_info, mode_number | (1 << 14)); - itoa(mode_info.mode_attributes, buff, 16); - vga_printstring(buff); - vga_newline(); - uint32_t off = VBE_get_word(0x0, 0x7E1E + 10); - uint32_t seg = VBE_get_word(0x0, 0x7E1E + 12); - VBEStatus x = VBE_set_video_mode(mode_number, true); - VBE_get_vesa_mode_information(&mode_info, mode_number); - off = VBE_get_word(0x0, 0x7E00 + 40); - seg = VBE_get_word(0x0, 0x7E00 + 42); - uint32_t address = VBE_get_dword(0x00, 0x7E00); - VBE_get_current_video_mode(&mode_number); - /*uint8_t* mem_buff = (uint8_t*)0xc0000000; - for(int i = 0; i < 320 * 240; i++) - { - //mem_buff[seg * 0x10 + off + i] = 255; - mem_buff[address + i] = 255; - //mem_buff[seg * 0x10 + off + i * 3 + 1] = 255; - //mem_buff[seg * 0x10 + off + i * 3 + 2] = 255; - //mem_buff[0xA0000 + i * 3] = 255; - //mem_buff[0xA0000 + i * 3 + 1] = 0; - //mem_buff[0xA0000 + i * 3 + 2] = 0; - }*/ - VBE_set_current_bank(0); - for(int xx = 0; xx < 320; xx++) - { - for(int yy = 0; yy < 200; yy++) - { - VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); - } } - } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); } + #endif + + #ifdef FUN_4 + VBE_initialize(); + VBEStatus x = VBE_set_video_mode(0x10f, true); + svga_mode_information mode_info; + VBE_get_vesa_mode_information(&mode_info, 0x10f); + VBE_set_current_bank(0); + for(int yy = 0; yy < 200; yy++) + for(int xx = 0; xx < 320; xx++) + VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); + + #endif + + #ifdef FUN_5 + VBE_initialize(); + VBEStatus x = VBE_set_video_mode(0x10f, true); + VBE_set_current_bank(0); + drawLenaIn10fH(); + #endif while (1); return 0; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 94d27353..f5d818be 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -20,6 +20,8 @@ //#define DEBUG_V8086_INTERACTIVE #endif +bool skipDebugging = false; + int16_t parse_and_execute_instruction(v8086* machine); #ifdef DEBUG_V8086 @@ -113,6 +115,11 @@ uint32_t read_reg_32() return value; } +void setSkipDebugging(bool value) +{ + skipDebugging = value; +} + #endif void v8086_set_8086_instruction_set(v8086* machine) @@ -474,6 +481,7 @@ int16_t parse_and_execute_instruction(v8086* machine) #endif #ifdef DEBUG_V8086_INTERACTIVE + if(!skipDebugging) while(true) { char d[100]; diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 0b05dd82..389b5e58 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -2,6 +2,7 @@ #define V8086_H #include +#include #define bit_get(p,m) ((p) & (m)) #define bit_set(p,m) ((p) |= (m)) @@ -178,5 +179,6 @@ uint32_t v8086_get_address_of_int(v8086* machine, int16_t num); uint32_t read_reg_32(); void read_regs(v8086* machine); void read_sregs(v8086* machine); + void setSkipDebugging(bool value); #endif #endif \ No newline at end of file From b71dfb1034d71da99f932c4c217a31a85efd27ec Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sat, 20 Mar 2021 12:40:28 +0100 Subject: [PATCH 128/165] Fixed VBE palette data set and get functions --- os/kernel/src/drivers/vbe/vbe.c | 93 ++++++++++++++++++++++++++++----- os/kernel/src/drivers/vbe/vbe.h | 7 ++- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index b06c8fea..b76a292b 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -271,15 +271,20 @@ VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) return VBE_OK; } -VBEStatus VBE_get_set_palette_data_16bit(uint8_t action, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table) +//table_size max value is 256 +VBEStatus VBE_set_palette_data_16bit(bool secondary_palette, uint8_t index, uint8_t palette_table[], uint16_t table_size) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f09; - machine->regs.h.bl = action; - machine->regs.x.cx = palette_registers_num; - machine->regs.x.dx = first_palette_register; - machine->sregs.es = palette_table; - machine->regs.x.di = 0x00; + machine->regs.h.bl = secondary_palette?0x02:0x00; + machine->regs.x.cx = table_size; + machine->regs.x.dx = index; + machine->sregs.es = 0x0000; + machine->regs.x.di = 0x7E00; + for(uint16_t i = 0; iMemory[0x00*10+0x7E00 + i] = palette_table[i]; + } int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; @@ -287,16 +292,80 @@ VBEStatus VBE_get_set_palette_data_16bit(uint8_t action, uint8_t palette_registe return VBE_OK; } -VBEStatus VBE_get_set_palette_data_32bit(bool during_vertical_retrace, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table, uint16_t memory_selector) +VBEStatus VBE_set_during_vertical_retrace_palette_data_16bit(uint16_t index, uint8_t palette_table[], uint16_t table_size) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f09; - machine->regs.h.bl = during_vertical_retrace? 0x80 : 0x00; - machine->regs.x.cx = palette_registers_num; - machine->regs.x.dx = first_palette_register; - machine->sregs.es = palette_table; - machine->regs.d.edi = 0x00; + machine->regs.h.bl = 0x80; + machine->regs.x.cx = table_size; + machine->regs.x.dx = index; + machine->sregs.es = 0x0000; + machine->regs.x.di = 0x7E00; + for(uint16_t i = 0; iMemory[0x00*10+0x7E00 + i] = palette_table[i]; + } + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_get_palette_data_16bit(bool secondary_palette, uint16_t index, uint8_t palette_table[], uint16_t table_size) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f09; + machine->regs.h.bl = secondary_palette?0x03:0x01; + machine->regs.x.cx = table_size; + machine->regs.x.dx = index; + machine->sregs.es = 0x0000; + machine->regs.x.di = 0x7E00; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + for(uint16_t i = 0; iMemory[0x00 * 10 + 0x7E00 + i]; + } + return VBE_OK; +} + +VBEStatus VBE_set_palette_data_32bit(uint16_t index, uint8_t palette_table[], uint16_t table_size, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.h.bl = 0x00; + machine->regs.x.cx = table_size; + machine->regs.x.dx = index; + machine->sregs.es = 0x0000; + machine->regs.d.edi = 0x7E00; + machine->sregs.ds = memory_selector; + for(uint16_t i = 0; iMemory[0x00*10+0x7E00 + i] = palette_table[i]; + } + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + + +VBEStatus VBE_set_during_vertical_retrace_palette_data_32bit(uint16_t index, uint8_t palette_table[], uint16_t table_size, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.h.bl = 0x80; + machine->regs.x.cx = table_size; + machine->regs.x.dx = index; + machine->sregs.es = 0x0000; + machine->regs.d.edi = 0x7E00; machine->sregs.ds = memory_selector; + for(uint16_t i = 0; iMemory[0x00*10+0x7E00 + i] = palette_table[i]; + } int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 748945a1..f6816f21 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -61,8 +61,11 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint1 VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits); VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); -VBEStatus VBE_get_set_palette_data_16bit(uint8_t action, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table); -VBEStatus VBE_get_set_palette_data_32bit(bool during_vertical_retrace, uint8_t palette_registers_num, uint16_t first_palette_register, uint16_t palette_table, uint16_t memory_selector); +VBEStatus VBE_set_palette_data_16bit(bool secondary_palette, uint8_t index, uint8_t palette_table[], uint16_t table_size); +VBEStatus VBE_set_during_vertical_retrace_palette_data_16bit(uint16_t index, uint8_t palette_table[], uint16_t table_size); +VBEStatus VBE_get_palette_data_16bit(bool secondary_palette, uint16_t index, uint8_t palette_table[], uint16_t table_size); +VBEStatus VBE_set_palette_data_32bit(uint16_t index, uint8_t palette_table[], uint16_t table_size, uint16_t memory_selector); +VBEStatus VBE_set_during_vertical_retrace_palette_data_32bit(uint16_t index, uint8_t palette_table[], uint16_t table_size, uint16_t memory_selector); VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); From 3bb908568f33088472fcd75774c9a5b0e04600a3 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sat, 20 Mar 2021 13:02:25 +0100 Subject: [PATCH 129/165] Minor bugfix --- os/kernel/src/drivers/vbe/vbe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index b76a292b..283204bd 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -120,7 +120,7 @@ VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen) if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f02; machine->regs.x.bx = mode_number & 0x7FFF; - if(clear_screen) machine->regs.x.bx | 0x8000; + if(clear_screen) machine->regs.x.bx = machine->regs.x.bx | 0x8000; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; From 98ba0bf15f13d3c224bf9b3bc76b09bef96392dc Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sat, 20 Mar 2021 13:15:16 +0100 Subject: [PATCH 130/165] Added set and get display start functions --- os/kernel/src/drivers/vbe/vbe.c | 114 +++++++++++++++++++++++++++++++- os/kernel/src/drivers/vbe/vbe.h | 9 ++- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 283204bd..b85b9c2a 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -242,7 +242,119 @@ VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length, uint return VBE_OK; } -//set/get display start +VBEStatus VBE_set_display_start_16bit(bool during_vertical_retrace, uint16_t first_line, uint16_t first_pixel_in_line) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = during_vertical_retrace?0x80:0x00; + machine->regs.x.cx = first_pixel_in_line; + machine->regs.x.dx = first_line; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_get_display_start_16bit(uint16_t* first_line, uint16_t* first_pixel_in_line) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = 0x01; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *first_pixel_in_line = machine->regs.x.cx; + *first_line = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_schedule_display_start_16bit(bool during_vertical_retrace, uint32_t display_start_address_byte) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = during_vertical_retrace?0x082:0x02; + machine->regs.d.ecx = display_start_address_byte; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_schedule_stereoscopic_display_start_16bit(bool during_vertical_retrace, uint32_t left_image_address_byte, uint32_t right_image_address_byte) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = during_vertical_retrace?0x083:0x03; + machine->regs.d.ecx = left_image_address_byte; + machine->regs.d.edx = right_image_address_byte; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_get_scheduled_display_start_16bit(bool* flip_occured) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = 0x04; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *flip_occured = machine->regs.x.cx==0?false:true; + return VBE_OK; +} + +VBEStatus VBE_enable_stereoscopic_mode() +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = 0x05; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_disable_stereoscopic_mode() +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f07; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = 0x06; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_set_display_start_32bit(bool during_vertical_retrace, uint16_t first_half_start_address, uint16_t second_half_start_address, uint16_t memory_selector) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.h.bh = 0x00; + machine->regs.h.bl = during_vertical_retrace?0x80:0x00; + machine->regs.x.cx = first_half_start_address; + machine->regs.x.dx = second_half_start_address; + machine->sregs.es = memory_selector; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits) { diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index f6816f21..7a250797 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -58,7 +58,14 @@ VBEStatus VBE_display_window_control_get_16bit(uint8_t window_number, uint8_t* w VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t window_mem_number, uint16_t memory_selector); VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); - +VBEStatus VBE_set_display_start_16bit(bool during_vertical_retrace, uint16_t first_line, uint16_t first_pixel_in_line); +VBEStatus VBE_get_display_start_16bit(uint16_t* first_line, uint16_t* first_pixel_in_line); +VBEStatus VBE_schedule_display_start_16bit(bool during_vertical_retrace, uint32_t display_start_address_byte); +VBEStatus VBE_schedule_stereoscopic_display_start_16bit(bool during_vertical_retrace, uint32_t left_image_address_byte, uint32_t right_image_address_byte); +VBEStatus VBE_get_scheduled_display_start_16bit(bool* flip_occured); +VBEStatus VBE_enable_stereoscopic_mode(); +VBEStatus VBE_disable_stereoscopic_mode(); +VBEStatus VBE_set_display_start_32bit(bool during_vertical_retrace, uint16_t first_half_start_address, uint16_t second_half_start_address, uint16_t memory_selector); VBEStatus VBE_set_dac_palette_format(uint8_t primary_color_bits, uint8_t* curent_number_color_bits); VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits); VBEStatus VBE_set_palette_data_16bit(bool secondary_palette, uint8_t index, uint8_t palette_table[], uint16_t table_size); From f3a8f0f6cce24145668ac6316c682815c5b6dd17 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sat, 20 Mar 2021 14:11:51 +0100 Subject: [PATCH 131/165] Splitted VBE_save_restore_state function into two --- os/kernel/src/drivers/vbe/vbe.c | 19 +++++++++++++++++-- os/kernel/src/drivers/vbe/vbe.h | 3 ++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index b85b9c2a..049ba340 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -154,11 +154,26 @@ VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, u return VBE_OK; } -VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer) +VBEStatus VBE_save_state(uint16_t requested_states, uint16_t buffer_pointer) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f04; - machine->regs.h.dl = save? 0x01 : 0x02; + machine->regs.h.dl = 0x01; + machine->regs.x.cx = requested_states; + machine->sregs.es = buffer_pointer; + machine->regs.x.bx = 0x00; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + return VBE_OK; +} + +VBEStatus VBE_restore_state(uint16_t requested_states, uint16_t buffer_pointer) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f04; + machine->regs.h.dl = 0x02; machine->regs.x.cx = requested_states; machine->sregs.es = buffer_pointer; machine->regs.x.bx = 0x00; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index 7a250797..df8f4da9 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -52,7 +52,8 @@ VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); -VBEStatus VBE_save_restore_state(bool save, uint16_t requested_states, uint16_t buffer_pointer); +VBEStatus VBE_save_state(uint16_t requested_states, uint16_t buffer_pointer); +VBEStatus VBE_restore_state(uint16_t requested_states, uint16_t buffer_pointer); VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t window_mem_number); VBEStatus VBE_display_window_control_get_16bit(uint8_t window_number, uint8_t* window_mem_number); VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t window_mem_number, uint16_t memory_selector); From 79dff9cdd012e904fc3414486e9597b858fd4520 Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sat, 20 Mar 2021 14:21:23 +0100 Subject: [PATCH 132/165] Splitted some functions into two --- os/kernel/src/drivers/vbe/vbe.c | 40 ++++++++++++++++++++++++++++----- os/kernel/src/drivers/vbe/vbe.h | 6 +++-- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 049ba340..8718ee42 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -226,11 +226,42 @@ VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t wi return VBE_OK; } -VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +VBEStatus VBE_get_logical_scan_line_length(uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f06; - machine->regs.h.bl = get_maximum_length? 0x03: 0x01; + machine->regs.h.bl = 0x01; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *bytes_per_line = machine->regs.x.bx; + *actual_pixel_in_line = machine->regs.x.cx; + *maximum_scan_lines_number = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_get_maximum_logical_scan_line_length(uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x03; + int16_t status = v8086_call_int(machine, 0x10); + if(status != 0x10) return VBE_INTERNAL_ERROR; + if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; + if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; + *bytes_per_line = machine->regs.x.bx; + *actual_pixel_in_line = machine->regs.x.cx; + *maximum_scan_lines_number = machine->regs.x.dx; + return VBE_OK; +} + +VBEStatus VBE_set_logical_scan_line_length_in_pixels(uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +{ + if(!initialized) return VBE_NO_INITAILIZED; + machine->regs.x.ax = 0x4f06; + machine->regs.h.bl = 0x00; + machine->regs.x.cx = length; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; @@ -241,11 +272,11 @@ VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* by return VBE_OK; } -VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) +VBEStatus VBE_set_logical_scan_line_length_in_bytes(uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number) { if(!initialized) return VBE_NO_INITAILIZED; machine->regs.x.ax = 0x4f06; - machine->regs.h.bl = in_pixels? 0x00: 0x02; + machine->regs.h.bl = 0x02; machine->regs.x.cx = length; int16_t status = v8086_call_int(machine, 0x10); if(status != 0x10) return VBE_INTERNAL_ERROR; @@ -398,7 +429,6 @@ VBEStatus VBE_get_dac_palette_format(uint8_t* curent_number_color_bits) return VBE_OK; } -//table_size max value is 256 VBEStatus VBE_set_palette_data_16bit(bool secondary_palette, uint8_t index, uint8_t palette_table[], uint16_t table_size) { if(!initialized) return VBE_NO_INITAILIZED; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index df8f4da9..284ed71d 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -57,8 +57,10 @@ VBEStatus VBE_restore_state(uint16_t requested_states, uint16_t buffer_pointer); VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t window_mem_number); VBEStatus VBE_display_window_control_get_16bit(uint8_t window_number, uint8_t* window_mem_number); VBEStatus VBE_display_window_control_set_32bit(uint8_t window_number, uint8_t window_mem_number, uint16_t memory_selector); -VBEStatus VBE_get_logical_scan_line_length(bool get_maximum_length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); -VBEStatus VBE_set_logical_scan_line_length(bool in_pixels, uint16_t length,uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_get_logical_scan_line_length(uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_get_maximum_logical_scan_line_length(uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_set_logical_scan_line_length_in_pixels(uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); +VBEStatus VBE_set_logical_scan_line_length_in_bytes(uint16_t length, uint16_t* bytes_per_line, uint16_t* actual_pixel_in_line, uint16_t* maximum_scan_lines_number); VBEStatus VBE_set_display_start_16bit(bool during_vertical_retrace, uint16_t first_line, uint16_t first_pixel_in_line); VBEStatus VBE_get_display_start_16bit(uint16_t* first_line, uint16_t* first_pixel_in_line); VBEStatus VBE_schedule_display_start_16bit(bool during_vertical_retrace, uint32_t display_start_address_byte); From dd7b5862963e09abe49a6ed5f0f1f39dc6a6f612 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 23 Mar 2021 19:18:00 +0100 Subject: [PATCH 133/165] Update --- os/kernel/src/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index b8a7d9d5..f6c12e16 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -418,7 +418,7 @@ int kmain() serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); - #define FUN_1 + #define FUN_5 #ifdef FUN_1 mode13h_set_mode(); From 43815b3e44097a5c441a1e6d98d0b7b65f2d7d3f Mon Sep 17 00:00:00 2001 From: xBLACKxSNAKEx Date: Sun, 11 Apr 2021 13:50:09 +0200 Subject: [PATCH 134/165] Tested linear buffer --- os/kernel/src/drivers/vbe/vbe.c | 15 ++++++++++++++- os/kernel/src/drivers/vbe/vbe.h | 14 ++++++++++++++ os/kernel/src/drivers/vga/vga_gmode.c | 25 +++++++++++++++++++++++++ os/kernel/src/drivers/vga/vga_gmode.h | 1 + os/kernel/src/kernel.c | 14 +++++++++++++- 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index a9c9655e..eb4e8d84 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -105,7 +105,19 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc infromation_struct->bank_size = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1C)); infromation_struct->page_count = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1D)); infromation_struct->reserved = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1E)); + infromation_struct->mask_size_red = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E1F)); + infromation_struct->field_position_red = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E20)); + infromation_struct->mask_size_green = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E21)); + infromation_struct->field_position_green = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E22)); + infromation_struct->mask_size_blue = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E23)); + infromation_struct->field_position_blue = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E24)); + infromation_struct->mask_size_direct_color = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E25)); + infromation_struct->field_position_direct_color = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E26)); + infromation_struct->direct_color_mode_info = read_byte_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E27)); + infromation_struct->frame_buffor_phys_address = read_dword_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E28)); + infromation_struct->reserved1 = read_dword_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E2C)); + infromation_struct->reserved2 = read_word_from_pointer(machine->Memory, get_absolute_address(0x0000, 0x7E30)); return VBE_OK; } @@ -182,7 +194,8 @@ VBEStatus VBE_set_current_bank(uint32_t bank_number) void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { uint32_t offset = (y * 3) * mode_width + (x * 3); - uint32_t position = offset / (granularity * 1024); + //uint32_t position = (offset/(granularity * 1024)); + uint32_t position = (offset/(granularity*1024)) * (winsize/granularity); offset = offset - (granularity * 1024) * position; VBEStatus status = VBE_set_current_bank(position); mem_buff[offset] = b; diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index eee2bf29..b3f33988 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -35,6 +35,20 @@ typedef struct _svga_mode_information{ uint8_t bank_size; uint8_t page_count; uint8_t reserved; + + uint8_t mask_size_red; + uint8_t field_position_red; + uint8_t mask_size_green; + uint8_t field_position_green; + uint8_t mask_size_blue; + uint8_t field_position_blue; + uint8_t mask_size_direct_color; + uint8_t field_position_direct_color; + uint8_t direct_color_mode_info; + + uint32_t frame_buffor_phys_address; + uint32_t reserved1; + uint16_t reserved2; } svga_mode_information; typedef enum _VBEStatus{ diff --git a/os/kernel/src/drivers/vga/vga_gmode.c b/os/kernel/src/drivers/vga/vga_gmode.c index 8a7b74b5..54bfa530 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.c +++ b/os/kernel/src/drivers/vga/vga_gmode.c @@ -89,6 +89,31 @@ void drawLenaIn13H() heap_kernel_dealloc(buffer); } +void drawLenaIn10fH_linear(uint8_t* color) +{ + filesystem_file_info info; + filesystem_get_file_info("A:/LENAD.BMP", &info); + + uint8_t *buffer = heap_kernel_alloc(info.size, 0); + filesystem_read_file("A:/LENAD.BMP", buffer, 0, info.size); + + OS2BMPFILEHEADER fh; + memcpy(&fh, buffer, sizeof(OS2BMPFILEHEADER)); + + OS21XBITMAPHEADER bh; + memcpy(&bh, buffer + sizeof(OS2BMPFILEHEADER), sizeof(OS21XBITMAPHEADER)); + + for(int x = 0; x < bh.Width; x++) + for(int y = 0; y < bh.Height; y++) + { + int i = 3*y * bh.Width + 3*x; + color[i] = buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width]; + color[i+1] = buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width + 1]; + color[i+2] = buffer[fh.BitmapOffset + (x * 3) + (bh.Height - y - 1) * 3 * bh.Width + 2]; + } + heap_kernel_dealloc(buffer); +} + void drawLenaIn10fH() { filesystem_file_info info; diff --git a/os/kernel/src/drivers/vga/vga_gmode.h b/os/kernel/src/drivers/vga/vga_gmode.h index be3c6680..bd438eec 100644 --- a/os/kernel/src/drivers/vga/vga_gmode.h +++ b/os/kernel/src/drivers/vga/vga_gmode.h @@ -5,6 +5,7 @@ void drawMicrOSLogoIn13H(); void drawLenaIn13H(); +void drawLenaIn10fH_linear(uint8_t* color); void drawLenaIn10fH(); char vga_gmode_get_mode(); diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index f6c12e16..a8554195 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -418,7 +418,7 @@ int kmain() serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); - #define FUN_5 + #define FUN_3 #ifdef FUN_1 mode13h_set_mode(); @@ -467,6 +467,7 @@ int kmain() uint32_t max_width = 0; uint32_t max_height = 0; uint16_t max_bit_per_pixel = 0; + uint32_t physBufforAddress = 0; for(int i=0; i < svga_info_ptr->number_of_modes; i++) //for(int i=0x11b; i < 0x11c; i++) { @@ -480,6 +481,7 @@ int kmain() while(!keyboard_get_key_from_buffer(&kb)); } else{ + physBufforAddress = mode_info.frame_buffor_phys_address; if(mode_info.mode_height == 200 && mode_info.mode_width == 320 && mode_info.bits_per_pixel == 24) { mode_number = svga_info_ptr->mode_array[i]; @@ -515,7 +517,17 @@ int kmain() itoa(max_bit_per_pixel, buff, 10); vga_printstring(buff); vga_newline(); + + if(physBufforAddress != 0) + { + VBEStatus x = VBE_set_video_mode(0x10f|(1<<14), true); + VBE_set_current_bank(0); + paging_map_page(physBufforAddress/0x400000, 12, false); + uint8_t* color = 12*0x400000 + 0xc00000000; + drawLenaIn10fH_linear(color); + paging_unmap_page(12); } + } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); } From fc80cbe67334756e897b41c83230bc93cdcd6a8e Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Tue, 20 Apr 2021 16:21:29 +0200 Subject: [PATCH 135/165] Update harddisk_header.c Reading the status register takes at least 100ns on a 10MHz bus, but the parallel ATA bus supports speeds up to 33MHz, which means reading a register could take only 30ns. You would have to read the status register 14 times to ensure a 400ns delay. --- os/kernel/src/drivers/harddisk/harddisk_header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/harddisk/harddisk_header.c b/os/kernel/src/drivers/harddisk/harddisk_header.c index a7963011..5ce77538 100644 --- a/os/kernel/src/drivers/harddisk/harddisk_header.c +++ b/os/kernel/src/drivers/harddisk/harddisk_header.c @@ -5,7 +5,7 @@ harddisk_states harddisk_current_states; void __harddisk_400ns_delay(uint16_t port) { - for(int i = 0; i < 4; ++i) + for(int i = 0; i < 15; ++i) { io_in_byte(port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET); } From 108c6e401bb6033fcebacf55b1f9a5be275d8669 Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Tue, 20 Apr 2021 16:22:41 +0200 Subject: [PATCH 136/165] Changed used port --- .../src/drivers/harddisk/ata/harddisk_ata.c | 16 ++++++++-------- .../src/drivers/harddisk/ata/harddisk_ata.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c index b7d6c3bb..8ae5ff78 100644 --- a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c +++ b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c @@ -66,7 +66,7 @@ int8_t __harddisk_ata_read_sector(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA_B __harddisk_400ns_delay(control_port); // For any other value: poll the Status port until bit 7 (BSY, value = 0x80) clears. - int8_t pooling_result = __harddisk_ata_poll(control_port); + int8_t pooling_result = __harddisk_ata_poll(io_port + HARDDISK_IO_STATUS_REGISTER_OFFSET); if(pooling_result == 1) { for(int i = 0; i < 256; i++) @@ -122,13 +122,13 @@ int8_t __harddisk_ata_write_sector(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA_ } __harddisk_400ns_delay(control_port); - if(__harddisk_ata_poll(control_port) != 1) return -1; + if(__harddisk_ata_poll(control_port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET) != 1) return -1; // Send message to drive io_out_byte(io_port + HARDDISK_IO_DRIVE_HEAD_REGISTER_OFFSET, message_to_drive.value); __harddisk_400ns_delay(control_port); - if(__harddisk_ata_poll(control_port) != 1) return -1; + if(__harddisk_ata_poll(control_port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET) != 1) return -1; // Send what to write io_out_byte(io_port + HARDDISK_IO_SECTOR_COUNT_REGISTER_OFFSET, 0); @@ -146,7 +146,7 @@ int8_t __harddisk_ata_write_sector(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA_ __harddisk_400ns_delay(control_port); // For any other value: poll the Status port until bit 7 (BSY, value = 0x80) clears. - int8_t pooling_result = __harddisk_ata_poll(control_port); + int8_t pooling_result = __harddisk_ata_poll(io_port + HARDDISK_IO_STATUS_REGISTER_OFFSET); if(pooling_result == 1) { for(int i = 0; i < 256; i++) @@ -167,19 +167,19 @@ int8_t __harddisk_ata_write_sector(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA_ } -int8_t __harddisk_ata_poll(uint16_t control_port) +int8_t __harddisk_ata_poll(uint16_t port) { harddisk_io_control_status_register result; for(;;) { - result.value = io_in_byte(control_port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET); + result.value = io_in_byte(port); if(result.fields.busy == 0) { // Otherwise, continue polling one of the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets. for(;;) { - result.value = io_in_byte(control_port + HARDDISK_CONTROL_ALTERNATE_STATUS_REGISTER_OFFSET); - if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1 || result.fields.overlapped_mode_service_request == 1) + result.value = io_in_byte(port); + if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1) { return 1; } diff --git a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.h b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.h index ff0b40fa..d8150ba2 100644 --- a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.h +++ b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.h @@ -50,6 +50,6 @@ uint32_t __harddisk_ata_get_disk_space(const harddisk_identify_device_data *data \param port Port for do delay. \return 1 if ready, -1 if error */ -int8_t __harddisk_ata_poll(uint16_t control_port); +int8_t __harddisk_ata_poll(uint16_t port); #endif \ No newline at end of file From 8cc237a18e2e21ea16319a0be086d8c93ad71eeb Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Thu, 22 Apr 2021 15:48:47 +0200 Subject: [PATCH 137/165] Typo --- os/kernel/src/drivers/harddisk/harddisk_identify_device_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/kernel/src/drivers/harddisk/harddisk_identify_device_data.h b/os/kernel/src/drivers/harddisk/harddisk_identify_device_data.h index 3538e839..202b5b77 100644 --- a/os/kernel/src/drivers/harddisk/harddisk_identify_device_data.h +++ b/os/kernel/src/drivers/harddisk/harddisk_identify_device_data.h @@ -990,7 +990,7 @@ typedef struct harddisk_identify_device_data_fields //! Signature uint8_t signature : 8; //! Checksum - uint8_t chacksum : 8; + uint8_t checksum : 8; } __attribute__((packed)) harddisk_identify_device_data_fields; From 60574dab7738c709948425148a7c79b13b731470 Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Thu, 22 Apr 2021 16:41:05 +0200 Subject: [PATCH 138/165] Count SERV bit as ok --- os/kernel/src/drivers/harddisk/ata/harddisk_ata.c | 2 +- os/kernel/src/drivers/harddisk/harddisk_header.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c index 8ae5ff78..47142181 100644 --- a/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c +++ b/os/kernel/src/drivers/harddisk/ata/harddisk_ata.c @@ -179,7 +179,7 @@ int8_t __harddisk_ata_poll(uint16_t port) for(;;) { result.value = io_in_byte(port); - if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1) + if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1 || result.fields.overlapped_mode_service_request == 1) { return 1; } diff --git a/os/kernel/src/drivers/harddisk/harddisk_header.h b/os/kernel/src/drivers/harddisk/harddisk_header.h index f069ab42..5e7f7bf1 100644 --- a/os/kernel/src/drivers/harddisk/harddisk_header.h +++ b/os/kernel/src/drivers/harddisk/harddisk_header.h @@ -61,7 +61,7 @@ void __harddisk_soft_reset_port(uint16_t control_port); //! Makes 400ns delay. /*! - Makes 400ns delay by checking drive status 4 times. User after switching type of drive in bus. + Makes 400ns delay by checking drive status 15 times. User after switching type of drive in bus. \param port Port for do delay. */ void __harddisk_400ns_delay(uint16_t port); From e5ad3079bef4fa03bf370c0f62367df5992ecb1b Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 8 Jun 2021 23:54:37 +0200 Subject: [PATCH 139/165] Fixes in v8086 --- os/kernel/src/drivers/vbe/vbe.c | 18 +++++++++- os/kernel/src/drivers/vbe/vbe.h | 3 +- os/kernel/src/kernel.c | 32 ++++++++++++++---- .../v8086/operations/arithmetic_operations.c | 4 +-- .../src/v8086/operations/misc_operations.c | 4 +-- .../v8086/operations/procedure_operations.c | 18 +++++++++- os/kernel/src/v8086/v8086.c | 24 +++++++++++++ os/kernel/src/v8086/v8086.h | 2 ++ resources/TC.com | Bin 0 -> 39070 bytes 9 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 resources/TC.com diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index eb4e8d84..4f825e19 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -203,7 +203,6 @@ void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t wi mem_buff[offset + 2] = r; } - VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number) { if(!initialized) return VBE_NO_INITAILIZED; @@ -255,7 +254,9 @@ VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t wi machine->regs.h.bh = 0x00; machine->regs.h.bl = window_number; machine->regs.x.dx = window_mem_number; + setSkipDebugging(false); int16_t status = v8086_call_int(machine, 0x10); + setSkipDebugging(true); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; @@ -622,4 +623,19 @@ VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, ui if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; *closest_pixel_clock = machine->regs.d.ecx; return VBE_OK; +} + +void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) +{ + uint32_t offset = (y * 3) * mode_width + (x * 3); + uint32_t position = offset / (granularity * 1024); + offset = offset - (granularity * 1024) * position; + if(position != currentBank) + { + VBEStatus status = VBE_display_window_control_set_16bit(0, position); + currentBank = position; + } + mem_buff[offset] = b; + mem_buff[offset + 1] = g; + mem_buff[offset + 2] = r; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vbe/vbe.h b/os/kernel/src/drivers/vbe/vbe.h index b3f33988..547c8f33 100644 --- a/os/kernel/src/drivers/vbe/vbe.h +++ b/os/kernel/src/drivers/vbe/vbe.h @@ -65,8 +65,6 @@ VBEStatus VBE_get_vesa_mode_information(svga_mode_information* infromation_struc VBEStatus VBE_destroy_svga_information(svga_information* svga_information_ptr); VBEStatus VBE_set_video_mode(uint16_t mode_number, bool clear_screen); VBEStatus VBE_get_current_video_mode(uint16_t* mode_number); -VBEStatus VBE_set_current_bank(uint32_t bank_number); -void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b); uint16_t VBE_get_word(uint32_t seg, uint32_t offset); uint32_t VBE_get_dword(uint32_t seg, uint32_t offset); VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number); @@ -97,4 +95,5 @@ VBEStatus VBE_set_during_vertical_retrace_palette_data_32bit(uint16_t index, uin VBEStatus VBE_get_protected_mode_interface(uint16_t* real_mode_table_segment, uint16_t* table_offset, uint16_t* table_length); VBEStatus VBE_get_set_pixel_clock(uint16_t pixel_clock, uint16_t mode_number, uint16_t* closest_pixel_clock); +void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b); #endif \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index a8554195..e2c9ff92 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -37,6 +37,7 @@ #include "terminal/terminal_manager.h" #include "cpu/cpuid/cpuid.h" #include "v8086/v8086.h" +#include "v8086/memory_operations.h" #include "drivers/vbe/vbe.h" #ifdef TEST_V8086 @@ -55,6 +56,8 @@ typedef struct _linesStruct char buff[50]; linesStruct ssBuffer[64]; +v8086* v8086_machine; + //! Prints processor details. /*! Used during boot to print informations about print processor. */ @@ -375,6 +378,12 @@ void turn_on_serial_debugging() breakpoint(); } +void v8086_BIOS_timer_interrupt() +{ + timer_interrupt(); + write_dword_to_pointer(v8086_machine->Memory, get_absolute_address(0x40, 0x6c), timer_get_system_clock()); +} + int kmain() { clear_bss(); @@ -418,7 +427,16 @@ int kmain() serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); - #define FUN_3 + v8086_machine = v8086_create_machine(); + v8086_set_386_instruction_set(v8086_machine); + //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); + vga_printstring("Starting DOS Program\n"); + int16_t stat = v8086_call_com_program(v8086_machine, "A:/TC.COM"); + vga_printstring("OUT\n"); + //memcpy((uint8_t*) 0xc0000000 + 0xb8000, v8086_machine->Memory + 0xb8000, 0xFFFF); + + + #define FUN_9 #ifdef FUN_1 mode13h_set_mode(); @@ -482,15 +500,15 @@ int kmain() } else{ physBufforAddress = mode_info.frame_buffor_phys_address; - if(mode_info.mode_height == 200 && mode_info.mode_width == 320 && mode_info.bits_per_pixel == 24) + /*if(mode_info.mode_height == 200 && mode_info.mode_width == 320 && mode_info.bits_per_pixel == 24) { mode_number = svga_info_ptr->mode_array[i]; max_width = mode_info.mode_width; max_height = mode_info.mode_height; max_bit_per_pixel = mode_info.bits_per_pixel; break; - } - /*if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) + }*/ + if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) { if(max_bit_per_pixel <= mode_info.bits_per_pixel){ mode_number = svga_info_ptr->mode_array[i]; @@ -498,7 +516,7 @@ int kmain() max_height = mode_info.mode_height; max_bit_per_pixel = mode_info.bits_per_pixel; } - }*/ + } } } vga_printstring("BEST MODE: "); @@ -538,7 +556,7 @@ int kmain() VBEStatus x = VBE_set_video_mode(0x10f, true); svga_mode_information mode_info; VBE_get_vesa_mode_information(&mode_info, 0x10f); - VBE_set_current_bank(0); + VBE_display_window_control_set_16bit(0, 0); for(int yy = 0; yy < 200; yy++) for(int xx = 0; xx < 320; xx++) VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); @@ -548,7 +566,7 @@ int kmain() #ifdef FUN_5 VBE_initialize(); VBEStatus x = VBE_set_video_mode(0x10f, true); - VBE_set_current_bank(0); + VBE_display_window_control_set_16bit(0, 0); drawLenaIn10fH(); #endif while (1); diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index bdcae0e0..979ae951 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -299,7 +299,7 @@ int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; imul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax), "=d"(machine->regs.x.dx) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { __asm__ __volatile__( @@ -316,7 +316,7 @@ int16_t perform_multiplication(v8086 *machine, void *source, uint8_t signed_mul, } else if (width == 16) { __asm__ __volatile__( "movw %%dx, %%ax; mul %%cx; pushfw; pop %%bx;" - : "=b" (temp_flags), "=a" (machine->regs.d.eax) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) + : "=b" (temp_flags), "=a" (machine->regs.w.ax), "=d"(machine->regs.x.dx) : "d" (machine->regs.w.ax), "c" (*((uint16_t *) source)) ); } else if (width == 32) { __asm__ __volatile__( diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index 830168ef..4853f16e 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -46,7 +46,7 @@ int16_t perform_group_5(v8086* machine) machine->IP.w.ip += machine->internal_state.IPOffset; push_word(machine, machine->IP.w.ip); if(width == 16) - machine->IP.w.ip += *((uint16_t*) dest); + machine->IP.w.ip = *((uint16_t*) dest); else return V8086_BAD_WIDTH; machine->internal_state.IPOffset = 0; return V8086_OK; @@ -60,7 +60,7 @@ int16_t perform_group_5(v8086* machine) return V8086_OK; case 4: //Near absolute indirect jmp if(width == 16) - machine->IP.w.ip += *((uint16_t*) dest); + machine->IP.w.ip = *((uint16_t*) dest); else return V8086_BAD_WIDTH; machine->internal_state.IPOffset = 0; return V8086_OK; diff --git a/os/kernel/src/v8086/operations/procedure_operations.c b/os/kernel/src/v8086/operations/procedure_operations.c index 2ddb8273..48ac87d6 100644 --- a/os/kernel/src/v8086/operations/procedure_operations.c +++ b/os/kernel/src/v8086/operations/procedure_operations.c @@ -1,6 +1,7 @@ #include #include #include "procedure_operations.h" +#include "../../drivers/vga/vga.h"" int16_t near_relative_call(v8086* machine) { @@ -78,12 +79,27 @@ int16_t far_ret_imm(v8086* machine) int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number) { + if(interrupt_number == 0x21 && machine->regs.h.ah == 0x4c){ +// vga_printstring("Wszedlem\n"); + machine->sregs.cs = 0x7c0; + machine->regs.w.sp = 0xFFFE - 6; + return far_ret(machine); + } + else if(interrupt_number == 0x21 && machine->regs.h.ah == 0x40 && machine->regs.x.bx == 1) + { + for(uint32_t i = 0; i < machine->regs.x.cx; i++) + { + vga_printchar(machine->Memory[get_absolute_address(machine->sregs.ds, machine->regs.x.dx + i)]); + } + machine->regs.x.ax = machine->regs.x.cx; + bit_clear(machine->regs.x.flags, 1u << CARRY_FLAG_BIT); + } int16_t newIP = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4)); int16_t newCS = read_word_from_pointer(machine->Memory, get_absolute_address(0, interrupt_number * 4 + 2)); push_word(machine, machine->regs.w.flags); push_word(machine, machine->sregs.cs); - push_word(machine, machine->IP.w.ip); + push_word(machine, machine->IP.w.ip + machine->internal_state.IPOffset); machine->IP.w.ip = newIP; machine->sregs.cs = newCS; diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index f5d818be..54c5240c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -636,4 +636,28 @@ int16_t parse_and_execute_instruction(v8086* machine) #endif #endif return status; +} + +int16_t v8086_call_com_program(v8086* machine, char* programPath) +{ + filesystem_file_info info; + filesystem_get_file_info(programPath, &info); + + uint8_t *buffer = machine->Memory + 0x7C00 + 0x100; //SEG 0x7C0, OFF: 0x100 + filesystem_read_file(programPath, buffer, 0, info.size); + + machine->sregs.cs = 0x7c0; + machine->sregs.ds = 0x7c0; + machine->sregs.es = 0x7c0; + machine->sregs.fs = 0x7c0; + machine->sregs.gs = 0x7c0; + machine->sregs.ss = 0x7c0; + machine->IP.w.ip = 0x100; + machine->regs.w.sp = 0xFFFE; + + push_word(machine, machine->regs.w.flags); + push_word(machine, 0xFFFF); + push_word(machine, 0xFFFF); + int16_t x = v8086_call_function(machine); + return x; } \ No newline at end of file diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 389b5e58..9929ac14 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -3,6 +3,7 @@ #include #include +#include "../cpu/timer/timer.h" #define bit_get(p,m) ((p) & (m)) #define bit_set(p,m) ((p) |= (m)) @@ -167,6 +168,7 @@ int16_t v8086_call_int(v8086* machine, int16_t num); void v8086_set_8086_instruction_set(v8086* machine); void v8086_set_386_instruction_set(v8086* machine); uint32_t v8086_get_address_of_int(v8086* machine, int16_t num); +int16_t v8086_call_com_program(v8086* machine, char* programPath); #ifdef DEBUG_V8086 void send_reg_32(uint32_t reg); diff --git a/resources/TC.com b/resources/TC.com new file mode 100644 index 0000000000000000000000000000000000000000..342531ef1b6f0eadd657640c99002718f73d478e GIT binary patch literal 39070 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 Date: Wed, 16 Jun 2021 01:31:39 +0200 Subject: [PATCH 140/165] Changes --- os/kernel/src/drivers/vbe/vbe.c | 12 +----------- os/kernel/src/kernel.c | 18 ++++++++++++++++++ .../v8086/operations/arithmetic_operations.c | 4 ++-- .../src/v8086/operations/jump_operations.c | 4 ++-- .../src/v8086/operations/stack_operations.c | 7 +++++-- .../src/v8086/operations/string_operations.c | 17 +++++++++++++---- os/kernel/src/v8086/v8086.c | 2 +- 7 files changed, 42 insertions(+), 22 deletions(-) diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 4f825e19..6f09f6ef 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -191,17 +191,7 @@ VBEStatus VBE_set_current_bank(uint32_t bank_number) return VBE_OK; } -void VBE_draw_pixel_8_8_8(uint32_t mode_width, uint32_t mode_height, uint32_t winsize, uint32_t granularity, uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) -{ - uint32_t offset = (y * 3) * mode_width + (x * 3); - //uint32_t position = (offset/(granularity * 1024)); - uint32_t position = (offset/(granularity*1024)) * (winsize/granularity); - offset = offset - (granularity * 1024) * position; - VBEStatus status = VBE_set_current_bank(position); - mem_buff[offset] = b; - mem_buff[offset + 1] = g; - mem_buff[offset + 2] = r; -} + VBEStatus VBE_return_save_restore_state_buffer_size(uint16_t requested_states, uint16_t* buffer_block_number) { diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index e2c9ff92..5c5ebb4a 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -429,12 +429,30 @@ int kmain() v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); + v8086_machine->regs.x.ax = 0x3; + int dupa = v8086_call_int(v8086_machine, 0x10); + + video_card_set_video_mode(0x3); + + uint8_t pre_com[1024]; + memcpy(pre_com, v8086_machine -> Memory, 1024); //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); vga_printstring("Starting DOS Program\n"); int16_t stat = v8086_call_com_program(v8086_machine, "A:/TC.COM"); vga_printstring("OUT\n"); + uint8_t post_com[1024]; + memcpy(post_com, v8086_machine -> Memory, 1024); //memcpy((uint8_t*) 0xc0000000 + 0xb8000, v8086_machine->Memory + 0xb8000, 0xFFFF); + for(int i =0; i<1024; i++){ + uint8_t tmp[100]; + if(post_com[i]!=pre_com[i]){ + vga_printstring("Roznica: "); + itoa(i, tmp, 10); + vga_printstring(tmp); + vga_newline(); + } + } #define FUN_9 diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 979ae951..e6979db4 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -455,7 +455,7 @@ int16_t perform_inc(v8086 *machine, void *dest, uint8_t width) { __asm__ __volatile__("incl %%eax; pushfw; pop %%bx;" : "=a" (*((uint32_t *) dest)), "=b" (temp_flags) : "a" (*((uint32_t *) dest))); else return V8086_BAD_WIDTH; bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); - bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + //bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); @@ -497,7 +497,7 @@ int16_t perform_dec(v8086 *machine, void *dest, uint8_t width) { __asm__ __volatile__("decl %%eax; pushfw; pop %%bx;" : "=a" (*((uint32_t *) dest)), "=b" (temp_flags) : "a" (*((uint32_t *) dest))); else return V8086_BAD_WIDTH; bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); - bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + //bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); diff --git a/os/kernel/src/v8086/operations/jump_operations.c b/os/kernel/src/v8086/operations/jump_operations.c index f8d5420f..92533336 100644 --- a/os/kernel/src/v8086/operations/jump_operations.c +++ b/os/kernel/src/v8086/operations/jump_operations.c @@ -86,7 +86,7 @@ int16_t jump_on_condition(v8086* machine, uint8_t opcode, uint8_t width) if(bit_get(machine->regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <regs.x.flags, 1u <Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); + int8_t imm = (int8_t)read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; - push_byte(machine, imm); + if (machine -> internal_state.operand_32_bit ) + push_dword(machine, imm); + else + push_word(machine, imm); return V8086_OK; } if(width == 16) diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index 305049c9..c220b26f 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -14,7 +14,7 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; - do{ + //do{ void* source = NULL; if(machine->internal_state.address_32_bit) source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.esi), width); @@ -42,7 +42,12 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; } - } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); + //} while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); + + if(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)) + { + machine->internal_state.IPOffset = 0; + } return V8086_OK; } @@ -56,7 +61,7 @@ uint16_t perform_stos(v8086* machine, uint8_t width) //if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; - do{ + //do{ if(machine->internal_state.address_32_bit) dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); else @@ -72,7 +77,11 @@ uint16_t perform_stos(v8086* machine, uint8_t width) machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); else machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); - } while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); + //} while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); + if(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)) + { + machine->internal_state.IPOffset = 0; + } return V8086_OK; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 54c5240c..1d61f44b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - //#define DEBUG_V8086_INTERACTIVE + #define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; From cfb289b3949218eebe238145188c8c75f08d3bff Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Thu, 17 Jun 2021 01:28:54 +0200 Subject: [PATCH 141/165] Debugged interrupt 10h ax=0x3 --- .../v8086/operations/arithmetic_operations.c | 2 +- .../src/v8086/operations/string_operations.c | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index e6979db4..3279d76c 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -276,7 +276,7 @@ int16_t perform_neg(v8086 *machine, void *source, uint8_t width) { else if (width == 16) __asm__ __volatile__("negw %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); else if (width == 32) - __asm__ __volatile__("negl %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) source)) : "a" (*((uint16_t *) source))); + __asm__ __volatile__("negl %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) source)) : "a" (*((uint32_t *) source))); else return V8086_BAD_WIDTH; bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index c220b26f..66b2d4f7 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -44,8 +44,9 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { } //} while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - if(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)) + if(machine->internal_state.rep_prefix == V8086_REP_REPE ) { + --(machine->regs.w.cx); machine->internal_state.IPOffset = 0; } @@ -58,15 +59,18 @@ uint16_t perform_stos(v8086* machine, uint8_t width) void* source; void* dest; if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything - if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; - //do{ - if(machine->internal_state.address_32_bit) + if(machine->internal_state.address_32_bit) dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); else dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); source = get_variable_length_register(machine, V8086_AL, width); + + //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; + + //do{ + if(source == NULL) return V8086_UNDEFINED_REGISTER; if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); @@ -77,10 +81,14 @@ uint16_t perform_stos(v8086* machine, uint8_t width) machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); else machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + //} while(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)); - if(machine->internal_state.rep_prefix == V8086_REP_REPE && --(machine->regs.w.cx)) + if(machine->internal_state.rep_prefix == V8086_REP_REPE) { - machine->internal_state.IPOffset = 0; + --(machine->regs.w.cx); + //if (machine->regs.w.cx != 0) + machine->internal_state.IPOffset = 0; } return V8086_OK; From 4acd3a64f25fbf266f4b1d6d6e924233b8ba9838 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 18 Jun 2021 01:42:01 +0200 Subject: [PATCH 142/165] corrections in string_operations --- os/kernel/src/kernel.c | 8 +- .../src/v8086/operations/string_operations.c | 113 +++++++++++++++++- os/kernel/src/v8086/v8086.c | 2 +- resources/TC.com | Bin 39070 -> 26818 bytes 4 files changed, 114 insertions(+), 9 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 5c5ebb4a..dbb1cf78 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -429,14 +429,14 @@ int kmain() v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); - v8086_machine->regs.x.ax = 0x3; - int dupa = v8086_call_int(v8086_machine, 0x10); + //v8086_machine->regs.x.ax = 0x3; + //int dupa = v8086_call_int(v8086_machine, 0x10); - video_card_set_video_mode(0x3); + //video_card_set_video_mode(0x3); uint8_t pre_com[1024]; memcpy(pre_com, v8086_machine -> Memory, 1024); - //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); + idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); vga_printstring("Starting DOS Program\n"); int16_t stat = v8086_call_com_program(v8086_machine, "A:/TC.COM"); vga_printstring("OUT\n"); diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index 66b2d4f7..d491a7be 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -11,7 +11,71 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { if(source_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; if(dest_segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; - //if repeat and number of repats == 0 -> dont copy anything + if(machine->internal_state.rep_prefix == V8086_REP_REPE) + { + while(machine->regs.x.cx) + { + void* source = NULL; + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.esi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + void* dest = NULL; + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(width == 8) + *((uint8_t*)dest) = *((uint8_t*) source); + else if(width == 16) + *((uint16_t*)dest) = *((uint16_t*) source); + else if(width == 32) + *((uint32_t*)dest) = *((uint32_t*) source); + else + return V8086_BAD_WIDTH; + int8_t offset = width / 8; + if(machine->internal_state.address_32_bit){ + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } + else { + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } + --(machine->regs.w.cx); + } + } + else{ + void* source = NULL; + if(machine->internal_state.address_32_bit) + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.d.esi), width); + else + source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.si), width); + void* dest = NULL; + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); + if(width == 8) + *((uint8_t*)dest) = *((uint8_t*) source); + else if(width == 16) + *((uint16_t*)dest) = *((uint16_t*) source); + else if(width == 32) + *((uint32_t*)dest) = *((uint32_t*) source); + else + return V8086_BAD_WIDTH; + int8_t offset = width / 8; + if(machine->internal_state.address_32_bit){ + machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } + else { + machine->regs.w.si += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -offset : offset; + } + } + + /*//if repeat and number of repats == 0 -> dont copy anything if(machine->internal_state.rep_prefix == V8086_REP_REPE && machine->regs.w.cx == 0) return V8086_OK; //do{ @@ -48,7 +112,7 @@ uint16_t perform_movs(v8086 *machine, uint8_t width) { { --(machine->regs.w.cx); machine->internal_state.IPOffset = 0; - } + }*/ return V8086_OK; } @@ -60,7 +124,48 @@ uint16_t perform_stos(v8086* machine, uint8_t width) void* dest; if(segment == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; - if(machine->internal_state.address_32_bit) + if(machine->internal_state.rep_prefix == V8086_REP_REPE) + { + while(machine->regs.x.cx) + { + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); + source = get_variable_length_register(machine, V8086_AL, width); + if(source == NULL) return V8086_UNDEFINED_REGISTER; + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return -1; + + if(machine->internal_state.address_32_bit) + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + else + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + + --(machine->regs.w.cx); + } + } + else{ + if(machine->internal_state.address_32_bit) + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); + else + dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); + source = get_variable_length_register(machine, V8086_AL, width); + if(source == NULL) return V8086_UNDEFINED_REGISTER; + if(width == 8) *((uint8_t*) dest) = *((uint8_t*) source); + else if(width == 16) *((uint16_t*) dest) = *((uint16_t*) source); + else if(width == 32) *((uint32_t*) dest) = *((uint32_t*) source); + else return -1; + + if(machine->internal_state.address_32_bit) + machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + else + machine->regs.w.di += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); + } + + /*if(machine->internal_state.address_32_bit) dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.d.edi), width); else dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*segment, machine->regs.w.di), width); @@ -89,7 +194,7 @@ uint16_t perform_stos(v8086* machine, uint8_t width) --(machine->regs.w.cx); //if (machine->regs.w.cx != 0) machine->internal_state.IPOffset = 0; - } + }*/ return V8086_OK; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 1d61f44b..54c5240c 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - #define DEBUG_V8086_INTERACTIVE + //#define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; diff --git a/resources/TC.com b/resources/TC.com index 342531ef1b6f0eadd657640c99002718f73d478e..a9f568021ed31c99037d1dfce7a8c469a30a950b 100644 GIT binary patch delta 18891 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 SAOa4Pz?LYJ?3OT-B$r71njK33 delta 31097 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 Date: Wed, 7 Jul 2021 01:54:23 +0200 Subject: [PATCH 143/165] PIC NOT WORKING --- os/kernel/src/cpu/pic/pic.c | 50 +++++++++++++++++++++++++++++++++---- os/kernel/src/kernel.c | 21 ++++++++++++---- os/kernel/src/v8086/v8086.c | 2 +- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/os/kernel/src/cpu/pic/pic.c b/os/kernel/src/cpu/pic/pic.c index 76a2e187..effdc524 100644 --- a/os/kernel/src/cpu/pic/pic.c +++ b/os/kernel/src/cpu/pic/pic.c @@ -1,4 +1,30 @@ #include "pic.h" +#include "../../drivers/vga/vga.h" + +void pic_wait_100_us() +{ + unsigned ticks = 0; + + unsigned int last_pit; + + io_out_byte(0x43, 0x0); + + last_pit = io_in_byte(0x40); // Low byte + last_pit |= io_in_byte(0x40)<<8; // High byte + + while(ticks < 1200) + { + unsigned int current_pit; + io_out_byte(0x43, 0x0); + current_pit = io_in_byte(0x40); // Low byte + current_pit |= io_in_byte(0x40)<<8; // High byte + if(current_pit != last_pit) + { + last_pit = current_pit; + ticks++; + } + } +} void pic_init() { @@ -12,30 +38,44 @@ void pic_remap(uint32_t master_offset, uint32_t slave_offset) { // Send initialization sequence to the master PIC and slave PIC io_out_byte(MASTER_PIC_COMMAND, 0x11); + pic_wait_100_us(); + io_out_byte(SLAVE_PIC_COMMAND, 0x11); + pic_wait_100_us(); // Set master PIC offset io_out_byte(MASTER_PIC_DATA, master_offset); + pic_wait_100_us(); // Set slave PIC offset io_out_byte(SLAVE_PIC_DATA, slave_offset); + pic_wait_100_us(); // Tell master PIC that there is a slave PIC on the IRQ2 (4 = 0100) io_out_byte(MASTER_PIC_DATA, 4); - + pic_wait_100_us(); // Tell slave PIC about his role io_out_byte(SLAVE_PIC_DATA, 2); + pic_wait_100_us(); // We are in 8086 mode - io_out_byte(MASTER_PIC_DATA, 0x05); + //TODO: Consider if should be like this: + //io_out_byte(MASTER_PIC_DATA, 0x05); + io_out_byte(MASTER_PIC_DATA, 0x01); + pic_wait_100_us(); io_out_byte(SLAVE_PIC_DATA, 0x01); + pic_wait_100_us(); - // Reset masks to the default values - io_out_byte(MASTER_PIC_DATA, 0xFF); - io_out_byte(SLAVE_PIC_DATA, 0xFF); + vga_printstring("PIC WAIT START\n"); + pic_wait_100_us(); + vga_printstring("PIC WAIT STOP\n"); + // Reset masks to the default values + io_out_byte(MASTER_PIC_DATA, 0x0); + io_out_byte(SLAVE_PIC_DATA, 0x0); // Enable interrupts io_enable_interrupts(); + while(1); } void pic_enable_irq(uint8_t interrupt_number) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index dbb1cf78..905d7cf9 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -233,18 +233,20 @@ void print_harddisks_status() void startup() { // Must be done before any VGA operation + + volatile uint8_t* scr_ptr = (uint8_t *)(VGA_MODE_03H_BASE_ADDR); + int i = 0; gdt_init(); paging_init(); - //Don't use VGA before calling VGA init vga_init(VGA_MODE_03H); logger_log_info("MicrOS is starting..."); logger_log_ok("BASIC TEXT VGA Driver"); - cpuid_init(); + logger_log_ok("Procesor"); print_processor_status(); - + //Loading Generic VGA Driver generic_vga_driver_init(); logger_log_ok("Loaded DAL, and Generic VGA Driver"); @@ -259,6 +261,8 @@ void startup() pic_init(); logger_log_ok("Programmable Interrupt Controller"); + //while(1); + idt_init(); logger_log_ok("Interrupt Descriptor Table"); @@ -434,7 +438,7 @@ int kmain() //video_card_set_video_mode(0x3); - uint8_t pre_com[1024]; + /*uint8_t pre_com[1024]; memcpy(pre_com, v8086_machine -> Memory, 1024); idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); vga_printstring("Starting DOS Program\n"); @@ -452,7 +456,14 @@ int kmain() vga_printstring(tmp); vga_newline(); } - } + }*/ + + + + vga_printchar('x'); + uint32_t s = timer_get_system_clock(); + while(timer_get_system_clock() - s < 10000); + vga_printchar('y'); #define FUN_9 diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 54c5240c..1d61f44b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - //#define DEBUG_V8086_INTERACTIVE + #define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; From 5d4a769315f793025d0ed20b4b6bdbad2366586b Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Wed, 7 Jul 2021 14:09:02 +0200 Subject: [PATCH 144/165] Fixed problem with bootloop caused by PIC --- os/kernel/src/cpu/idt/idt.c | 1 + os/kernel/src/cpu/pic/pic.c | 163 +++++++++++++++++++++++++++--------- os/kernel/src/kernel.c | 14 ++-- 3 files changed, 132 insertions(+), 46 deletions(-) diff --git a/os/kernel/src/cpu/idt/idt.c b/os/kernel/src/cpu/idt/idt.c index 2cd323bc..471db352 100644 --- a/os/kernel/src/cpu/idt/idt.c +++ b/os/kernel/src/cpu/idt/idt.c @@ -205,6 +205,7 @@ void idt_init() // Add system calls interrupt handler idt_attach_interrupt_handler(18, idt_syscalls_interrupt_handler); + io_enable_interrupts(); } void idt_set(uint8_t index, uint32_t (*handler)(interrupt_state *state), bool user_interrupt) diff --git a/os/kernel/src/cpu/pic/pic.c b/os/kernel/src/cpu/pic/pic.c index effdc524..06ae44dd 100644 --- a/os/kernel/src/cpu/pic/pic.c +++ b/os/kernel/src/cpu/pic/pic.c @@ -34,48 +34,133 @@ void pic_init() pic_remap(0x20, 0x28); } +//DEBUG ONLY FEATURE +//TODO: REWRITE THIS USING BETTER TIMING CALCS, USING PIT ISN'T THE BEST IDEA FOR THAT +void pic_delay(uint32_t us) +{ + unsigned ticks = 0; + + unsigned int last_pit; + + io_out_byte(0x43, 0x0); + + last_pit = io_in_byte(0x40); // Low byte + last_pit |= io_in_byte(0x40)<<8; // High byte + + while(ticks < 400) + { + unsigned int current_pit; + io_out_byte(0x43, 0x0); + current_pit = io_in_byte(0x40); // Low byte + current_pit |= io_in_byte(0x40)<<8; // High byte + if(current_pit != last_pit) + { + last_pit = current_pit; + ticks++; + } + } +} + +// For very old systems waiting some time between calls with sending bytes for PIC might be / is required +// (since PIC might be too slow to actually update anything with new bytes) +// To be safe this function will wait few microseconds after writing using PIT. +void pic_out_byte(uint16_t port, uint16_t val) +{ + //Write as usual + io_out_byte(port,val); + //Wait + //Since PIT runs at 1.193182 MHz this will wait 4 ticks, which corresponds to about 3.35 us + pic_delay(1000); +} + void pic_remap(uint32_t master_offset, uint32_t slave_offset) { - // Send initialization sequence to the master PIC and slave PIC - io_out_byte(MASTER_PIC_COMMAND, 0x11); - pic_wait_100_us(); - - io_out_byte(SLAVE_PIC_COMMAND, 0x11); - pic_wait_100_us(); - - // Set master PIC offset - io_out_byte(MASTER_PIC_DATA, master_offset); - pic_wait_100_us(); - - // Set slave PIC offset - io_out_byte(SLAVE_PIC_DATA, slave_offset); - pic_wait_100_us(); - - // Tell master PIC that there is a slave PIC on the IRQ2 (4 = 0100) - io_out_byte(MASTER_PIC_DATA, 4); - pic_wait_100_us(); - // Tell slave PIC about his role - io_out_byte(SLAVE_PIC_DATA, 2); - pic_wait_100_us(); - - // We are in 8086 mode - //TODO: Consider if should be like this: - //io_out_byte(MASTER_PIC_DATA, 0x05); - io_out_byte(MASTER_PIC_DATA, 0x01); - pic_wait_100_us(); - io_out_byte(SLAVE_PIC_DATA, 0x01); - pic_wait_100_us(); - - vga_printstring("PIC WAIT START\n"); - pic_wait_100_us(); - vga_printstring("PIC WAIT STOP\n"); - - // Reset masks to the default values - io_out_byte(MASTER_PIC_DATA, 0x0); - io_out_byte(SLAVE_PIC_DATA, 0x0); + // Proposition (Minus) + // Make PIC init code read current masking for both master and slave PIC units, and restore this mask AFTER init. + // Also make Micros old af hardware compatible, cause why not §(* ̄▽ ̄*)§ + + // Read current IRQ masks + uint8_t master_mask = io_in_byte(MASTER_PIC_DATA); + uint8_t slave_mask = io_in_byte(SLAVE_PIC_DATA); + + // First send INIT with ICW1 + ICW4 enabled + // By setting it, next 3 bytes sent to MASTER_PIC_DATA will be interpreted as proper values for init. (Read about small IBM fuckup in desing to understand why we send this) + // PS: Especially about offsets, really, IBM did fuck up there with great consequences. + pic_out_byte(MASTER_PIC_COMMAND, 0x11); + + // Send master unit offset + pic_out_byte(MASTER_PIC_DATA, master_offset); + + // Tell master unit that it is going to have SLAVE unit on IRQ2 (4 = 0100) + pic_out_byte(MASTER_PIC_DATA, 4); + + //Set master unit ICW4 mode to 8086, setting value 5 is incorrect, cause it seems there's no way to have 8086 mode with buffering enabled. + pic_out_byte(MASTER_PIC_DATA, 0x01); + + // Same stuff, but for Slave unit + // Also order of sending seems to not have any influence on actual data reading, but for ease of mind I made it in that order. + // Order of sent bytes for each PIC unit does matter tho, so make sure it is sent in correct order. + pic_out_byte(SLAVE_PIC_COMMAND, 0x11); + + // Send slave unit offset + pic_out_byte(SLAVE_PIC_DATA, slave_offset); + + // Tell slave unit it's identity (2 = 0010) + pic_out_byte(SLAVE_PIC_DATA, 2); + + //Set slave unit ICW4 mode to 8086. + pic_out_byte(SLAVE_PIC_DATA, 0x01); + + + // Now restore retrieved masks, also we don't care about these bytes timing cause, we're not sending anything after these. + io_out_byte(MASTER_PIC_DATA, master_mask); + io_out_byte(SLAVE_PIC_DATA, slave_mask); + + //Commented original code for easy copying, sorry if it's long (* ̄3 ̄)╭ + + // // Send initialization sequence to the master PIC and slave PIC + // io_out_byte(MASTER_PIC_COMMAND, 0x11); + // pic_wait_100_us(); + + // io_out_byte(SLAVE_PIC_COMMAND, 0x11); + // pic_wait_100_us(); + + // // Set master PIC offset + // io_out_byte(MASTER_PIC_DATA, master_offset); + // pic_wait_100_us(); + + // // Set slave PIC offset + // io_out_byte(SLAVE_PIC_DATA, slave_offset); + // pic_wait_100_us(); + + // // Tell master PIC that there is a slave PIC on the IRQ2 (4 = 0100) + // io_out_byte(MASTER_PIC_DATA, 4); + // pic_wait_100_us(); + // // Tell slave PIC about his role + // io_out_byte(SLAVE_PIC_DATA, 2); + // pic_wait_100_us(); + + // // We are in 8086 mode + // //TODO: Consider if should be like this: + // //io_out_byte(MASTER_PIC_DATA, 0x05); + // io_out_byte(MASTER_PIC_DATA, 0x01); + // pic_wait_100_us(); + // io_out_byte(SLAVE_PIC_DATA, 0x01); + // pic_wait_100_us(); + + // vga_printstring("PIC WAIT START\n"); + // pic_wait_100_us(); + // vga_printstring("PIC WAIT STOP\n"); + + // // Reset masks to the default values + // io_out_byte(MASTER_PIC_DATA, 0x0); + // io_out_byte(SLAVE_PIC_DATA, 0x0); + + + //while(1); // Enable interrupts - io_enable_interrupts(); - while(1); + //io_enable_interrupts(); + //while(1); } void pic_enable_irq(uint8_t interrupt_number) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 905d7cf9..dcb3ffd4 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -261,10 +261,10 @@ void startup() pic_init(); logger_log_ok("Programmable Interrupt Controller"); - //while(1); idt_init(); logger_log_ok("Interrupt Descriptor Table"); + timer_init(); logger_log_ok("Timer"); @@ -424,15 +424,15 @@ int kmain() switch_active_terminal(0); - //process_manager_run(); + process_manager_run(); keyboard_scan_ascii_pair kb; - vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); - while(!keyboard_get_key_from_buffer(&kb)); + //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); + //while(!keyboard_get_key_from_buffer(&kb)); - serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); +// serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); - v8086_machine = v8086_create_machine(); - v8086_set_386_instruction_set(v8086_machine); +// v8086_machine = v8086_create_machine(); + // v8086_set_386_instruction_set(v8086_machine); //v8086_machine->regs.x.ax = 0x3; //int dupa = v8086_call_int(v8086_machine, 0x10); From b0aed23ec3a7692ca24286e41b5362f73e61f89e Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Thu, 8 Jul 2021 16:37:56 +0200 Subject: [PATCH 145/165] Probably fixed issue with floppy drive causing PageFaults --- os/kernel/src/drivers/floppy/floppy.c | 22 +++++++--- os/kernel/src/filesystems/fat/fat.c | 21 ++++++++-- os/kernel/src/filesystems/fat/fat_header.h | 40 +++++++++---------- .../src/filesystems/partitions/partitions.c | 23 +++++++++-- os/kernel/src/kernel.c | 8 ++-- .../src/process/manager/process_manager.c | 1 + 6 files changed, 78 insertions(+), 37 deletions(-) diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index 759f68b1..24b8b93a 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -135,7 +135,7 @@ bool floppy_wait_until_ready() return true; } - sleep(1); + sleep(10); } return false; @@ -274,6 +274,12 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect { // Run floppy motor and wait some time floppy_enable_motor(); + //sleep(500); + + if(!read){ + vga_printstring("JASNA DUPA"); + while(1); + } for (int i = 0; i < 10; i++) { @@ -310,7 +316,8 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect uint8_t sectors_per_track = floppy_sectors_per_track; // Sectors per track - floppy_send_command(((sector + 1) >= sectors_per_track) ? sectors_per_track : (sector + 1)); + //floppy_send_command(((sector + 1) >= sectors_per_track) ? sectors_per_track : (sector + 1)); + floppy_send_command(sectors_per_track); // Length of gap (0x1B = floppy 3,5) floppy_send_command(0x1B); @@ -324,6 +331,8 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect return false; } + sleep(100); + // Read command status /*uint8_t st0 =*/ floppy_read_data(); uint8_t st1 = floppy_read_data(); @@ -387,11 +396,12 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect if (!floppy_calibrate()) { sleep(10); - } + - if (i + 1 == 10) - { - return false; + if (i + 1 == 10) + { + return false; + }else{break;} } } diff --git a/os/kernel/src/filesystems/fat/fat.c b/os/kernel/src/filesystems/fat/fat.c index ce6a5b4b..0619ee83 100644 --- a/os/kernel/src/filesystems/fat/fat.c +++ b/os/kernel/src/filesystems/fat/fat.c @@ -1,4 +1,6 @@ #include "fat.h" +#include "../../drivers/keyboard/keyboard.h" +#include "../../drivers/vga/vga.h" volatile partition *current_partition; @@ -62,14 +64,25 @@ void fat_save_fat() void fat_load_root() { - int root_first_sector = current_partition->header->reserved_sectors + current_partition->header->sectors_per_fat * current_partition->header->fat_count; - int root_clusters_count = current_partition->header->directory_entries * 32 / current_partition->header->bytes_per_sector; + int root_first_sector = current_partition->header->reserved_sectors + current_partition->header->sectors_per_fat * current_partition->header->fat_count;//19 + int root_clusters_count = current_partition->header->directory_entries * 32 / current_partition->header->bytes_per_sector;//14 for (int i = root_first_sector; i < root_first_sector + root_clusters_count; i++) { - uint16_t cluster_number = i + current_partition->first_sector; - uint32_t root_offset = (uint32_t)current_partition->root + (i - root_first_sector) * current_partition->header->bytes_per_sector; + uint16_t cluster_number = i + current_partition->first_sector;//19+ + uint32_t root_offset = (uint32_t)current_partition->root + (i - root_first_sector) * current_partition->header->bytes_per_sector;//0+ + //vga_printstring("Kolejne wykonanie wewnatrz fat_load_root()... Nacisnij ENTER"); + //keyboard_scan_ascii_pair kb; + /*while(!keyboard_get_key_from_buffer(&kb)); + char tmp[9]; + + itoa(cluster_number, tmp, 10); + vga_printstring(tmp); + vga_printchar(' '); + vga_newline(); +*/ + uint8_t *buffer = current_partition->read_from_device(current_partition->device_number, cluster_number); memcpy((void *)root_offset, buffer, current_partition->header->bytes_per_sector); } diff --git a/os/kernel/src/filesystems/fat/fat_header.h b/os/kernel/src/filesystems/fat/fat_header.h index 62bd4bbd..196e89d8 100644 --- a/os/kernel/src/filesystems/fat/fat_header.h +++ b/os/kernel/src/filesystems/fat/fat_header.h @@ -6,28 +6,28 @@ typedef struct fat_header { // Bios Parameter Block - uint32_t jump_signature : 24; - char oem_identifier[8]; - uint16_t bytes_per_sector; - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t fat_count; - uint16_t directory_entries; - uint16_t total_sectors; - uint8_t media_descriptor_type; - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t heads; - uint32_t hidden_sectors; - uint32_t large_sectors; + uint32_t jump_signature : 24;//0x9049eb + char oem_identifier[8];//MICROS + uint16_t bytes_per_sector;//512 + uint8_t sectors_per_cluster;//1 + uint16_t reserved_sectors;//1 + uint8_t fat_count;//2 + uint16_t directory_entries;//224 + uint16_t total_sectors;//2880 + uint8_t media_descriptor_type;//240 + uint16_t sectors_per_fat;//9 + uint16_t sectors_per_track;//18 + uint16_t heads;//2 + uint32_t hidden_sectors;//0 + uint32_t large_sectors;//0 // Extended Boot Record - uint8_t drive_number; - uint8_t flags; - uint8_t signature; - uint32_t volume_id; - char volume_label[11]; - char system_identifier[8]; + uint8_t drive_number;//0 + uint8_t flags;//0 + uint8_t signature;//41 + uint32_t volume_id;//0x12345678 + char volume_label[11];//SYSTEM PART + char system_identifier[8];//FAT 12 } __attribute__((packed)) fat_header; #endif \ No newline at end of file diff --git a/os/kernel/src/filesystems/partitions/partitions.c b/os/kernel/src/filesystems/partitions/partitions.c index b668d5b5..c9f9b9de 100644 --- a/os/kernel/src/filesystems/partitions/partitions.c +++ b/os/kernel/src/filesystems/partitions/partitions.c @@ -1,14 +1,16 @@ #include "partitions.h" +#include "../../drivers/vga/vga.h" +#include kvector partitions; void partitions_init() { partitions_init_floppy(); - - partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); - partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); - partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); + //Temporary commented + //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); + //partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); + //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); // partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_SECONDARY_BUS); } @@ -31,8 +33,21 @@ void partitions_init_floppy() floppy_partition->write_on_device = floppy_write_sector; floppy_partition->read_from_device = floppy_read_sector; floppy_partition->first_sector = 0; + memcpy(floppy_partition->header, floppy_do_operation_on_sector(0, 0, 1, true), 512); + char tmp[33]; + for(int i=0; i<62; i++){ + itoa(((uint8_t*)(floppy_partition->header))[i], tmp, 16); + vga_printstring(tmp); + vga_printchar(' '); + if ((i+1)%16==0) vga_newline(); + } + vga_newline(); + vga_printstring(floppy_partition->header->oem_identifier); + vga_newline(); + + //while(1); fat_generic_set_current_partition(floppy_partition); if (fat_init()) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index dcb3ffd4..1689e28c 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -282,19 +282,21 @@ void startup() harddisk_init(); logger_log_ok("Hard Disks"); print_harddisks_status(); - - partitions_init(); - logger_log_ok("Partitions"); keyboard_init(); logger_log_ok("Keyboard"); + partitions_init(); + logger_log_ok("Partitions"); + + timer_init(); logger_log_ok("Timer"); tss_init(); logger_log_ok("TSS"); + syscalls_manager_init(); logger_log_ok("Syscalls manager"); diff --git a/os/kernel/src/process/manager/process_manager.c b/os/kernel/src/process/manager/process_manager.c index cec45e61..6108b1f4 100644 --- a/os/kernel/src/process/manager/process_manager.c +++ b/os/kernel/src/process/manager/process_manager.c @@ -46,6 +46,7 @@ uint32_t process_manager_create_process(char *path, char *parameters, uint32_t p paging_table_entry *page_directory = paging_get_page_directory(); memcpy(process->page_directory, (void *)paging_get_kernel_page_directory(), 1024 * 4); + paging_set_page_directory(process->page_directory); filesystem_file_info process_file_info; From f6c648e28c7b2615e7fe49697150a6aa19687fa3 Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Thu, 8 Jul 2021 18:31:24 +0200 Subject: [PATCH 146/165] Trying to find problems in Floppy drivers --- os/kernel/src/filesystems/fat/fat.c | 5 +++++ os/kernel/src/kernel.c | 1 - resources/LENAD.bmp | Bin 192122 -> 0 bytes resources/lena.bmp | Bin 65146 -> 0 bytes 4 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 resources/LENAD.bmp delete mode 100644 resources/lena.bmp diff --git a/os/kernel/src/filesystems/fat/fat.c b/os/kernel/src/filesystems/fat/fat.c index 0619ee83..32f65f95 100644 --- a/os/kernel/src/filesystems/fat/fat.c +++ b/os/kernel/src/filesystems/fat/fat.c @@ -395,6 +395,11 @@ uint8_t *fat_read_file_from_cluster(uint16_t initial_cluster, uint16_t cluster_o for (int i = 0; i < current_partition->header->sectors_per_cluster; i++) { + keyboard_scan_ascii_pair kb; + vga_newline(); + vga_printstring("Loading files... Press any key to test next file"); + vga_newline(); + while(!keyboard_get_key_from_buffer(&kb)); uint8_t *read_data = current_partition->read_from_device(current_partition->device_number, cluster_to_read + i); memcpy(buffer_ptr, read_data, current_partition->header->bytes_per_sector); diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 1689e28c..e3e762d2 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -421,7 +421,6 @@ int kmain() attach_process_to_terminal(ts[i].terminal_id, process_manager_get_process(p)); } - vga_clear_screen(); switch_active_terminal(0); diff --git a/resources/LENAD.bmp b/resources/LENAD.bmp deleted file mode 100644 index 967ff071d4ddc63f655d0ea80df59c0b661bcbcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192122 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 z 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 RZfl*Zq%Z$)#Qn?s{{vS-m{kA( diff --git a/resources/lena.bmp b/resources/lena.bmp deleted file mode 100644 index c8ae0e6825c33e066286d18c5cf09637702c022d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65146 zcma%^y^kAdp5NPsp?09)vcs@jdjl9SHu6li@&VUHGMUKmNP?P0Dw*sy*k(&}nUg(O zd~Ho|x!6s1OTqmC-I{R1y+C`gv(5Ix{Tm#3{P}!;#g^7Ea4xcn#Ufc%&-eNMUY{2Z z|I2^--v?R#+rK+F_zipge{*o~PrUw{gMVKi{I7$9|L~t`<)9xN48M8$clF`_|MuVh zKfd~p9%J*5-OfMyX2g~QqtWQ#XV%fryt0l)KlA=)-t)@p@|S=4mj_>d`Q^b^Uww7( z`0?X|Z@&5F;M;G%J^1ds?+#wRe0lKqfB*Lf|L_n0aIo9$4u1Uc$Af?Rr++&5mw)+} z{N6MCe9&k8E$dILwe_7x{q&&E`dikYSiR=YKe7Inwa@ymeEeI^^xG}#Ppp4r{rTXJ ztUs}CS%2%gW&MfukE}nt{*m=3)-CIA54Nm7vHp?uXV*Wn{=~Xvr940X_&e4=u>Ohl z=Yv17{(<#(tUtQ`j`a_$e`4kQKmPnD)<3ZRj`hcb-?9FI^-runyZ(vw53IlY@!%y0 zygc|T*2k#teAV{KW#J!o0KWBoPjOV?kse#hE=3rDE`gTG+?lJ#rW z+WO9;etPg1tY5Nz&DwYUn)OT8zhM1WK8Dx*FMr9(xxakO+CO;A`Zen>S-*7sB`fFt z@-b`Q^)c($tiNRa^5B=OU$Z`D?Yll^{hIZctjJ9NE6)AZuUH$_{z1d~E7q@BzjEc= zU;T=;VdeZ^^&8e-v3||^73coy;8&~-Yu~kD{T1uiUmg5w%W}D#`k2nA)8+Ye#irly z53;P?wuAntZ3nCK>0&xxw5$2;-TZbjKby|a7H4~#BeX^O& zW=~o3x;fm;FON2x+1;G8FZt2kVmY0EnBH;G#o}(dxO0=o^n>@&ocGUJ``(H#O~1cl zw^`+-ziRvaUH`fr+>D3q;dnfryl2DGyX15(IZKMxP(BLfqaCdInU8kWt{NWQv%g$6 zt7WrmcDvQCSvSkoh%XOc{4gB;@M1W5F?=x@z8L;69$yUB=d0=B1Gng1uFjVYcfDk# z40mif%&qs={Z&CXxCoG|_HeMGfV25%dpEngJ)17(bFjMu!})wMyAvwmd-D1;Wy4#=lx|NCtyO?tpRSw`!y?7 z+YWle@$e|%wMUoS3+HBayKE>O=&|Wfo8@BKUJQbswa`5Z#O1OtluI!M#AUl&E(Sk{ z*@VXr!^wmyR)FjjRBoY!&!YU z&lYXF>aU^Kx?RG!{tmQ+tX)A#7`bHK?MACzyWNepEyzKwe6#pPn|6+C6mCS;A}S;7iv;-%qhe+Ad5iXDvWueR>PI3Cx{c8_7R zMd$}_08IeHyb0`sgYSpq!I)EUyAdWN1?Uz_uP7;U<5srt-AKI%aR2-M`N^UkuR(3Q zoX>AVy9G*68NLO+`R3{7>6N78GhQ~|vU%DAw)xrR;nSnp{Nvdjr30MskC%_7{!&;) zK;Yz`UqQ1#K)4nVg{*^;mzIYRwrezCI{?16cZuXGw5bJ3l8Tu^FR|kl1&E?*+wa9K zvbutYu4{yqgX>m(x@_SdbcBZOdMxvP2>rnEUYa3b0JO$GaH~^TA$rrhkJIyM|9t5^ zBfk+`wVylG_jz-9G;XKU(<{Ukf#Y7!pb#tszq5}|HrfxA-E4mOgzb~p8WTXAU-q6O z!*^I6@q-c69vE@iJ4{FAmtKAKPo-EuU*kd%_1mvLM53r9Nl_A=8 zaMAB;_C9i%>5@&*vusEX_l)@%^i_T!HxB>SgIE3Y#k?6kTFsjs0<6|U?Ad||;(Pmg z^Yrq$^eas`+x%CBxc7Y4JMBHYL@O3O=5wSfCU*&Z;xz}iDsD$W?*jDLpo^Cc3)065 ze5s&-)7xMcty^mqSrRp zLa8R)fna+90fp}e?5`jSp>Gl4!Fp|lVEr(H-hL27fS@+&k3|DgvO9FgL+8`^<>l$( zs=ueP041e2WIs-C-s)z%zcs6ZyS;D_U3%7IDOWAk9yDC$r7-C3-US(_CX@L8;^y z8-@a?qw2i^P^t(Xz+p#_1_ffN0t74&WDWaNgjit?o`c$5$j1f3<$|VpLuar6-Q-wtvlTxF-z};ca^%>6BoRQ-f~AYF_yR2OuEdEBaYx6tgJq;X@ zQ!Iws56%xVB8auD&xiv|phH1sk%@d|9RO(w#?0?dMQ09gxs=jRV2y4+7Z8SqkmHNnAd5F@Po z!avT%x${7gEHs8$eVlxoP=_|BUYk zbZ_H4zn(q4JZY{P{KeG~Mbb`p#iJ-7sSAqz&~gMW%m=S~{%L{5E#N7+N(E{e^a248 z!lUd{Xe^sfr4MT*+yhg!4J*+v_6V>23>gI`I0ylI9cBt{7$|&Ef#v<}n(bgL{~%x7 z7tAnExhN%NWsJ%2j>w5?DM>i})R#BCM*o4_h3ExAOAv{m7LgW0kBG}H>ThPs$v&RM1yQS(r6JK0<6rbq5eOfG`&ciaV=IJMPL1k9EjkaujT5=n0w31+N`>_sfNwTdp_mDz|4kI;%c zV&pakqy#ozAn4UQ_!p}@86FO&cOSf{37-bxHGjaO@qMEX>;kw46aoG%7brBzcOs`2 zxAG4qcs5(WJS7+}M*e9=n&yPK<79m_9+v#-W~i#dy)waJegT&)5R%lO4qYGi9|9mi zD!Oh#k)TT?fpMo((Ag8ko}j!)t|{ka6pDn3J`A^QmWksar|!E(^%Z*2fiO}uQH6Lg zoS1hw)4Of|JvfDa(oSE-l>@Abbo`m2dYxiGi4XYe!WZ$40U2PU^#e^7g?~#OKwTad z;edZL&BpEKZvhS;(8QlOZf2)^iRiZ>IWoDJ#(x2E{hqj;#B1S8%Bpgw$boRB-R(4= zA}oZVpT1v~M*E@olIS27Ba*o#g zfDsE55hjO)5gsVN(RXoTARop9`0!>rJV6rwMP1=V4S#W9Qp55tnlBt2P!RdII6dLE z5Z+RNsy@^Xb_4tXP`_F4Wj6co&u4hr&v`V*V?svK6_!oDSu~KO7JN!-uU+8rT9!lG z8}@;iDutW!w)n76gn?9Q8(=x^DL6e(HER`U9>)b4R{fE@oG!MIPBx(Zz%8tUcpR!X z$S`{fvL<-j?7&Zx0a|&2BwEhP1n#QsWZwYRo z12U28R`+>RIRz}Td1L}wejOjvI>{9*6ak#n!wV$i1pl@Q{hHql@K^wHk6VZ3Ht#zZ z#vu77ev7JZ&$#*{ABc}ts{*`;2dD^p(<=fvvVUNxuW)vGiBSMM z3@|wZNT<=zg0NscHYbb4Y_pg(&2hULyc@0nk8l|)tg^C*_|>Vk9O(GRQT;w~d&zyg z?8kwYeL>A5VIv!!okiBR5VLS<_(yR(ZRD5g@NO-a3|TDA*pM5Mas{4Sz`Tc2>UI1h zmo<=npjR=7YLB<-J&si@2cDKhFNvqJ69GZ7sP;@(voU1sza)ah{$8R0VTWRt=2%p?M3+->|`(;PO67bn#yP zFYfvFVRy9OJe>BYu_y>P5J5mr&FMAoqGsrJPMpu3t1{*d{KNhN&;>BUz=$yL8I|OT zP9-s>3M8Mu9%v*04P&vFVi~6Z>j=6#8KN+_6xjI^TTgw)eR&fF7(d49*Z*6Znmuot z#o26wTZaP!XwpyUaGrT(fBsDQ-H>K3+Qdu_qrP=tG`9crW{0N`7(5O-gbiiv=rn{wNppoX%G}ydEqFCK%b0dPtcV z3gP_&4-iif1=znJQy|{}FZqM_g(3%x-n1nkTku(3@(*o-lK|mhoy(gc+%`EuUMmE= z8gV~rz{LhLi~-hdX6Xz_cF9^jLkB*)Iz1tB9Uo&L2g5f5;Ff>}3F<*glw`A)20(N? z#Wns8{p4Qfz62g~8lu+#8cXvK+;~!#=2D=`N)MVV=uU)y=q2@^1taXVqVWHcSQ0pQ z1DPJpK-w97=((^HDjpk;j9`FK9NS z5u(kPmPqiFlqT}~Yy*?XyaYZ1U@&ueZSJp@)5}W=*gk4e@q=-@iV@a8>aL3!%FycL z22_h00q~J{D89leF4E01$>h;a6f*$s`V;~hXUEI=$XF?<%IwewuJumz_TkMQ@ zUFcSLcxL7n>orT_<3M6pi<+`l$cC1k-c!mP~@LB*Gk_*~7(>2nSFrw1r_E&lTu z?FZ2ZEoNhb7@z?K4{wyrl@ahAElK8_A>p^Z4mBk?pg!F^w`f=6L$hL-qZRz?=%;>1 z$>*w^x5O7wQ#wmX_xua-I8Edk)IhL`)5YPq;RiF-x>Ii~!V$Nv>TM#wuQrx89 z_moZQ`9udAjA%i^LCII%i*|iI03K|I96S<2_IxJ?c^gIe!wb&q#b_Zw1M0GSTS1Tu zbOm`plVsU`+X9#{}U4-_EDK!Ce_eMAJ35SVuy;fV{=TI_cG1urXf;EFFtdgBDb z!45j^LEEqP3r40q%z5`6o59Ogm0z&@XPTlw-RyJ-_n9UFi9o*veAxo%ZtO%kj*ggDZi;Fgp-t7 zDL=9Y#2+THl0GG*=7w7Hz)3~Y)(wv^n2q84bm8r z@r?}8`X<^wCCv5Tbts& zNGPZ|6g=WM{TlfPGn6g?(-D+}?Db3w@^(jVTJ+SYxH)7=C0&%B=xH*@A3(*x=MnP< z6oEoeQ(Ori?6_wxlIQ~q;w$Mt@_y(*@H2)ZpiSE^Aut|v4Dj2hrT3x*lg*;z0mVA+ zkAFeau{n4fKmm`!MRM=m41C`Y3ffBekYC-t&hg_w7KztjbzLzY+6}WA!4b(2e#ry$K%aG3Kf*0O&gUMBLm0*B$*JwEkFiKG9cqaKGe%cV7nTgfU z)98%)R|8TE|s^XwV>O7*Y1$t3X6p!7wxi-XDb!b1uSF3C03K5omLNllx!R@}mclai^stNHWUsMBf zR^_;8k?%$>;8tE+cq~Lzp5dA*PsJD9f}y(w zUs611H*A#w`M&jy)^^T<{664D(I;0h5LLK^j4Ys6+HXdugC}ocUcm=)GzCM)#ptS8 zj1I?#6RfXI%SU4~St@x!3kxNOg+;()d<71;_UN%YP#J=4B9n(NqXnr>t*}`0QCVSf z3FcrF)q>BqDt+i&;_i&_V@GAkKnbV^Eo#tDx5b=J*$%a$CK!a@gn)1@Do_S?;Hdy7 z?>Q`fYCj5u3PfLE&(Nc(qEdsBklK9-bV{xSTsD|ql77ivg@XFgC!1MmK2VHTNSBUg zbJ7DqdPdQ4sW~4Vt!?YkaD;qbn=7mTkTbrZ*vch^3Rhtk zUfY(iA1WR+Aim!{del+nPvsxH1V3CIglkp0kL?X6CAh^0-0uRZ>{||Kf=fG*!rIAi zIEWTR6+%Itlz|%$1=(ds18lv>K2dZLKEa*R;;+029{}3B1rFNk2AXO-fn#r;hV%K| zM^ifOVHkKp@mBq#_Jbu{^*_iI-Di+wiTpAaNvC?}>%0RmU$umYc5!dPtP-{lnm zv2iQ=l-x}}5^GC81Vv&%4?_~teOMY9$Iql+XoulthqK)He#h}NW70zbk84=+8yC8$ z7zqyfz)<;(g^%Xbx`IyKrB}(46siIYdPq2O1_KFz!HpDEQuz2UrVu*(X1{@qWTSg1 zbG)2pba}cw-L`a|iF1C44KDdLXD@IxR$zY#-C{rRP?BT;JSo;K1s89K1+kxbDjb{^ zFYtz*Y23F2)OP5XhH#dR*p1t^&gk*cETJFSIGENUXx`amBH)z`W;gHY4Fdx7pbUn| zoJv8PKYSkVF;x3$`tpJdfsZ^6d0Kz^tG=XeR z`xsj(Cgi&j{Y2MxQf$Zn18&GX;fn%HPBj%%>M!ndhhEfSa7?`hNB6LgExrHn|448f zqL&v)Pa?yQ+fsmVI~TBl{tm6S+Ue;eI8D?W6C(Y51Vi_C$UVguBbj@Q?3#Ot|6KgT0#45tr^@6>1Q+?m00SFMAea%M%R(r;IiYJ) z+y-pUa!cpBo5>LzK410PB~At^&_F*vw6bPT#&Tae;f=N{l_v-935Z^&>1aTRPC!F$ zRuqrMkcO{tV_ecS0_Qimjqp-9jn&;9RoCJwu1t>L+DQ^16Fq>^WOmUA-k@>FmO$jf zPN<5oN#}9^jd}$S>5T_?OdXlw)~?D!Tv#(25npW;{tGCEfAmMuRgi&Z05KBJs{mlL(oPc5{d~nAy zvqZo5TLT;V>CpiYQ_6=%!YjF#5aez-SAIJR0x3QU%0ivV3HS-BQ#TMka#{nBU2=bX zCdSBb@lOtdm>dK$;A2xENbE=KfoV6*1N>9OP!MWnk&}WfG+>Hdo=VyY4j@R`vri}R zHnJ;%1|j7BPNC(=;)JXbWWe=r>5zRi?h$OAFR#aI7>JmCsD3WcZ~o7?FWTO$Ffbs3 zNohc>ti}QaqX7#oDz_zp0)9ux?+%PXne*TTBEBExAO0-8HxMklRu6g&y)yWgx=9Dk zN1_l)40iHw)n3@2jR@Hc%zyx-v%r#2KSmVgUj*2V>@&3odX?exF07x=7Tsq&R+t(B z5($_6J)?yK_;6wFjR*RV=hI6WNo$*d6a9@AMbc7(|v#9|&K?K-);>1Fiz{=aeeO_&Oul0p-@DGZ) z$CI~9?XC~BAH0OD{T07E_9 zWt1P_2Qvc@clBk=#?r0Vo!wweCum}jU}(QJ2oV3#4&n$NxCxsw8|#tXP6r-KD(#ltGf;on z2yYMKp#V{SL~o3mc)(37z9gsf?PUXe25{)T4IPSPU$uY8NIK$c196Q91Ka90!bGnC z5(q~v7g+TVCxju1wTOlF)s)_8k^^!tKz10)s^EnT=&1>$OX`_V7{kyTQ(j1wFJeJF zF^M%Ye$dU_DJF{S^LoU{7<$F1|AZzUw0K>^m+)}J3n$!#gc6ZHy!y}`gi(MoAqp^P z>OyNWl-m$cFu4scP==$_APNKj59D|h|H!@TK@)}C&YpG|tk*`pbRV+s8YX#4z&=UuJoGrnu+^mitGk-ATZY3Z zINr;P;h}y0qItkD353M#{L&L6!$HtAs1};$9YG}jTm~2jkzF%aEN3df&FokM4F9mY zSWFzRTiV(&!)a_&&vAQFbV+%>YPWrNB?Pl+Z}^fOd+5))p5~*s5=huP6kpzA)nOLfJne} zc$Rt*-Hv!#kG$7^R(82oEHD(~7I6V#Ue^UC))$5IiGbP$F;n;56OeIREN`D{lc{`E zHF^gim0vs_V-Bqb-NOd&$A@Th1lKl9Lj|kOs>!A@1|S%{2M@R%7B@<7rS&5S?gBSD z5Z>@%X~1($usYBP}3}j2c+^H@zVFnto2>4nn{MTO`KI5%j6BfWH zXdh6Ii}orkyZdlUFXS6ThVcym<{%rxkH{|#9F=_mrOy{26rZR;ScdpwR+CWmi{W2& zCW`)s>?%O`2RqE~!1D&ZhUVq)5~5*1v^XHgv%}C!&>>&&?2v$=VNV6vB@s&h$+|c% zN&ijW z?q&bqss9jmoA!=yMIdK%C21HgqzTh~rrsH1r~3>hHa#z-2gn3FoaBt4aY%_e4;Cf> z-ij@!Bn4d|uv?((Sf?u(^NanJd4R_zWRLwQ=BfP5ACU5Si6uMH$<=|Ovw)^o0+O~m zquc#kQG|c5pB{Qp`L!#VRs;V58ZJUW(wnz;RypdY9bc^B25oV;fzl7`04DYq78R6e zy%Jo^A$*MQ!e?2$QNEA6U<^0rm|*9pm7$=zD3Rlq(HuI*TjUqP)-Mn!BM{B7q6Qtg ztymHH$BF}p%y&7!$Z$C==3n;lFA$n{CMJ-DHUNKsh};Q{1U8)CFB}5p#R&}{d=-he z7daO9S@nLIV>xI7+5E;)AmZnMAcJ3IXxm>SKn@1N*VDCF^aOA@+7kC$P&D8fSuV+4 z)Dy@c1fM$oAraiuj-xOvb|xqaw&MGUP@Yfu3>(Zb>X#E6!cjH|2oqyJ%$g~{5irpz z1Qp?H-XYYs#1Wgo%FvNS%~<)>fesNvJR~{Y05u}0Q}i0yKh$5Y#pPdNJ<4+-f|G=J zf99WU05ScCUyA(7KlGnQ<2M@!=<=jT>Pqj$xY&Co&p_iZ9wmOP&I|^HF69)HW-0{= zZsG>s@f8SIw1a{y0PJekP9dxBCPFAuLHQgUv@)z%p* zhYPI(g9KB$a89MCyz-ERpqOBUr0lL=1{nUabUt4P-cig5j!Oub{3!&)$$N;<#C!l< z(tm^>4+9?{BgD32n!!K0&l)7|y*2iY3y8uq{xH#;KBlBD`-rH$Bo%Cirs=6Ma(unz zJ4s)08^QtcIuZtsxD!BzW;14$HzFJK+=PF)(34+0I^@GJ(Bp8z%G3VJ4I??kx8<&N z2$s7h6f5kqg@>^wWCBGJI1yrPGNZT*fMK7CQ2m!YU}r->&}J_vZkVm6MPHzq5#LB} zwO(@5Nx&drqz{N?H_vtal5}}qyo)CM&!(MqVi=6(=vHLd9E?FV?dQh0y3BWXzej@f zp~sVVw1!|+2u`@TavALxjO3zZbCG=Y7$~3IARq}JYr^11WB6wTf(k@>`H;>C)|A34 zel)%{NThVvfLI%y3n+Y$F7ylel7Cs#5djql|FFQCj>1p~F}@|dwWZd%0`017}k}o6>{?=v@eLkfU8-n=-n#CpMK1ZXbG<*OG ztL6}~OKS*Tpe8K(PhbLzSg?e8YzO3*@=l{sUto)rH>40IzZf6dl|=#yd^!^e6;cIg zAMRi~cx;n*1Wd`r`|H>Z^xjTs2CHi*r`hGRZo@d%GQsa1^EOT-X98b02BkZkXyGMb zJs=?WRPpt_`JnfP@vlij#_`hwpGV~P@?>GNQNhUe?SDpo8TrAD8-MajKN(7d0w;fk zmrGfADnbL(WaHxrJrblO7)N{ynG#|!rV#xw4|&6BW4m7hbHtYpHtqNq6F?B~*c(4I zg`hm?x57il=aUiTo_NluRV@(X8us<=f)z`m2?4((|D>NduKIDI%LmkqMC*0(3xtL^ z^@z6)K~lL9U(Or)nLdz!h&qtbsbIdL1r9^&FgWb6p7ZR#CVtyEXu=F)u#RifNm7-r%p3)_bYa$1QIs~jlAyjKerLV3Ygc^|gkOHuFH0WXA2PW_FA7+}9l|IB7Qe)Nkm)C6M)SRZ2PxC+;W9_l}YchslLJ6sV!D`ZE>;{M^~ z=>>8%>@cB6be~s-eLft=(0MO_sNAwfh}qR=Q3HmA+Fu1&0~`iwKp5^H`9($1i_!%2 z$>wy#Of_VnPo6t*PA1)eg0G*LyGrmbe0drLb8fWuWs4x=T+!R=?rgfV=*M)8nb4&J zg&4&v9((#pI2JYmj)JHKc|<;7s$^AOb^l0V@ygpJKdCPuyCQ{I#FRllz6f?qlVY9j zI2RQAi~c+vu8- z1Bo|K-d~~w6LM-NHtcj60=~j`d|*DXACJsLV@sf5b;m+mE2+3ojadptBQ)0|4k^|u zdGOOFIg*BiGrR^l#ExCVl^_K1MRZGmO9$c({xGpYf?J0GvO^Xa{ziW3 zyxYeA143@qNRMakdfH$oHqYm0CvziUOs)aQ>@9;p5XM9wIIt)i@(43(CK15NvVVay zt-XMNYfiN8jSnA9u0JYjh(S&bd?66%iW0D-jJ_I)Bfd&@zN4e9`%DKza!n-i!zW zGXVQEFG>g-YpqNof}HFD*X|nZ4M7miUKjLwiI|LmS`Yn4O*kI{DxnydjtCw5>Lu8L z;30_Fv#c_W`he*d z`%F0$%iFdIK#^;NXh&Ilkg!n$62T+E zG$H|AGJ)6=c&JsuejvNR1|B{oqMas05AS(MA80fn;YZj0p}#5vp$-`YMVGb>+G+wI z_;CO_5_d3<6=s+uu){S`;kbBBiwflK6<@K{g<0BqHa@%nPwj8V?bH`Mqs(#-mOww- zCNvBke@V59tLsy}Kn0!I@&JC_Y0YeZ0M0jtGM7{_}n^c6{VL|5R$I zHEaPT?0U%aN}<3}|7A!071Vr{3V1{=@w$)h;yzJ;o$PbQM8M?Q(05=EHR5nnT3l9~ zoAbl~gVA+(h?U|r>vI15kRRERk}r@76}{wP;t6U>Y@GuU&@=ak8G(SxFIt+#0dV|? z*RKDI`Va5LZYDT^c+#K)avIz;1=DZsH3O(Y&$-nEuSVC9`!k@Uuc9496<)T4#{?mL za&fdjPTo7>FOaCa0s|XBi`Ys)ntvj`=(u|g7+D_?eLNZifcz^|i-5pq7aQc4>~l}^ z3jyV%{vh2P;hPX~X88^Cgv%pbHP_<3JoL&-`jSJuz&Gh^$$MJYf1v+?ZC^1C_RwG# z>ySy=3~0?>qjf{A@jOEWm(CW~@W=_&=*Kxm%+8ya<^6dJ6pqpunChB{BM*y~MoLo51r;Tfe#oy1u=HOD z2qz-GfJP9B{UG{PdEgY-|Jo3kaZy%D*AE&!2;FfEgQFjF10qUSIg!3Wge4tr3=4bk z5ds!;MMC+PC@TD`(dRO;4*`KrkiBai=#%H0=ck*|mGk?}=nP#-P&4uje^7?itcpo2 z{Pkwjn~_5>g#{4-5DwD7xS~H1B^$q|e=kYaF8uHsiZG#u$dzThh6HvK5Yxa!_Qi2D z=Pexz$sWicpygNjxp!#@XFo&uw`5>BX(roBvw?tE2JHecX_QbF*BT6-8We+&MpcNI z)81twn$8@+wO4*I9~1FQmlmBs6d;m}oADBJ!HGNnrQ$anKyHX7w@2L~z>LwqeD;h< z6X6>m!b6)cB^fy@$_N ze2+XrJUtdh!m;2}vvn?_yUYvYn~*Y{5^$;uLm-5rvn3#`Mi3AuaB`C_2%MU+m2%L~ zwk&WAAQ|FzB%=AKyA|k1_L=a5-f?`S{qVPZDkEYjpxoJF+wYBN%98qaI@GW*Jq-Oh zRe1_AaG~E!dE{3Yacc820;61qnSQzYv@0^N_OQDPHW1 zAozi}1Dwfb6$q%hDkky{y$76~|IF^HCI+mT7J*OG!87?(fCN5)BdwwW#DXXs<`3TC zzL0*Y0N8rv(@ZFb)=7@eGvmn6LS$b*>Exgq=ioqO1yrwaE_R|9*IEe%K5Cy=of@3z z{&~;f3jinU7}X*l+4vFB8n^%yS`99UWHlre!9W_2)t)rQi(r8l__jc% zWG%5JU`OTY227WoVk`S310A^qZn)F%P`ax@lmTu-a-tGxj=O+-$pj`MF8fQJnV90C z6KfCuWM2}2D8JSJnUDE!{}4WUmG07%X%K=BqX;_(0+e%_Xo34{N2nv!4(JEIkPqYt zPc*^=rWg$Jm`CmSX!1TM=U%`i!R!u5((zf328E>yNprV1LMH@8oY5tYPsB>6>k!{h zF`}$Ri+VzSZG98IRG;xUVbQ|y+vEVq75&(PsSY7%N_s(66H-!!&gn}7Fw?Op!8kK- z*qtOJz^RnqbY!CpWj|n^4z%hI2N2ly0_-_6k@%1_f*h zwNTn$SccHf&uslAdj)`+fxFJM= zfSm?p9!2gA@T$HfAp7_)a9HRt($a5j_=|zb7uoZ1(R^U|=#C))^v!M8ON2G-i^qcf zxaDp3Nh^TfljK=VXC*bm#xP0(Qc%#N4*`)J{VF*%H^DtAwQL2C17)tb+!|~Vb3e#e z+Lktev8iX#u!jUmq_6?m6?K`_YGhG=qbMpnAINWm{ZQ>8&2V1*ivey{CZ)+1L`b`45C|D3 znk*nr2+&3Mg`6$Y9Wf^FI-KDD$-^MxRl_|&GJJ~zDEq=c`@eKw;Kr+bPN#!-Y#9Zv z4?$;^WoE-dgmw3rnu9%ZG4RsST=*~uk~&ZM_5L%@Lr1`o`4c(;5y-s>1G53J+!P41 zOZyK()GinT>kFA!ool1k!Y5FXOm`vt(%h2~Fz@%LcqNZr^B z>=J09`Qp4VIiNxf5hWf3greALlp{Q0eqM6feolQ$K-m{+ss3;P-A8_tzDn~s>4OK{ zsiryK3xXC%2aD_oGI)tZdD6IA*$au-9c3P>D>>f%SlsNg)}11V5u;28T45 z;1z!cfCfa0bAd1q0t(=Yq5AZkPDgR&R^;LVD8;}|>j$?7dQ7x`+G~&enT-+PgoO|P zP=CrV3$>Rts?1k+iDA1MP_MuQViuLzahbNQQHe_B{bc_@@d? zRSP0_2mg>;XaBQpbl?8_Ieh*Mzmb}p&qqDRbsy3&ztW2aq|h$C@*}=(>=NBskErot zAp-}^Y>|aAH8m!cz);sWsy)xntAc26L%INu9x)RNy)=Z6c9P zCV(Tc0CvwDjSki1Us8g|6+{$6yq>%HmXYm8YtA795#j=gOW7U+iWK=|b9`!=j|NPJ zax)P^P(-MhWs_lCd}(`vf@9LR%h3+_i+@}I`$6hE=9e}yQ!jx|%d#h+WC{TTl*H<6 zF14d_)U6Rxbs;_|&M`SUMa?E4w0kA)P(Ynn&syuz{&sF0OI_Ag>dlm zHz+`VJUw@u7^9E%5*0e6!&uI+L<2$?g7Jla#v76_*vdUEh=}qJ4gD!e1XMCKK4h#q zcz9+P;iK3z;vPL3!NACtgZd9hi425wfeQWsrU4yLi5L6opeQ2VDeh*X4~gPP#Psw6 zCk$4Pd9wMjvzyb=h%n=dTC|44KVDRu`~aN^oj(H1>0&gpPXM+y>QDU#|CC)TLXD^t zd;R!MvWk;PG+>O3BBsbIeGXNFfe$$IS@91Uh%ZP=dt1%`N=9&a8sWkry=F~t+`kGx zlI7QR6|&DBQyRdAUWS%0pt&hDIYy$H>aPz(3P2z!xT> z0Ku-Cc}N&vfli7OP07~^zG5tI!EXpdadV(5V|=`M(lM_AkXf=|V(hPj{cS0s%K|V) z6Z#pYBNa_1j=^061O+gV-{H}PHHsC;*+LrriLE@~CG6`G{R2F=`~%Vu+ofTcpV8B+ z*ry3WX9yO#8!|=VAIPNvDQ)|>(4rw?QjiV#3?RM10g-UFjRa0D2gyOxs`o0;SX^}s zXdnU_+SlY??AgHbW-r3Ff8eY{Q3|sm<|hgoehi129ow&ouk2?U|2e6b!q09+IE3VA zfGkZQ(h_$Oar(etk0`-7;SfIjLy8C7%btJ&GN+HUjG~3GKu;K1) zF-e+VGN>0RL$foFRZa|;9A0oK8>AzPU?VP=PV@-=acZ=o&nf)t@oli@&o>0lUnrl* zDj~Wl3e$h$M;-8Ut*`kP2q=DrAklv+JCn~5SE;B!7+&hP$V5ap{L__2Yi2$f!4Lqs>}lISbtfkO@@TP#TNL~ zh?evNPT&@X-;8lcL%<_b`ZOA7-UUQ9X;iJmpvP@mvfWVxXv{s#}WT-H|wNOo21^4BYI zqLt$4A{&G67SwHXWGPgDjL1i=VTIGlg)4}gVFlj4cPRgC!Ie5P7VnckM=@bT^@1AC zg8%tJ1~pV{diaNsv3Mx~p`S*$k}z6Y^<6lJ^O8M}$v{Op;KD#GwIdr8Z`0B!u3hL? zNCXTUwP2Dk)M5h0yEOoI!dAXjpw-^}R{EjDxEAbYybS)C$!YTk3b1s;bAfa6PA#~g zlLtkhn+IaeUvll7Di9x#z#KeQG>Pz^XXw>wB9dyKB0>!WoPYo{+ z43ZcS21~4Fp~FUy%lK7jxavPhG^O$@Q=L>oBqb2;F{D%jM#^aP7-YnM)^L9xVm!>o z%o*GzUct(e76GC=SJ3-aA#$=h(w&ytnttcSeg zN3eRwy-1;Zz2=)Fph>CUn_sg0K@L92x7J!06FIIV1K&Xp?$)SzljAxhB$WUX0I5E)Bd}2g^|fU}7Qx^q;;TPv{4X4h7{!?EwLm_&^l?1wDn97IkTt>;aY+2vrwcv@9^h zWsjmuL0+H}+XmWD4V> zC6p238Bc5o?Ul`UXb!4L>)!Qz$NCR z30`eUD=5pbr^tkUTpQ1 z&nwq3jrG;;KBHq16fi!nR2DC0*uz0b`ZGNm@aViH+Ov?Z}%Ho4*A-U=1M(4o@T7v#&h9C=n7AI z7h*cNrMNDLE*fNu?FIrLsbL8ycql+A$fA4PCZ}kvmhnFmWI>9N`@U zoSi3mxwb17Wz7R!=~EgG1aBf`txMpu$%X&0()^-23_%2ujpl=Ye&YJvBb06w-H=Vn zp!p9^jbDj69Y&8p(x!kdI0T12Mmq{?qH?b2U&Ndy`YV6a4Op zKob#}m_>w{g9vLFhB1!`Ga)4O1wlI1-tiYo0*7g4!bs4KI@+3#;NsV4Y}6UfV7nVr zq83$c@svPBg6N=baM}hk&RfK1mN6N7G42<`+2!!1O^OCWC-@ zcRtWz^gf`y8u;jqZ?2B=`gtrcxOM39hc{SnZU~$>AtRRIUmD(Ep9+uT`Sb8(7q}12 zXcXX0!B^xHJZ>Y?!vLPfzLQyzEIoqISJMY*r09`H;8XhpfaqyjmjCm0b|ls9x`X%J7-!2of@V>5D& zFo;ny%*~@w{&Zf1QFa;rR`y{3y}j)X z6$KCGBK}2SQ?4?QP=JRK33gU{0aip#G7T zpykkw<`W74_k3_16GFo$K`=|u15Lh%+SOa)ymW8qi$1G?-uAxs)D4VX1zVpsus2_)(*J6hkq;=j*dCH_s*Iv8Sf{Z{91*AGDI z9z!dj8PKnWS1Lxo7mILC_+*&o?J{!_l@9Ox3-mLC5yry8M=-oy&{VhFiF;fxdDUyb z*wB3sO^Ct^^#GT8r=a8ZUA(`JdvSGwVVV^k0mr#jf61O2tzq(k@G}(c31|`~F$i42 zdFlG|0**S?log#06kSY=a;s>-ST>{|*OEzrEF^Gen5^3167)j7j(&Vj4h~zOfi9=V zUv`hYu&L+ytKmd0NNG%;cMcp?EpSF*Et3X*NfYaG}BgK(LX1?dBA~ zlGB0{*KrT5ee9&oCFyvi>ci^d{V}K=)VVO11@g@CAEn{PK-MAXKHm^fKc$G>qZ~SO09^x81#p%BBltif_@)?&h`+km zfA`o47=IiT!<6$@MhOFGBnMp4ezH%`g}wpc36x19(DCCf4NiB&&P0~U=~1HX=@qgI zLe5i+ht?oK1EpIHD0~KP_lpiRVx|70#&j{SM(q~gKiUF&1zzHa2@y|*JMWLrYYeV|R^CmD=;K=|t|FG`tN_Uzk7Ab4e>CwP(EaBA;+6FdgK z{Fcp%368RF8VQ9+Dn$C?LU6;-3+yZyLqa5=t!8Ek>587IV>H5yvgTJf(Z=h&(@SyE zlMa9uiXs{Uo39oS^%H)Gn?QchoS=`J9R?%>j9Upn zp<7V1>kG)L>-1*y0<)jPj=->}6-y{+(f=j8_TY#SCY}I*I4*p(IJf6uem>wI5`Yl@ z+0O@)7ye^HebrYx?_q`W=q!acL-iy_?7RvAQGHln-g5*;k1_VzKJIvPdIXH($KCV5 zHK+c=Khl1h7QDaDS$NUfUE50H{8J|H-o|}~cs9MI8U<2?SUOS(#s}n_aLu0hvd?;w zXYn%?*ua)Z*e^s2Qj_>i}U*2NZ-%dnuNKKuE?uiR-+Be#2s( z6(R*mB5>Q9VV-vcACyha2LQ709a$DM%$X)?eVJB>2C%Ozr_mvQYi~wyo;aQ0;^FIqBS{UC? z^zs&Ja?~%vL#fy)vkpR_z-H$8L92I<9clF+FLabK!=+pcAom6>ju`#Re6)la&@0-Ic!Yp0(nUEmnbqs# zT~L&RdVh(2>EC&_aN1h?6>-Y^*EW*Sp(p{P0MD5Jl9+;)-+Ho9cK-A!?ua zrlO9;fEP69#gx zq!Y?EYIy^g{KJu9K6A~BdOr-jV!D)3?{stZ#rPeQM+0DcXkpAt%SA@zQasZKLa3|F z9_a+-1wDI4!g9`ZHFOAc)&&f$8u9+IhmYf=@rglhAR+EDtEkn#w1Sjb{Z5Qgc%sRZ zz3SLOp%k#fps+B3aK9kK;OXB_qrJjZzii@JxPxQ&+d4eFizSdfn95O&DLnBfOIAS}+Az6u55;}y;K|vg2Ii-DB@v_d6%9^TxqdH{k54G%hZ+8V{C@|63}!YpdsN{;Eba+ z80SqD(=8|n1UNkSWPd?X{xScg4q&AKBd`I!zW-<2Y2SH06kw7GM!yDdAQ<^&kC{%X z@<3+v!H!SzT4&5k<_I}#irEoNGkTH)7(+LYHX{=Gz;+no2_LZG`}K;163<>Rr3_Jw z+!2?6e)9!$C0#L0!C*uiLQeXV1dFJnX}BmpG?~#NV8G+dV5iyxI|+!glkVz0z}*ut zCHo8j#()#9MSl0KZ@4dD0srJ3PzbaT=A~#W=+pq~w0Q-5;AaAw10u%i01lJ+(2rIO z=l>+@7q3tF?3LvkK(s_*3c;ySv4I`O@qx(}*t-oyi24hTj(Wp)?r}`9g_6}tA8BEl zz3Gxkx~BZ$F5w@QN5J7jp;n3mqC|`|8<{M(R5tyHnMejv4Fl17QFg+G+=?DX7wAxZ zyooOu>{Nik1O$j2`gnk!3$Wm5JM7bffhhFC!h(^H{YLkoBfi6%lp-K3>Y*>)<81&% z|3MFg)`6SqK_p1&g$6d5Q5-(?b9;U`so<$|=bL0k%TYFT-nF6&pwWU5Fj(?RKu2M4 zT$ZPtYjHKge_^H>0${EJdiH5UHzK()DLGOWMCC`wfyRsIhIkR&&Uk24v|e!lG%G-9 z)JM52x@3VtQ+& zN)+7`RTtjryd;lM%}O4}Fn0@fnI_0yZ-D=jC_{ld;+;v=wr2wquXxgt<9L7Q2qx&l ze;N7D56Gd7sx(VWZQ=Vwz;t2aMj)WA;Sf+)&-tVU3lMpUCWLL;T@%u_ZpcO-z$bK+ zl1*?B!FvN7A%>C0lR=sd&w{0XfW&Kb@?$8b?PYKx;;U|za#4dxqh`oDBmZ?{AYdkc zGWfM|bM`#lilPshzzyQbJ^z$>aXO!kdh|>{N{`5un#~V*z^C(qZ>Va7j2L0e3ceUQ zd;YqQ&IL%X1DEjF?92h%BE;!~FNUIr1WS3sOTb8enflRwh}$lj4hRFE8JD0|&>_;s zR$?cNd64{j(7At-?*UXKoC65xR}mav|AhAbXZ2(F_I>BR7=f5bjsqCig+#vi2_%(a zT3-p3fB?uIlbK_4E4ZW4HsTA0ub*v3&u6GH+SE-nYiC6b1I$w+0&Mmdgp_JQip1F$ z{sBAe8*P|cnzHl%&1>Q60OQ(ah3$)_KD3qi3ZD*TUCxSZ)9CtY4po<#otO~QsMz3q zB>6052Osh)|FUR%vm_Z>^b7my>wD<-zvPue%&U*_NWU%ApSIWk1QJG^MvaMo{258c zxh3yRQzp`@1$mD1B9NFCO(pjCjFikRQ~Q#ZSu8ieHfF3o{8JGs&41N6u-42P>9(SS4v$7TezG=p&2{O5`U%rvRtUgyF9S(q5?430xY zPMAJhytniUrkbiyRR3W=_UNG}QGd~Yj?OHg<={Q!`#t44zBA3)bU(LNJfprN21@K0 z@w(rI9YBSSlYkJf+TW06<^T+$a|h>Z>PFeAEyWs7xgMDWJ{ zGsDI+MX=qhmZz6jmkY*hI;Xf0(#PD`W|3LXp`fBm6FW>)6*Cx;6buSb)z(pupJ8rg zphmT{-NH?KX;G&Ux3^v=JMv8%rmnCNLrGILKXEF z73dpt(LUuO_m1Vz0d&Q2v2_GdHlTwXfGQP9%DmmYzTNcD?TnJmB7*vU#KXLjmFd}T zZsq`pZs@;6C)&`0(-vl%u*hA`My6^67Z}D$WM2?c5e)GZ!E~zs_ z*r~iYGZ3;BX1Q1Vj~l14I}tIb1Itcc&C5c$0yp0QChRAST50 zpItX%eW6_-l!D?$+?y8Rj)=DZ7JPdH0@X77x5G{-LONK5U4V zfro7&T3?>Ta7r~pJG(>a!vUuKYZ(ECY)XyAeYOdcr7$#{0|Wal@~wQo`?jRIe_)_j z25t<@mVCNE{7B4{Thcq6!z;l-0!^bh1(|kDT|KR?J_P#7u@1Z^D4D(W|8QU5F#`qv zEpoXdF|cZxwcN!Nj2V4+81(dOl;I_EcLq)dOV(AwFcHAK?!V-`% zU~P@`^t`gn;GI zMic>1JH-m;STQEaDoj6M_m?(aa*tdHbh?Z)I|dz~hXPbP%0%(yU=_W#VUb*W@aN4R zd-ny1B;Q_YwIhMB_{gra^Qfc?KKpzt?Vu-Ax~A#Fr}5nCbAa&DWfKL-e-wYA8U< zECZP(B{sw4l?u=Y{4?K!e-#ZVIIQB$jzV0h5uIG;GkqA@N2`+*34a2^%ZIuzG59bq z3Q!^uqT&3(x~MsMN5KFqvR8bk0IzR%Kgzs^eBlD|b$&d=SH5LHI<`Uy){F!&IhTiC3?mk!4kG`oi!na0_Y?l7Vrga3}Kn9}2$vL!2++8}b7t*zreIHBgRyle>C>c9lTO1XRnk@NbRhC(LQd zl&ZKfXLx@>%z0#-J4V^2^Cc~Ibi(|&!HO_au8TzqzSv!;H-68I@Q$BD1J;v?E$wnr zu4@cG>I`LhvBGJg3yf2uVvo(mK*?L;J{v;J)2rV0nNsBzsV&OkvtUOM>1!ogDWseQ zA=9cnM0KGkBD#vNOZhJl5D@FDPBORuNx_$fx6bY_D6Mjgf+b!XtVY)wj&P3odod|RxA8FClZMFhBmN;{ zLg#ZE9!z7%MGO|w&s=469ZE(O^I>uy4ai7tTo~EM?MXoOUOeZhKO|Wo#We?;0YK`a zu>wtmSX04Ba#73JOX=tEHx-C;Eb1(ZxQ+~aJUjUMQ`DdCOUy6b$iq27&UY18(A*)c z!stv@yb|o|Len~TmCoj7O|T`IaiT`9qXKDEPbv`o2LqX8e@5uL?&}CL=bfrgk<|+G zRE!1HNwHjbJsx8LRt^{dJXf?^izEFGGaL~n`xj%vTTQUi!6Tf*k;Y-_+-3}hsD^w= zNeFL8qmE2E&<~P-?o5d6Q=I`73z!wy_qY`edD~1M91ETyiDQi3n>F`yw2P;^dEM0RsR>?UqJnY>6E>T4*%Fp>v;D({ubPxHlXcxC|Z! z_mXYF5;odHxGm+FH#v7VcDJL=-|z=F8)uJ+N{m{>ln~Y8 zXW+ef|L_bXM9>%WgV>Mo&QGMD@YM^+6Q}r+DvU@HR8$~SNWni?m`px>7Uql`EdnC1 zcDwJmX7&#jUpW|GMh3Ps>>s#rv}TS|%_KuWO7=xM);wv>kcG#fv};F5SQ z{?UCEHvvPg^zw;F1vK9BhA7tK;E8fk12TuD)2b=TfH*xlo1ZeYtY!EJ;4%3L_Jvk( zf{FR!Quxm9wxbd07xHo@@cB2=A<0yvHqJ|IisF0Bkw?H64B4A7APs+1_!@c&apWdp zuf5o4M~D83Ga69sw@uX+b}&sg#(waM8NqphfNm(cNU*6K0{nYm`bEQ03z8Tlpx+*~ zj#nLcqKIl4^S>-C{!kB`U-@~Y)s3Nto_#QsgmkhulNw#!ENmy!466i}bNlSkao3U6 zj=*8G-l#WU+7|wNamvtj=6GS^duHn(9z*lVzF1&**g1ej!k{OVa1d)utLM(fP1V&F z<1^vks}g#MT>f0Zn8y?}(GEy<31sQ4s zat=oWK{+>PLw9@1OdAH}!Ku~d_X~D$bl4D{Fad3+{Xh@MSdQ>%@TS#-9rxtlBME57 zw4KtxCECf034drC3lc+uCrvui&RBfQd&6#^WMhBXT9Hb1e_$(cWV-y9u1i6fgsO}G zQW;dR2oi{AtcT+|`D3#|&ocSjjBPoBz|8(@PnccUOz`&-l@2^hFoR4T7T zBK>*$Q7CBmVdI5CkY6v>1#RBu1Z z!dD4z=*Ob`VmfF&uV7pP7JBz#0%ec79gi?qzAs~D-u9&Cj2{i$3YCT znotigZjA99Gox@uS=c8RGdW%%z&L^WfKregIQD&ks$pzV2qz6lXH<@fMmDjQ&AL3 zo*V;0ena8(3w9U?l^n2PTcU(`qubBdL@+P(?e$wbILJi8;h@O_=A#S`*@#`Sk6nXd z!eM@6{|tYJ4>P%`C>SGxFH@~@m|*Bn{lt+`dc%3D8r(#Y7cEI@Sje!f#ix3~^}W}A z;2|F=V&~!nCI29x>|?zEOd#YV z8qkBGTrIr!sOJpL`8uJm=~g=shJUFT5O-=E5R2ao*}#jNQ#10y^i!}A8E5)VS*V@$ z&Mcp8KlodjxYe6xp#VC~wb+$cAPwY(Q1Fe(1Q1L>QXq<+ULckj{3ef%^#K9AvhRFz z8`$t-GC4xR5IRmToE-}4BORd`7pA(bQfpS%nXR`ZZUPaT3d<;Wb^imlEMRFi#qa~# znWgCr2tQ(2QW4kRhkprJI0cnZ^-;19{|Z4FCvw{15D*(-Ud<_ZnRg64L55YsYZnu- zw5W=k%(Gd0Z70C=kO#dSr+0$mle&~N983~W8j5EgKv+QH@es(;L#@xWar}4H&fpgU zGMJ0MhofQL7$m*1R3~u(f?=or0vc6{VWwZgj)t<3ughME31u(jIt7UI0s^{E4?0MT zSz!+9djO~Mk6x3oH5~>;Q0h@5M%Wk*R^`?=(R@1L0S`3fCzc7dl3~Z50_Fvl*@Lqx`I=I<`jW6;|Hez$nJ(5k-eBf%?x|Yt3giUI4ihQhwPx5J+;*biMNcI? zckM(e6@7(_(9i`@C6y4F#reZ%l<2vGrS>m5w`=uK9muPz}xOeIha?&yik7@ADam((BaW=mZ*=5#Elj!7c;U zBhH2$nN>&n;9&Z~FjtH+ zjO^Zkvl$ji$c|5U5)T8bLxu&Ie@=gN2z2oP!A@re6fq%yiGJDP6>xWQPrm86aNn+S zkR7dWIM_iL?MM3V6Z?Qr)n9{u@4qTI0d>#D^YaY*Ao-B5htx46O0jH{f>O^$Bksx; z5vz8I?vsm|O+GiLiYrfr>{NJ%9U)5~@n9NT(CUn9_5t_^3`J8-X!3)Y%ha6GzGvQy6$wj-f0vcOKcr`j~t9*Z(d^rn?y z5A;mZYfDgd&c6Zq2-9F6{xW8R*CP*$CT}35wnS0Zgn*xaQ3MC`?06`UJd9FE38MZW z;M%S)JToU;><7NIX&5F4bb=TCm{3r$m4Tfodr-Nxm_q2oc1QdVCAVydBJ6*X+j0;o zuWxtI>`jEfr~d(8*6*{sA4l>{-odZ^MswDAg3S4|Lk;e@I|YHAYd{k?A|yz*28-$k zs>s?|gO8lmi=sm@kP${U3aiw_Y8-+ja@!uWkGP7kV5#-Q&4v+!;2cqS5#L{6fyp7H z3CRhjdDts@>a<8qfL10XWaEy|*9xy-D#qAk`#4hG5Xv3f&jVaCFyO&!=L+M&6efNz zKk0~A?;8i6@4w8Ua$QIj`Y}J`#VwHtSJtet7n>$jV8~6y54pjzDYkFwNFZgT2dvZZ z;-iFdgCopA9sM!T?skf3Y_qF~1f6q5u=CsQ1*FpFP}# zVWf|e>+)^5#}|X1+K;D|WMVCjpteIcLOg&|GIrjlKC|hSI41fh5Rwct#}4)WZX_w} zbL0_PkH0=ryRjo`tcB_Eu`<-gg$7o>ljIBN)gw6Sx*)#rZ=4Kj2OY{UCRihk2|;>6 zkV*MeceKfbc_E<$)PAJwY&zE%VNK^-NmvRn7FFiiiHVncu6{;a&eDLNquvaPb+k6&J!z8M(cyN52E4T7AL1uQYT34gKt z5)jMF3-F0uY({W{cpTHu6TG7V00<#;Du9eUf?fw(5XnArDyuAkEB(z|m}g%%+k$=g z-E5?!`cDH~N$4m+n}UVU7Z6lgqhbIJ%-9Wf)-!@50r$Er_E#Lz^`g{Yrvy`QnU_^M ziMJ|nk6#Sz`RaS-jZjy@=so%TMn^mj^V?Jv+L*tbg8ZmM|I-Scr;mbZjpcQKFSf$g zAuvlY5r?I$sf?p{Zd6_2XIg&07tut02SNY&Y9w&FD*@1t%N|F3ZIfed=@Np)z=lNi z=|?9RQ3u*kXH^@ehjyX{jz|y$WMWZDnBqo`d4uY$39z)lc!Jys?Z5cX$sc^iypFa0 zBqt#PnGE@>IKINTg*tY>1v>V%A$Bt$_T?tLAskZv<}VAKdI0gL{Jy}6=Z|3PrZCh< z^z>bnVM5r7H12Wh5PZbH!9hR8CL)YHtb$-=3ur`#dwU-c9>##YAOcbA*#Ke_u*}mO z^A`xDwHjd=Z-AojLf)a#EuzrUG~~Hqdr)JWBH{$`qqj ze}VD3g2iP(mi5^Am&jg1o9SrPnLm+)MVE^^&;6^>tptK9CMLTrD%)6t!B9-sWiQMi zPzDWX(I`9*eu4M#PS@Rg?NW|`-q!;L`rpgA=6Bq`E^?m-NQ{pG5y&6)pvZho1qubq z2InTAAxz2v7dx2y*KE&uQ7`a5*Lz*Xx7m)P0pI@9$W-pbiM|(*2RKMR50g+4Tzhw+ z4(#B?&x|lZKXE`Pu2V-z&2U%U%az1<8dGiI_m7h z{oVU&fU()5V#;KBun5$8VfW2}Y zlwx9Y5peO-%Y_cgL%&-9VSbG8Rs73${$2ui0e%qN-0aOyInWiG!y8x`oRHs+nT@=_ zf-&2}Y}7nnNNDDxni#+mv`R{0S$1qpoahBrC?cVJ*`2Lf;)HqJyWqROe*wNJzlm@J zloFi)-jQrlpE_~u<;2%GH{avqlfBf=i3Q!QA>`nu+A=;!=8q9)3LeR}|2Bj6- zTv?YNQ>NQJcGAmqU3p+@1EB)o0EXO+f0m*2mudAkV%_aXd62#%FwTvFp$Od6viDew zs=7dQU7j5&#=dpTNtWmQDI!mF%ad7zVVSf1kAqzzIr#25!}sojnezuu;0*AO_g{YpnUD*QB_1}oA7xmPCLHzdv{L6MDUE~#xT{+O;S^h- z^i1L5?OptXU?ybcmyXnb#CK$#QM(xC@1F}nXMoQexy}IR06Unuwf+5P1xa&SN=B9< z#h1sIvwQ+9K`GmTiQxvh&2GvL5I8kIuC-A4_~ADNIPzIdDIrt$((w1sUtT)pBeu6l z35Gc=DZu;3>Q$%wMm}?0!(~E3Qw^|cd&R#jFL}v~@CMmg1NR=P3>mZ7)bP^*2a5e5 z`X9`%u7l?6ou+s|3#rthPe+4^}Fn6ID+6%4@zobsz|-Ix zgs*@6mk+;{0Z!!|yPE@8fl@5gQIdfQAKvkyYg!#Rj~%lFzZjeglDsl6a9 zM_Vkp_S1C%eL651YDwb_zQd`T0eP0|3*L)^&rCdL%Zl_O5soiFl9eoit_*MSDo%5K zMGQ9`Z_L_0V|TeRtVQ?@!q-&U-C;noEB{f_(>{WYkm2ExVU#oEXsnB`E%EP#PD5+_ zu|hbYHED`mVW!IEI#V%Ffb1Fy*6FDv>mz1f>)Yr4|58Z6i9PDBjD3SpQW9ylpzjC> zGT)sWPS03bQwNpDWd%|l@EzAITRF_7k|f1bIcu>EY7c0#t5bIzK%GfOH3~1wJK2Tu zn3tcD;yd<(7y|7e7$grrrEw*hnU8-&tozX2)sOt+&re26R}Zyp-349vy?&)yI{sZ8 zM7TsbTarnJI~zO~x)T0a*IW0?o*ez>Sz}TF0qZb-7?R*zfgo!@E3fy6E-QLL7g7P^ zC!|aPF2UQkovk@11~yfd$g0n_DVA>;jSob@rzpXcGY zJIqTE1yUgSs5W;JG!0ly<%@ug=(vh%fB##^*Zfe89;(3@dsHp#i4*jU2#B zJ+}WZICh!p?Y5*s!p|9O8%q{OFhj(|cX*u^(OHc5@~=nr6|I`qI~+v3nULu*Zpi(^ zW5G-coYc_bBj8@IUf-%=9|eC4xw{Xq?qXu(L)%Yf-{8A$-GR0!Lb|Z8$SQD)A*lb# zWe7JJ#FA}wjS@hx#zooT9&&e2|D{N1L-A*a8WwCq{*0RceP>@#sYFSB4{(t3ER*5n zw!-r;OSIUMZINGvBGMBD#oDE(|^kI(iCY zz-^ZJx~)b!6UsRC=~c!z`De5Jjrt3`f(0Bu=v}f4x)HE4IXkQW5QJqt-YKjedd2U1 z+O$ShINYAPTecT+=??*A3v6pZx)_?6`iCcHO#AOat9{XM1l)niSr@Oh!`Iu6)`6Y(+wz za}}icAD_z3!LWdWTuD{1qF4gF>@R_BZQ$`<@??HD3_%fuJZ5Q2dSTc?Yn(mp24C=$ z>R+Y70&Y&s7+7$0XQAmV+<+T&2~02@sC0p#JP88d`q($^iRQTHyZv zm3G3!m(Qo`GD4fuOKO{g^@IZJ6Xk0jpmEs>msLH4W?1= z#noU7w5FCYQzCis?}F%^VHXFigOLFPHXqZR47^xa=_N)|eqDiLLAd&~`bZHb!~e~Y zygK3wL0PqGo@G7u(1(XXm^CN}kRf=bhu`y(W;SSXB=1GJ17sm_4O{VOn6DGnD!b?u zUA;ppAqH9yh9X3>Bf*$y7KkYqmlVIu04K#y?|u!r8pa&+aH-z`7Xx*qxFkr#8GXUo z#5ZgXA;;Lb=exb1-_`S^(*|-!c5LEncX+ajPvRLX3=US0*O)0ne}zcarArjd1g8Rr zUdSEvAP7U#a$gZB`k7unP|#kP3rh1KY^4_{(FclJ>|=rMNNEh_ik)_1Lta7ci0|kZ zXmK$F&u)R3PhV>ovO>ebSJ<-p;~sL)84cYo2jv${0gVI|g=`*5fyanHntFT`?-gcVU7UUu zAi^$Bgh~C11A7opkmP2kDrecN<(dp3Vdb1xJEwoQbgH3hlGsDQMV{+#aVU<8(NoJt z@W}}`%ZUNsmv_h6Ah?GyiCh{m21b-|u>0w}Qx^ym@Zbvz{~2lrs*>r;dtCwg06RPE zYs>8I=cjovGQkX4+v0x|N+nzdb4I|7M%H4n7AwU~=k#qh63+ZazqD5Yt0Y*Aehz}P zg`NRi_6*^3y#Jy1_=k*$G%KU{uV~@e#-^0cNog97=NC!Uz{-FipFJem);dX*-uF** z_qyk0L*V9180+07c)BFi7?^tDs4C>z|6< z3`dcKiuW@nIaUhkirdT1aW3@3L>1PpRYh&Qmr5+yio`b5Qha8uumt%acTWWK2$I(l z{igj$rwwmDE;VStG}Ly2Z=tzPrO1=iu!3I1LqgyU!IKm2AQkw8e_xH~N^`P#U*vyp zs;rt)Q%7z-;t4glbQ;))YRS!xaDLFdBsnrZPgW#1g^ZkMqtx5i)Zb2hrfJ~;H#1`I z(THyziYl)e$5i1A$YulXPC@uVZ-JA8-q<(SIRn>C5A~=v7hme7ws!g{GS5)LIwc1F z3_>^W+}xDuz`8V!dI&h?9Yt98Cfa^}eN)XB|6w|4Km6mx9W1U~$RQxy7C#6|%`c1l zDF9hN0>jRoO#?4rE(uLkOcj?L`Q2Gtk9VfhUki^HgAR7fwuR5#5Hp&Lw;MX)x zFR3c!v%!K{iz0|0)S9ygEJIQE#YX{x&A&O>zRAE2Wk2>A|LjkKBN@(7e1~>newbGe<^nM?!toD=C008USOlF5 zw|1_7gf{_x)_(5~Denb7z&6axg?GP(ykQoP|T*^E>7 zCE{VL6USOWwx<-B9pTv-+aa|PILw-ni4 zlAHYI@lATmtG z0WCZ-cxT$e?7Z-no+NP%!AbCB*MG{t#knD9tX`Ar+N1F3L5zJ^YJ{ z?Ku5y&zGrpq{rW;16dFf{LfWwx$0GgApJ+<5#0;DxX7MnJ$Rn8)qx!@H{=dhl5%)9 z3`d0Pgc(KaZ=hWP$U$>*oE!vXooU3y{QCDltOnraH&5BI7YT1D^8fN!IrfcPsqZ8+Pu%i-;xZlHFEp4Y~7L+Zb1S>k%*1M@l}- zljjhAY^N6J5%A=U3gyegeS0ICFSB-|ANcU@sKDhqmgoKW;$i4XP{ywp+^y%pZr1a; z#m|rR8k_gJ;FepnyPetbatM2Du@vx~C=BJd0D?WxOc!zpE#*rXk%!;>Q(4@T*eG_f z>U(_=tI=mp1n}s`P-!cRiUgohp&VA z&ra;TAS}u49w057`fmJcfOx-Wr_+vG>*1D%8=%Jt9FpM69aXxp*zV#kvb~(shYt#C z(|DKRCBFBJ??}1GvGTS+BcS_QJhTvLE1;w&) z({y3hR6H7(E7Ht`p#kMX9^ZeJT%9Oh?5cB@Na&fLi{EZ2*8Ibp!J&llB5L5YvA=}K z0StUM_8s^-PDl@C;PbfA5#KB@4|r`XFfKtp4O%M#*tl9{h!5@Z1|waOcM1?8nGO-Z z-2S7MuerPW47;0Hx{r6C=e%Pb47Hp1LZDTwjFH)yo86cOgkGLc1(`_MxSeJy_DXzj z0J(bLF)&{3%3bT^-)@c)#a{#dY(|iUBXRIOBrIt`bbgXK9&G2?1^LJJ!ue8#mi(7x zLa^_#4r>^bFYmwAA;gt~qYA%Kg5h>xG;cN2Yu}59$oD)Y9^E*GMZIPrl>k)wV8!h@ z)IB4W*P}aX5n20~|7^%EfE96xf%up^m_yir&j2LbX~N1wmhXs%%TEH6LrVKq zZnSPqSMT-*@#scDABX`N|B6>BF1k1Rnk$!d1SiR*%eqfY@>oZ;seka8@312f>@W>D z+~VHsaZXIIe}1EoE~F;901Ljfp~(MqU<~9%9|m@jK<^E4@aE2SMIR96!hjM%>x&7z z(}2=AaqL~6B!A~!HQBn_5#od0ISpz@au5B=f|PBun*<*-TwojlFYs3S3%UQTSUqQ^ zFhSVO0mMH&L6FItMoAm$?*w$~NpW!mcqs~*13l^; z0#-^As-l3wzw50~JZbt*Z~9MJ>i zK!{Mus{2!urQpEi=t>nm+UG$X-1B8TtziD|lh{GEJV<6F35I3jOC64t`c@T%-aELx zqM^`TKwg3PC From be9e0d58ce31aa5b63d7d5767637073848603ff0 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 8 Jul 2021 19:54:47 +0200 Subject: [PATCH 147/165] Floppy Works! --- os/kernel/src/cpu/panic/panic_screen.c | 16 ++++++------- os/kernel/src/drivers/floppy/floppy.c | 33 ++++++++++++++++++++------ os/kernel/src/filesystems/fat/fat.c | 5 +++- os/kernel/src/kernel.c | 4 ---- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/os/kernel/src/cpu/panic/panic_screen.c b/os/kernel/src/cpu/panic/panic_screen.c index 0eeac59a..b6a47cc1 100644 --- a/os/kernel/src/cpu/panic/panic_screen.c +++ b/os/kernel/src/cpu/panic/panic_screen.c @@ -46,14 +46,14 @@ void panic_screen_display_intro(exception_state *state, uint32_t code, const cha char buff[100]; //if(vga_gmode_get_mode() != 0x3) // set3Hvideo_mode(); - if(!video_card_is_text_mode()) - video_card_set_video_mode(0x3); - vga_clear_screen(); - for (int i = 0; i < 20; i++) - { - vga_printstring(img[i]); - vga_printchar('\n'); - } + //if(!video_card_is_text_mode()) + // video_card_set_video_mode(0x3); + //vga_clear_screen(); + //for (int i = 0; i < 20; i++) + //{ + // vga_printstring(img[i]); + // vga_printchar('\n'); + //} vga_printstring("Robimy to z bolem serca, ale musimy Ciebie o tym poinformowac... Zjebalo sie.\n"); vga_printstring(panic_screen_value_to_string(buff, code)); vga_printchar(' '); diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index 24b8b93a..21c73634 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -1,4 +1,5 @@ #include "floppy.h" +#include "../../debug_helpers/library/kernel_stdio.h" volatile uint32_t floppy_sectors_per_track; volatile uint32_t time_of_last_activity = 0; @@ -256,8 +257,11 @@ void floppy_disable_motor() uint8_t *floppy_read_sector(int device_number, int sector) { uint8_t head, track, true_sector; + //uint8_t x[80]; floppy_lba_to_chs(sector, &head, &track, &true_sector); - + /*kernel_sprintf(x, "%d, %d, %d", track, head, true_sector); + vga_printstring(x); + vga_newline();*/ return floppy_do_operation_on_sector(head, track, true_sector, true); } @@ -288,6 +292,7 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect if (!floppy_seek(track, head)) { + logger_log_warning("[FLOPPY] SEEK failed"); sleep(10); continue; } @@ -396,19 +401,19 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect if (!floppy_calibrate()) { sleep(10); - + logger_log_warning("[FLOPPY] Calibration failed"); if (i + 1 == 10) { return false; - }else{break;} + } } + else{break;} } sleep(100); continue; } - return st1 == 0 ? (uint8_t *)dma_get_buffer() : NULL; } @@ -458,7 +463,7 @@ bool floppy_seek(uint8_t cylinder, uint8_t head) bool floppy_wait_for_interrupt() { - for(int i = 0; i < 10; i++) + /*for(int i = 0; i < 20; i++) { if(floppy_interrupt_flag) { @@ -466,10 +471,24 @@ bool floppy_wait_for_interrupt() return true; } - sleep(1); + sleep(10); } - return false; + return false;*/ + uint32_t before = timer_get_system_clock(); + + while(!floppy_interrupt_flag) + { + if(timer_get_system_clock() - before > 60000) + { + logger_log_error("[FLOPPY] Floppy wait for interrupt timeout (60s)"); + return false; + } + } + + floppy_interrupt_flag = false; + return true; + } bool floppy_interrupt() diff --git a/os/kernel/src/filesystems/fat/fat.c b/os/kernel/src/filesystems/fat/fat.c index 32f65f95..118b0e8e 100644 --- a/os/kernel/src/filesystems/fat/fat.c +++ b/os/kernel/src/filesystems/fat/fat.c @@ -396,11 +396,14 @@ uint8_t *fat_read_file_from_cluster(uint16_t initial_cluster, uint16_t cluster_o for (int i = 0; i < current_partition->header->sectors_per_cluster; i++) { keyboard_scan_ascii_pair kb; - vga_newline(); + /*vga_newline(); vga_printstring("Loading files... Press any key to test next file"); vga_newline(); while(!keyboard_get_key_from_buffer(&kb)); + + logger_log_info("[FAT] Copy to buffer");*/ uint8_t *read_data = current_partition->read_from_device(current_partition->device_number, cluster_to_read + i); + if(read_data == NULL) logger_log_error("[FAT] FLOPPY RETURN NULL!"); memcpy(buffer_ptr, read_data, current_partition->header->bytes_per_sector); buffer_ptr += current_partition->header->bytes_per_sector; diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index e3e762d2..c57d6bf4 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -289,10 +289,6 @@ void startup() partitions_init(); logger_log_ok("Partitions"); - - timer_init(); - logger_log_ok("Timer"); - tss_init(); logger_log_ok("TSS"); From 9a977c66cfff2074b115be1cf93f967f18821fa1 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 8 Jul 2021 21:02:46 +0200 Subject: [PATCH 148/165] Murphy still alive --- os/kernel/src/drivers/floppy/floppy.c | 2 - os/kernel/src/drivers/vbe/vbe.c | 4 - os/kernel/src/kernel.c | 88 ++++++++++- os/kernel/src/v8086/memory_operations.h | 49 ++---- os/kernel/src/v8086/mod_rm_parsing.c | 145 +++--------------- os/kernel/src/v8086/mod_rm_parsing.h | 12 +- .../v8086/operations/arithmetic_operations.c | 5 +- .../src/v8086/operations/internal_funcs.h | 6 +- .../src/v8086/operations/misc_operations.c | 3 - os/kernel/src/v8086/operations/opcodes.c | 76 +++++++++ os/kernel/src/v8086/operations/opcodes.h | 19 +++ .../v8086/operations/procedure_operations.c | 8 +- .../src/v8086/operations/stack_operations.c | 4 +- os/kernel/src/v8086/stack.h | 9 +- os/kernel/src/v8086/v8086.c | 40 +++-- os/kernel/src/v8086/v8086.h | 88 ++++++----- 16 files changed, 318 insertions(+), 240 deletions(-) diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index 21c73634..d7e06c67 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -336,8 +336,6 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect return false; } - sleep(100); - // Read command status /*uint8_t st0 =*/ floppy_read_data(); uint8_t st1 = floppy_read_data(); diff --git a/os/kernel/src/drivers/vbe/vbe.c b/os/kernel/src/drivers/vbe/vbe.c index 6f09f6ef..9392e900 100644 --- a/os/kernel/src/drivers/vbe/vbe.c +++ b/os/kernel/src/drivers/vbe/vbe.c @@ -172,9 +172,7 @@ VBEStatus VBE_set_current_bank(uint32_t bank_number) machine->regs.x.ax = 0x4f05; machine->regs.x.bx = 0; machine->regs.x.dx = bank_number; - setSkipDebugging(false); int16_t status = v8086_call_int(machine, 0x10); - setSkipDebugging(true); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; @@ -244,9 +242,7 @@ VBEStatus VBE_display_window_control_set_16bit(uint8_t window_number, uint8_t wi machine->regs.h.bh = 0x00; machine->regs.h.bl = window_number; machine->regs.x.dx = window_mem_number; - setSkipDebugging(false); int16_t status = v8086_call_int(machine, 0x10); - setSkipDebugging(true); if(status != 0x10) return VBE_INTERNAL_ERROR; if(machine->regs.h.al != 0x4f) return VBE_NOT_EXIST; if(machine->regs.h.ah != 0x00) return VBE_FUNCTION_FAILURE; diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index c57d6bf4..20a3d539 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -40,6 +40,8 @@ #include "v8086/memory_operations.h" #include "drivers/vbe/vbe.h" +#include "debug_helpers/library/kernel_stdio.h" + #ifdef TEST_V8086 #include "v8086/tests/tests.h" #endif @@ -421,8 +423,8 @@ int kmain() switch_active_terminal(0); - process_manager_run(); - keyboard_scan_ascii_pair kb; + //process_manager_run(); + //keyboard_scan_ascii_pair kb; //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); //while(!keyboard_get_key_from_buffer(&kb)); @@ -455,12 +457,84 @@ int kmain() } }*/ + v8086_machine = v8086_create_machine(); + v8086_set_386_instruction_set(v8086_machine); + idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); + + uint8_t result_text[80]; + uint32_t list_timings[8]; + uint8_t iiii = 0; + + v8086_machine->regs.h.ah = 0x0; + v8086_machine->regs.h.al = 0x07; + uint32_t start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + uint32_t stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.h.ah = 0x0; + v8086_machine->regs.h.al = 0x13; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.h.ah = 0x0e; + v8086_machine->regs.h.al = 0x41; + v8086_machine->regs.h.bl = 0xf; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.h.ah = 0x0f; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.x.ax = 0x4f00; + v8086_machine->sregs.es = 0x0; + v8086_machine->regs.x.di = 0x7e00; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.x.ax = 0x4f01; + v8086_machine->sregs.es = 0x0; + v8086_machine->regs.x.di = 0x7e00; + v8086_machine->regs.x.cx = 0x13; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.x.ax = 0x4f02; + v8086_machine->regs.x.bx = 0x13; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + v8086_machine->regs.x.ax = 0x4f03; + start = timer_get_system_clock(); + v8086_call_int(v8086_machine, 0x10); + stop = timer_get_system_clock(); + list_timings[iiii++] = stop - start; + + generic_vga_set_video_mode(0x07); + for(int ii = 0; ii < 8; ii++){ + kernel_sprintf(result_text, "FUNKCJA %d: %d", ii++, list_timings[ii]); + vga_printstring(buff); + vga_newline(); + } - vga_printchar('x'); + /*vga_printchar('x'); uint32_t s = timer_get_system_clock(); while(timer_get_system_clock() - s < 10000); - vga_printchar('y'); + vga_printchar('y');*/ #define FUN_9 @@ -522,7 +596,7 @@ int kmain() vga_printstring("Unable to get SVGA MODE INFORMATION: "); vga_printstring(buff); vga_newline(); - while(!keyboard_get_key_from_buffer(&kb)); + //while(!keyboard_get_key_from_buffer(&kb)); } else{ physBufforAddress = mode_info.frame_buffor_phys_address; @@ -562,7 +636,7 @@ int kmain() vga_printstring(buff); vga_newline(); - if(physBufforAddress != 0) + /*if(physBufforAddress != 0) { VBEStatus x = VBE_set_video_mode(0x10f|(1<<14), true); VBE_set_current_bank(0); @@ -570,7 +644,7 @@ int kmain() uint8_t* color = 12*0x400000 + 0xc00000000; drawLenaIn10fH_linear(color); paging_unmap_page(12); - } + }*/ } else{ vga_printstring("Unable to get SVGA INFORMATION\n"); diff --git a/os/kernel/src/v8086/memory_operations.h b/os/kernel/src/v8086/memory_operations.h index 30f1777a..58c8027e 100644 --- a/os/kernel/src/v8086/memory_operations.h +++ b/os/kernel/src/v8086/memory_operations.h @@ -4,55 +4,40 @@ #include #include -static inline uint32_t get_absolute_address(uint32_t segment, uint32_t offset) -{ - return segment * 0x10 + offset; -} +#define get_absolute_address(segment, offset) ((uint32_t)segment * 0x10 + (uint32_t)offset) -static inline uint8_t* get_byte_pointer(uint8_t* memory, uint32_t absolute_address) -{ - return memory + absolute_address; -} +#define get_byte_pointer(memory, absolute_address) (memory + (uint32_t) absolute_address) -static inline uint16_t* get_word_pointer(uint8_t* memory, uint32_t absolute_address) -{ - return (uint16_t*)(memory + absolute_address); -} +#define get_word_pointer(memory, absolute_address) ((uint16_t*)(memory + (uint32_t) absolute_address)) -static inline uint32_t* get_dword_pointer(uint8_t* memory, uint32_t absolute_address) -{ - return (uint32_t*)(memory + absolute_address); -} +#define get_dword_pointer(memory, absolute_address) ((uint32_t*)(memory + (uint32_t) absolute_address)) -static inline void* get_variable_length_pointer(uint8_t* memory, uint32_t absolute_address, uint8_t width) -{ - switch(width) - { - case 8: - return get_byte_pointer(memory, absolute_address); - case 16: - return get_word_pointer(memory, absolute_address); - case 32: - return get_dword_pointer(memory, absolute_address); - default: - return NULL; - } -} +#define get_variable_length_pointer(memory, absolute_address, width) ((void*)(memory + (uint32_t) absolute_address)) + +#define read_byte_from_pointer(memory, absolute_address) (*(get_byte_pointer(memory, absolute_address))) + +#define read_word_from_pointer(memory, absolute_address) (*(get_word_pointer(memory, absolute_address))) +#define read_dword_from_pointer(memory, absolute_address) (*(get_dword_pointer(memory, absolute_address))) + +/* static inline uint8_t read_byte_from_pointer(const uint8_t* memory, uint32_t absolute_address) { return *(memory + absolute_address); } - +*/ +/* static inline uint16_t read_word_from_pointer(uint8_t* memory, uint32_t absolute_address) { return *get_word_pointer(memory, absolute_address); } - +*/ +/* static inline uint32_t read_dword_from_pointer(uint8_t* memory, uint32_t absolute_address) { return *get_dword_pointer(memory, absolute_address); } +*/ static inline void write_byte_to_pointer(uint8_t* memory, uint32_t absolute_address, uint8_t value) { diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index 812d9844..c99bd954 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -2,87 +2,10 @@ #include #include "memory_operations.h" -uint8_t* get_byte_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case V8086_AL: - return &(machine->regs.h.al); - case V8086_AH: - return &(machine->regs.h.ah); - case V8086_BL: - return &(machine->regs.h.bl); - case V8086_BH: - return &(machine->regs.h.bh); - case V8086_CL: - return &(machine->regs.h.cl); - case V8086_CH: - return &(machine->regs.h.ch); - case V8086_DL: - return &(machine->regs.h.dl); - case V8086_DH: - return &(machine->regs.h.dh); - default: - return NULL; - } - return NULL; -} - -uint16_t* get_word_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case V8086_AX: - return &(machine->regs.x.ax); - case V8086_CX: - return &(machine->regs.x.cx); - case V8086_DX: - return &(machine->regs.x.dx); - case V8086_BX: - return &(machine->regs.x.bx); - case V8086_SP: - return &(machine->regs.x.sp); - case V8086_BP: - return &(machine->regs.x.bp); - case V8086_SI: - return &(machine->regs.x.si); - case V8086_DI: - return &(machine->regs.x.di); - default: - return NULL; - } - return NULL; -} - -uint32_t* get_dword_register(v8086* machine, uint8_t reg_field) -{ - switch(reg_field) - { - case V8086_EAX: - return &(machine->regs.d.eax); - case V8086_ECX: - return &(machine->regs.d.ecx); - case V8086_EDX: - return &(machine->regs.d.edx); - case V8086_EBX: - return &(machine->regs.d.ebx); - case V8086_ESP: - return &(machine->regs.d.esp); - case V8086_EBP: - return &(machine->regs.d.ebp); - case V8086_ESI: - return &(machine->regs.d.esi); - case V8086_EDI: - return &(machine->regs.d.edi); - default: - return NULL; - } - return NULL; -} - void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width) { - switch (width) + return width == 8 ? (void*)get_byte_register(machine, reg_field) : (void*)get_dword_register(machine, reg_field); + /*switch (width) { case 8: return get_byte_register(machine, reg_field); @@ -92,28 +15,7 @@ void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t wi return get_dword_register(machine, reg_field); default: return NULL; - } -} - -uint16_t* select_segment_register(v8086* machine, segment_register_select select) -{ - switch(select) - { - case V8086_CS: - return &(machine->sregs.cs); - case V8086_DS: - return &(machine->sregs.ds); - case V8086_SS: - return &(machine->sregs.ss); - case V8086_ES: - return &(machine->sregs.es); - case V8086_FS: - return &(machine->sregs.fs); - case V8086_GS: - return &(machine->sregs.gs); - default: - return NULL; - } + }*/ } int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset) @@ -123,7 +25,14 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); else { - switch (mod_rm & 7u) + if(((mod_rm & 7u) == 2) || ((mod_rm & 7u) == 3) || (((mod_rm & 7u) == 6) && ((mod_rm & 0xC0) == 0))){ + segment_register = select_segment_register(machine, V8086_SS); + } + else{ + segment_register = select_segment_register(machine, V8086_DS); + } + /*TODO: consider better optimization*/ + /*switch (mod_rm & 7u) { case 0: case 1: @@ -139,7 +48,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 default: segment_register = select_segment_register(machine, V8086_SS); break; - } + }*/ } if(segment_register == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; @@ -246,7 +155,6 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 default: return V8086_BAD_MOD; } - return V8086_UNKNOWN_ERROR; } int16_t read_and_parse_sib(v8086* machine, uint8_t mod, uint16_t** segment, uint32_t *offset) @@ -471,27 +379,16 @@ void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width) uint16_t segment; uint32_t offset; - switch(mod_rm >> 6u) //Parsing mod than parsing rm + if((mod_rm & 0xC0) < 0xC0) { - case 0: - case 1: - case 2: - if(machine->internal_state.address_32_bit) - calculate_segment_offset_from_mode_32(machine, mod_rm, &segment, &offset); - else - calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); - return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); - case 3: - switch(width){ - case 8: - return get_byte_register(machine, mod_rm & 7u); - case 16: - return get_word_register(machine, mod_rm & 7u); - case 32: - return get_dword_register(machine, mod_rm & 7u); - default: - return NULL; - } + if(machine->internal_state.address_32_bit) + calculate_segment_offset_from_mode_32(machine, mod_rm, &segment, &offset); + else + calculate_segment_offset_from_mode(machine, mod_rm, &segment, &offset); + return get_variable_length_pointer(machine->Memory, get_absolute_address(segment, offset), width); + } + else{ + return get_variable_length_register(machine, mod_rm & 7u, width); } return NULL; } diff --git a/os/kernel/src/v8086/mod_rm_parsing.h b/os/kernel/src/v8086/mod_rm_parsing.h index f89b0cd9..a1701c75 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.h +++ b/os/kernel/src/v8086/mod_rm_parsing.h @@ -3,12 +3,18 @@ #include "v8086.h" -uint8_t* get_byte_register(v8086* machine, uint8_t reg_field); +#define get_byte_register(machine, reg_field) ((uint8_t*)(&(machine->regs.h.al) + ((((reg_field) & 3) << 2) + ((reg_field) >> 2)))) +#define get_word_register(machine, reg_field) ((uint16_t*)(&(machine->regs.d.eax) + (reg_field))) +#define get_dword_register(machine, reg_field) ((uint32_t*)(&(machine->regs.d.eax) + (reg_field))) + +/*uint8_t* get_byte_register(v8086* machine, uint8_t reg_field); uint16_t* get_word_register(v8086* machine, uint8_t reg_field); -uint32_t* get_dword_register(v8086* machine, uint8_t reg_field); +uint32_t* get_dword_register(v8086* machine, uint8_t reg_field);*/ void* get_variable_length_register(v8086* machine, uint8_t reg_field, uint8_t width); -uint16_t* select_segment_register(v8086* machine, segment_register_select select); +#define select_segment_register(machine, select) ((uint16_t*)(&((machine)->sregs.es) + (select))) + +//uint16_t* select_segment_register(v8086* machine, segment_register_select select); int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset); int16_t calculate_segment_offset_from_mode_32(v8086* machine, uint8_t mod_rm, uint16_t* segment, uint32_t* offset); void* get_memory_from_mode(v8086* machine, uint8_t mod_rm, uint8_t width); diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 3279d76c..8ba9c3a9 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -140,6 +140,7 @@ int16_t perform_rol(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { __asm__ __volatile__("rolw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); else if (width == 32) __asm__ __volatile__("roll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); + else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); @@ -375,7 +376,7 @@ int16_t perform_division(v8086 *machine, void *source, uint8_t signed_div, uint8 if (width == 8) { if(*((int8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; - int16_t temp = (int16_t) machine->regs.w.ax / *((int8_t *) source); + int16_t temp = (int16_t) machine->regs.w.ax / (int16_t)(*((int8_t *) source)); if((temp > (int8_t)0x7f) || (temp < (int8_t)0x80)) return V8086_DIVISION_OVERFLOW; machine->regs.h.al = temp; machine->regs.h.ah = (int16_t) machine->regs.w.ax % *((int8_t *) source); @@ -764,7 +765,6 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { machine->internal_state.IPOffset += 4; } return perform_test(machine, &immediate, dest, width); - break; } case 2: //NOT if (width == 8) @@ -775,7 +775,6 @@ int16_t execute_group_3(v8086 *machine, uint8_t opcode) { *((uint32_t *) dest) = ~(*((uint32_t *) dest)); else return V8086_BAD_WIDTH; return V8086_OK; - break; case 3: //NEG return perform_neg(machine, dest, width); case 4: //MUL diff --git a/os/kernel/src/v8086/operations/internal_funcs.h b/os/kernel/src/v8086/operations/internal_funcs.h index 03916f72..5285f6ba 100644 --- a/os/kernel/src/v8086/operations/internal_funcs.h +++ b/os/kernel/src/v8086/operations/internal_funcs.h @@ -3,9 +3,11 @@ #include -static inline uint8_t get_reg(uint8_t mod_rm) +#define get_reg(mod_rm) ((uint8_t)(mod_rm >> 3u) & 7u) + +/*static inline uint8_t get_reg(uint8_t mod_rm) { return (uint8_t)(mod_rm >> 3u) & 7u; -} +}*/ #endif //V8086_INTERNAL_FUNCS_H diff --git a/os/kernel/src/v8086/operations/misc_operations.c b/os/kernel/src/v8086/operations/misc_operations.c index 4853f16e..c1381105 100644 --- a/os/kernel/src/v8086/operations/misc_operations.c +++ b/os/kernel/src/v8086/operations/misc_operations.c @@ -18,10 +18,8 @@ int16_t perform_group_4(v8086* machine) { case 0: //INC rm8 return perform_inc(machine, dest, width); - break; case 1: //DEC rm8 return perform_dec(machine, dest, width); - break; default: return V8086_UNDEFINED_OPCODE; } @@ -76,7 +74,6 @@ int16_t perform_group_5(v8086* machine) default: return V8086_UNDEFINED_OPCODE; } - return V8086_UNKNOWN_ERROR; } int16_t setting_and_clearing_flags(v8086* machine, uint8_t opcode) diff --git a/os/kernel/src/v8086/operations/opcodes.c b/os/kernel/src/v8086/operations/opcodes.c index 719fa4d1..e849de35 100644 --- a/os/kernel/src/v8086/operations/opcodes.c +++ b/os/kernel/src/v8086/operations/opcodes.c @@ -686,3 +686,79 @@ OPCODE_PROTO(bsr) { return bit_scan_backward(machine, machine->internal_state.operand_32_bit ? 32 : 16); } + +OPCODE_PROTO(prefix_cs) +{ + machine->internal_state.segment_reg_select = V8086_CS; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_ds) +{ + machine->internal_state.segment_reg_select = V8086_DS; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_es) +{ + machine->internal_state.segment_reg_select = V8086_ES; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_fs) +{ + machine->internal_state.segment_reg_select = V8086_FS; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_gs) +{ + machine->internal_state.segment_reg_select = V8086_GS; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_ss) +{ + machine->internal_state.segment_reg_select = V8086_SS; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_address_32) +{ + machine->internal_state.address_32_bit = 1; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_operand_32) +{ + machine->internal_state.operand_32_bit = 1; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_repne) +{ + machine->internal_state.rep_prefix = V8086_REPNE; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_rep_repe) +{ + machine->internal_state.rep_prefix = V8086_REP_REPE; + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} + +OPCODE_PROTO(prefix_lock) +{ + machine->internal_state.previous_byte_was_prefix = 1; + return V8086_OK; +} \ No newline at end of file diff --git a/os/kernel/src/v8086/operations/opcodes.h b/os/kernel/src/v8086/operations/opcodes.h index 4d1b5747..342180cc 100644 --- a/os/kernel/src/v8086/operations/opcodes.h +++ b/os/kernel/src/v8086/operations/opcodes.h @@ -136,7 +136,26 @@ OPCODE_PROTO(movsx); OPCODE_PROTO(bsf); OPCODE_PROTO(bsr); +OPCODE_PROTO(prefix_cs); +OPCODE_PROTO(prefix_ds); +OPCODE_PROTO(prefix_es); + +OPCODE_PROTO(prefix_fs); + +OPCODE_PROTO(prefix_gs); + +OPCODE_PROTO(prefix_ss); + +OPCODE_PROTO(prefix_address_32); + +OPCODE_PROTO(prefix_operand_32); + +OPCODE_PROTO(prefix_repne); + +OPCODE_PROTO(prefix_rep_repe); + +OPCODE_PROTO(prefix_lock); #endif //MICROS_OPCODES_H diff --git a/os/kernel/src/v8086/operations/procedure_operations.c b/os/kernel/src/v8086/operations/procedure_operations.c index 48ac87d6..cd7c7210 100644 --- a/os/kernel/src/v8086/operations/procedure_operations.c +++ b/os/kernel/src/v8086/operations/procedure_operations.c @@ -1,7 +1,8 @@ #include #include #include "procedure_operations.h" -#include "../../drivers/vga/vga.h"" + +#include int16_t near_relative_call(v8086* machine) { @@ -80,16 +81,17 @@ int16_t far_ret_imm(v8086* machine) int16_t perform_interrupt(v8086* machine, uint8_t interrupt_number) { if(interrupt_number == 0x21 && machine->regs.h.ah == 0x4c){ -// vga_printstring("Wszedlem\n"); + printf("Wszedlem\n"); machine->sregs.cs = 0x7c0; machine->regs.w.sp = 0xFFFE - 6; return far_ret(machine); } else if(interrupt_number == 0x21 && machine->regs.h.ah == 0x40 && machine->regs.x.bx == 1) { + printf("Writting to screen\n"); for(uint32_t i = 0; i < machine->regs.x.cx; i++) { - vga_printchar(machine->Memory[get_absolute_address(machine->sregs.ds, machine->regs.x.dx + i)]); + putchar(machine->Memory[get_absolute_address(machine->sregs.ds, machine->regs.x.dx + i)]); } machine->regs.x.ax = machine->regs.x.cx; bit_clear(machine->regs.x.flags, 1u << CARRY_FLAG_BIT); diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index 895413f3..edeb5ce0 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -108,9 +108,9 @@ int16_t push_immediate(v8086* machine, uint8_t width) int8_t imm = (int8_t)read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; if (machine -> internal_state.operand_32_bit ) - push_dword(machine, imm); + push_dword(machine, imm); else - push_word(machine, imm); + push_word(machine, imm); return V8086_OK; } if(width == 16) diff --git a/os/kernel/src/v8086/stack.h b/os/kernel/src/v8086/stack.h index 18856d5c..f0202e78 100644 --- a/os/kernel/src/v8086/stack.h +++ b/os/kernel/src/v8086/stack.h @@ -6,17 +6,20 @@ static inline void push_byte(v8086* machine, uint8_t value) { - write_byte_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 1), value); + machine->regs.w.sp -= 1; + write_byte_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp), value); } static inline void push_word(v8086* machine, uint16_t value) { - write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 2), value); + machine->regs.w.sp -= 2; + write_word_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp), value); } static inline void push_dword(v8086* machine, uint32_t value) { - write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp -= 4), value); + machine->regs.w.sp -= 4; + write_dword_to_pointer(machine->Memory, get_absolute_address(machine->sregs.ss, machine->regs.w.sp), value); } static inline uint8_t pop_byte(v8086* machine) diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 1d61f44b..025645f3 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -247,6 +247,20 @@ void v8086_set_8086_instruction_set(v8086* machine) machine->operations_0fh[i] = NULL; } + ASSIGN_OPCODE(0x26u, prefix_es); + ASSIGN_OPCODE(0x36u, prefix_ss); + ASSIGN_OPCODE(0x64u, prefix_fs); + ASSIGN_OPCODE(0x65u, prefix_gs); + ASSIGN_OPCODE(0x2eu, prefix_cs); + ASSIGN_OPCODE(0x3eu, prefix_ds); + + ASSIGN_OPCODE(0x66u, prefix_operand_32); + ASSIGN_OPCODE(0x67u, prefix_address_32); + + ASSIGN_OPCODE(0xf0u, prefix_lock); + ASSIGN_OPCODE(0xf2u, prefix_repne); + ASSIGN_OPCODE(0xf3u, prefix_rep_repe); + machine->is_compatibility = V8086_IS8086; } @@ -399,11 +413,14 @@ uint32_t v8086_get_address_of_int(v8086* machine, int16_t num) int16_t parse_and_execute_instruction(v8086* machine) { - machine->internal_state.IPOffset = 0; - machine->internal_state.operand_32_bit = 0; - machine->internal_state.address_32_bit = 0; - machine->internal_state.segment_reg_select = V8086_DEFAULT; - machine->internal_state.rep_prefix = V8086_NONE_REPEAT; + //if(!machine->internal_state.previous_byte_was_prefix) { + machine->IP.w.ip += machine->internal_state.IPOffset; + machine->internal_state.IPOffset = 0; + machine->internal_state.operand_32_bit = 0; + machine->internal_state.address_32_bit = 0; + machine->internal_state.segment_reg_select = V8086_DEFAULT; + machine->internal_state.rep_prefix = V8086_NONE_REPEAT; + //} int16_t status = V8086_OK; @@ -561,8 +578,6 @@ int16_t parse_and_execute_instruction(v8086* machine) //Maybe opcode, an be also prefix uint8_t opcode; decode: opcode = read_byte_from_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); - uint32_t temp = get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset); - uint8_t* ptr_to_opcode = get_byte_pointer(machine->Memory, get_absolute_address(machine->sregs.cs, machine->IP.w.ip + machine->internal_state.IPOffset)); machine->internal_state.IPOffset += 1; @@ -577,7 +592,7 @@ int16_t parse_and_execute_instruction(v8086* machine) //PREFIXES //Segment Prefix V8086_CS DS V8086_ES SS - if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment + /*if((opcode & 0x7u) == 0x6 && ((opcode >> 5u) & 0x7u) == 0x1u) //001XX110 pattern where XX is number of segment { machine->internal_state.segment_reg_select = (opcode >> 3u) & 0x3u; goto decode; //continue parsing opcode; @@ -622,14 +637,19 @@ int16_t parse_and_execute_instruction(v8086* machine) else if(opcode == 0xF0) { goto decode; //ommit prefix, contniue parsinf opcode; - } + }*/ if(machine->operations[opcode] != NULL) status = machine->operations[opcode](machine, opcode); else return V8086_UNDEFINED_OPCODE; - machine->IP.w.ip += machine->internal_state.IPOffset; + if(machine->internal_state.previous_byte_was_prefix) + { + machine->internal_state.previous_byte_was_prefix = 0; + goto decode; + } + #ifdef DEBUG_V8086 #ifdef DEBUG_V8086_TEXT serial_send_string(COM1_PORT, "------------------------------------------\n"); diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index 9929ac14..b970f277 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -21,10 +21,10 @@ #define OVERFLOW_FLAG_BIT 11u #define DEBUG_V8086 -#define TEST_V8086 +//#define TEST_V8086 typedef enum _segment_register_select { - V8086_ES, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT + V8086_ES=0, V8086_CS, V8086_SS, V8086_DS, V8086_FS, V8086_GS, V8086_DEFAULT } segment_register_select; typedef enum _repeat_prefix { @@ -63,50 +63,53 @@ typedef enum _machine_status { } machine_status; struct DWORDREGS { - uint32_t edi; - uint32_t esi; - uint32_t ebp; - uint32_t cflag; - uint32_t ebx; - uint32_t edx; - uint32_t ecx; - uint32_t eax; - uint16_t eflags; - uint32_t esp; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t cflag; + uint16_t eflags; + } __attribute__((packed)); struct WORDREGS { - uint16_t di, _upper_di; - uint16_t si, _upper_si; - uint16_t bp, _upper_bp; - uint16_t cflag, _upper_cflag; - uint16_t bx, _upper_bx; - uint16_t dx, _upper_dx; - uint16_t cx, _upper_cx; - uint16_t ax, _upper_ax; - uint16_t flags; - uint16_t sp, _upper_sp; + uint16_t ax, _upper_ax; + uint16_t cx, _upper_cx; + uint16_t dx, _upper_dx; + uint16_t bx, _upper_bx; + uint16_t sp, _upper_sp; + uint16_t bp, _upper_bp; + uint16_t si, _upper_si; + uint16_t di, _upper_di; + uint16_t cflag, _upper_cflag; + uint16_t flags; + } __attribute__((packed)); struct BYTEREGS { - uint16_t di, _upper_di; - uint16_t si, _upper_si; - uint16_t bp, _upper_bp; - uint32_t cflag; - uint8_t bl; - uint8_t bh; - uint16_t _upper_bx; - uint8_t dl; - uint8_t dh; - uint16_t _upper_dx; - uint8_t cl; - uint8_t ch; - uint16_t _upper_cx; - uint8_t al; - uint8_t ah; - uint16_t _upper_ax; - uint16_t flags; - uint16_t sp, _upper_sp; + uint8_t al; + uint8_t ah; + uint16_t _upper_ax; + uint8_t cl; + uint8_t ch; + uint16_t _upper_cx; + uint8_t dl; + uint8_t dh; + uint16_t _upper_dx; + uint8_t bl; + uint8_t bh; + uint16_t _upper_bx; + uint16_t sp, _upper_sp; + uint16_t bp, _upper_bp; + uint16_t si, _upper_si; + uint16_t di, _upper_di; + uint32_t cflag; + uint16_t flags; + } __attribute__((packed)); union REGS { /* Compatible with DPMI structure, except cflag */ @@ -118,11 +121,11 @@ union REGS { /* Compatible with DPMI structure, except cflag */ struct SREGS { uint16_t es; + uint16_t cs; + uint16_t ss; uint16_t ds; uint16_t fs; uint16_t gs; - uint16_t cs; - uint16_t ss; } __attribute__((packed)); struct DWORDIP{ @@ -146,6 +149,7 @@ typedef struct _is{ segment_register_select segment_reg_select; repeat_prefix rep_prefix; uint16_t IPOffset; + uint8_t previous_byte_was_prefix; }__attribute__((packed)) _internal_state; typedef struct _v8086 From d7f927c57fcdb1325d167086813001b3c308850d Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Sat, 10 Jul 2021 19:24:25 +0200 Subject: [PATCH 149/165] Fixed issue with ATAPI drives. Removed unnecessary debug information --- os/kernel/src/drivers/floppy/floppy.c | 10 +++------ .../src/drivers/harddisk/harddisk_detection.c | 22 +++++++++++++++++-- .../src/filesystems/partitions/partitions.c | 22 +++++-------------- os/kernel/src/kernel.c | 6 ++--- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index d7e06c67..0d161702 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -1,5 +1,4 @@ #include "floppy.h" -#include "../../debug_helpers/library/kernel_stdio.h" volatile uint32_t floppy_sectors_per_track; volatile uint32_t time_of_last_activity = 0; @@ -280,10 +279,7 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect floppy_enable_motor(); //sleep(500); - if(!read){ - vga_printstring("JASNA DUPA"); - while(1); - } + for (int i = 0; i < 10; i++) { @@ -321,8 +317,8 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect uint8_t sectors_per_track = floppy_sectors_per_track; // Sectors per track - //floppy_send_command(((sector + 1) >= sectors_per_track) ? sectors_per_track : (sector + 1)); - floppy_send_command(sectors_per_track); + floppy_send_command(((sector + 1) >= sectors_per_track) ? sectors_per_track : (sector + 1)); + //floppy_send_command(sectors_per_track); // Length of gap (0x1B = floppy 3,5) floppy_send_command(0x1B); diff --git a/os/kernel/src/drivers/harddisk/harddisk_detection.c b/os/kernel/src/drivers/harddisk/harddisk_detection.c index 4ee8bf20..6e06770d 100644 --- a/os/kernel/src/drivers/harddisk/harddisk_detection.c +++ b/os/kernel/src/drivers/harddisk/harddisk_detection.c @@ -35,18 +35,23 @@ int8_t __harddisk_check_presence(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA_BU else if(type == HARDDISK_ATA_MASTER && bus == HARDDISK_ATA_SECONDARY_BUS) data = &states->secondary_master_data; else if(type == HARDDISK_ATA_SLAVE && bus == HARDDISK_ATA_SECONDARY_BUS) data = &states->secondary_slave_data; + // Do soft reset __harddisk_soft_reset_port(control_port); + // Send message to drive io_out_byte(io_port + HARDDISK_IO_DRIVE_HEAD_REGISTER_OFFSET, message_to_drive.value); + // Make 400ns delay __harddisk_400ns_delay(control_port); + uint8_t cylinder_low = io_in_byte(io_port + HARDDISK_IO_CYLINDER_LOW_REGISTER_OFFSET); uint8_t cylinder_high = io_in_byte(io_port + HARDDISK_IO_CYLINDER_HIGH_REGISTER_OFFSET); + /* differentiate ATA, ATAPI, SATA and SATAPI */ if (cylinder_low==0x3c && cylinder_high==0xc3) { @@ -110,6 +115,7 @@ int8_t __harddisk_get_identify_data(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA return -2; } + // Send message to drive io_out_byte(io_port + HARDDISK_IO_DRIVE_HEAD_REGISTER_OFFSET, message_to_drive.value); @@ -125,6 +131,7 @@ int8_t __harddisk_get_identify_data(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA // Send the specific IDENTIFY command to the Command IO port. io_out_byte(io_port + HARDDISK_IO_COMMAND_REGISTER_OFFSET, identify_command); + // Read the Status port again. harddisk_io_control_status_register result; result.value = io_in_byte(io_port + HARDDISK_IO_STATUS_REGISTER_OFFSET); @@ -140,11 +147,21 @@ int8_t __harddisk_get_identify_data(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA { if(result.fields.busy == 0) { + //Check LBA mid and high to check if device follows ATA specification + uint8_t LBA_mid, LBA_hi; + LBA_mid = io_in_byte(io_port + HARDDISK_IO_CYLINDER_LOW_REGISTER_OFFSET); + LBA_hi = io_in_byte(io_port + HARDDISK_IO_CYLINDER_HIGH_REGISTER_OFFSET); + if(LBA_hi != 0 && LBA_mid != 0) return 1; + //TODO + //There should be a way to load the data from devices that do not follow the standard. Find this way + // Otherwise, continue polling one of the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets. for(;;) { result.value = io_in_byte(io_port + HARDDISK_IO_STATUS_REGISTER_OFFSET); - if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1) + + + if(result.fields.has_pio_data_to_transfer_or_ready_to_accept_pio_data == 1 || result.fields.overlapped_mode_service_request == 1) { for(int i = 0; i < 256; i++) { @@ -153,11 +170,12 @@ int8_t __harddisk_get_identify_data(HARDDISK_ATA_MASTER_SLAVE type, HARDDISK_ATA } return 1; } - else if(result.fields.error_occurred == 1) + else if(result.fields.error_occurred == 1 || result.fields.drive_fault_error == 1) { return -1; } } + } result.value = io_in_byte(io_port + HARDDISK_IO_STATUS_REGISTER_OFFSET); } diff --git a/os/kernel/src/filesystems/partitions/partitions.c b/os/kernel/src/filesystems/partitions/partitions.c index c9f9b9de..239c4a13 100644 --- a/os/kernel/src/filesystems/partitions/partitions.c +++ b/os/kernel/src/filesystems/partitions/partitions.c @@ -1,5 +1,4 @@ #include "partitions.h" -#include "../../drivers/vga/vga.h" #include kvector partitions; @@ -7,11 +6,11 @@ kvector partitions; void partitions_init() { partitions_init_floppy(); - //Temporary commented - //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); - //partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); - //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); - // partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_SECONDARY_BUS); + + partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); + partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); + partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); + partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_SECONDARY_BUS); } void partitions_init_floppy() @@ -36,16 +35,7 @@ void partitions_init_floppy() memcpy(floppy_partition->header, floppy_do_operation_on_sector(0, 0, 1, true), 512); - char tmp[33]; - for(int i=0; i<62; i++){ - itoa(((uint8_t*)(floppy_partition->header))[i], tmp, 16); - vga_printstring(tmp); - vga_printchar(' '); - if ((i+1)%16==0) vga_newline(); - } - vga_newline(); - vga_printstring(floppy_partition->header->oem_identifier); - vga_newline(); + ; //while(1); fat_generic_set_current_partition(floppy_partition); diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 20a3d539..cb9d4ead 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -423,7 +423,7 @@ int kmain() switch_active_terminal(0); - //process_manager_run(); + process_manager_run(); //keyboard_scan_ascii_pair kb; //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); //while(!keyboard_get_key_from_buffer(&kb)); @@ -457,7 +457,7 @@ int kmain() } }*/ - v8086_machine = v8086_create_machine(); + /*v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); @@ -530,7 +530,7 @@ int kmain() vga_printstring(buff); vga_newline(); } - +*/ /*vga_printchar('x'); uint32_t s = timer_get_system_clock(); while(timer_get_system_clock() - s < 10000); From 65e4fa8dadd49912eeaf6a8537ce9e0ab2c9489a Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 17 Jul 2021 16:53:15 +0200 Subject: [PATCH 150/165] Not working --- os/kernel/src/kernel.c | 28 +++++++++++++++++++++++----- os/kernel/src/v8086/v8086.c | 2 +- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 20a3d539..7939cae1 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -466,12 +466,17 @@ int kmain() uint8_t iiii = 0; v8086_machine->regs.h.ah = 0x0; - v8086_machine->regs.h.al = 0x07; + v8086_machine->regs.h.al = 0x03; uint32_t start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + int status = v8086_call_int(v8086_machine, 0x10); uint32_t stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; + //generic_vga_set_video_mode(0x03); + + //vga_printstring("PIERDOLONA MAC!!!!"); + //vga_newline(); + v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x13; start = timer_get_system_clock(); @@ -523,10 +528,23 @@ int kmain() stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; - generic_vga_set_video_mode(0x07); - + v8086_machine->regs.h.ah = 0x0; + v8086_machine->regs.h.al = 0x3; + v8086_call_int(v8086_machine, 0x10); + + vga_clear_screen(); + vga_color c; + c.color_without_blink.background=VGA_COLOR_BLACK; + c.color_without_blink.letter=VGA_COLOR_WHITE; + vga_set_color(0, 0, c); + for(int ii = 0; ii < 8; ii++){ - kernel_sprintf(result_text, "FUNKCJA %d: %d", ii++, list_timings[ii]); + //kernel_sprintf(result_text, "FUNKCJA %d: %d", ii, list_timings[ii]); + vga_printstring("FUNKCJA "); + itoa(ii, buff, 10); + vga_printstring(buff); + vga_printstring(": "); + itoa(list_timings[ii], buff, 10); vga_printstring(buff); vga_newline(); } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 025645f3..3ecc10ee 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - #define DEBUG_V8086_INTERACTIVE + //#define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; From e4e8703dd51ed9fa203bf719bb528a1a97cbf88c Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Sun, 18 Jul 2021 00:19:58 +0200 Subject: [PATCH 151/165] Fixed bootloader freeze on most floppy controllers --- os/bootloader/src/bootloader.asm | 120 +++++++++++++++++++++++++------ os/kernel/src/init/startup.asm | 31 ++++++++ os/kernel/src/kernel.c | 3 + 3 files changed, 132 insertions(+), 22 deletions(-) diff --git a/os/bootloader/src/bootloader.asm b/os/bootloader/src/bootloader.asm index 81290526..33ecac3f 100644 --- a/os/bootloader/src/bootloader.asm +++ b/os/bootloader/src/bootloader.asm @@ -14,6 +14,8 @@ ; Jump to main and align to 3 bytes, we don't want to execute FAT12 header jmp Main + +; Function for displaying debug text in real mode nop ; FAT header @@ -44,9 +46,11 @@ NonDataSectors dw 0x0000 ; Entry point of bootloader Main: + ; Disable interrupts (will be enabled again during kernel initialization sequence) cli + ; Clear DF flag in EFLAGS register cld @@ -74,28 +78,46 @@ Main: ; Save non data sectors count to memory call GetNonDataSectorsCount mov [NonDataSectors], cl + + ; Reset floppy before read call ResetFloppy - ; Load FAT12 non data sectors - ; Number of sectors to read - mov al, [NonDataSectors] + ;floppy_loop: + ; Load FAT12 non data sectors + ; Number of sectors to read + mov al, [NonDataSectors] - ; We don't want load first sector with bootloader again - dec al + ; We don't want load first sector with bootloader again + dec al - ; Sector number - mov cl, 1 + ; Sector number + mov cl, 1 - ; Segment - xor bx, bx - mov es, bx + ; Segment + xor bx, bx + mov es, bx - ; Offset - mov bx, 0x7E00 + ; Offset + mov bx, 0x7E00 - call LoadFloppyData + call LoadFloppyData + + ; cmp ah, 0x61 + ; je floppy_out + + ;floppy_wait_keyboard: + ; mov ah, 1 + ; int 0x16 + ; jz floppy_wait_keyboard + ; mov ah, 0 + ; int 0x16 + ; cmp al, 'n' + ; jne floppy_wait_keyboard + ; jmp floppy_loop + + ;floppy_out: ; Get kernel first sector and store it in ax register call GetFirstKernelSector @@ -103,6 +125,8 @@ Main: ; Load all kernel sectors call LoadKernel + + ; Enter protected mode and jump to the loaded kernel call JumpToKernel @@ -138,7 +162,7 @@ GetCHS: div cx push ax - inc dx + ;inc dx push dx ; [ebp - 6] = Head = Temp % (Number of Heads) @@ -152,10 +176,15 @@ GetCHS: push ax ; Sector number - mov cl, [ebp - 4] + mov al, [ebp - 4] ; Track number - mov ch, [ebp - 8] + mov cx, [ebp - 8] + xchg ch, cl + ror cl, 1 + ror cl, 1 + or cl, al + inc cx ; Head number mov dh, [ebp - 6] @@ -175,23 +204,48 @@ GetCHS: ; - al - number of sectors read ; - cf - 1 if successful, 0 if error LoadFloppyData: + push ebp + mov ebp, esp + + movzx si, al + ; Function name: Read Disk Sectors - mov ah, 0x02 + mov ax, 0x0201 ; Get sector (cl), track (ch) and head (dh) + ; ax = [ebp - 2] push ax + ; bx = [ebp - 4] push bx + ; cx = [ebp - 6] + push cx + +loadfloppy_loop: mov bx, cx call GetCHS - pop bx - pop ax - + mov ax, [ebp - 2] + mov bx, [ebp - 4] + ; Drive number mov dl, [INT13Scratchpad] int 0x13 - ret + dec si + jz loadfloppy_exit + add bx, 0x200 + mov [ebp - 4], bx + inc word [ebp - 6] + mov cx, [ebp - 6] + jmp loadfloppy_loop + +loadfloppy_exit: + + mov esp, ebp + pop ebp + + ret + ; Input: nothing ; Output: ; cx - number of floppy sectors with metadata @@ -222,7 +276,7 @@ GetNonDataSectorsCount: ; ax - kernel first sector number GetFirstKernelSector: ; Set initial offset of non data sectors loaded into memory - mov ecx, 0x7E00 + mov cx, 0x7E00 ; Add size of both File Allocations Tables to get root directory offset mov al, [FileAllocationTables] @@ -251,6 +305,28 @@ GetFirstKernelSector: ; Compare chars from both strings mov ax, [si] mov bx, [di] + ;DEBUG + ;push cx + + ;mov ch, 0x0c + ;mov cl, al + + ;push ax + ;DispLoop: + ;xor ax, ax + ;mov ah, 1 + ;int 0x16 + ;jz DispLoop + ;mov ah, 0 + ;int 0x16 + ;cmp al, 'n' + ;jne DispLoop + + ;mov [es: 0], cx + + ;pop ax + ;pop cx +;DEBUG END cmp ax, bx ; If chars aren't equal, go to next entry diff --git a/os/kernel/src/init/startup.asm b/os/kernel/src/init/startup.asm index 7042bc91..d4fb2ce7 100644 --- a/os/kernel/src/init/startup.asm +++ b/os/kernel/src/init/startup.asm @@ -20,6 +20,18 @@ jmp main +; Function for displaying debug text in real mode +realstr: + + mov ax, 0xb800 + mov es, ax + mov ax, 0x0c41 + mov ecx, 10 + xor edi, edi + rep stosw + + ret + ; Entry frame: https://wiki.osdev.org/GDT gdt_begin: ; Null segment, reserved by CPU @@ -90,6 +102,8 @@ gdt_description: dd gdt_begin main: + ;call realstr + ;hlt ; Load memory map before we will switch to the protected mode ; Buffer segment mov bx, 0x0000 @@ -99,11 +113,18 @@ main: mov bx, 0x5C00 mov di, bx + + call load_memory_map + ;call realstr + ;hlt + ; Load GDT table lgdt [dword gdt_description] + + ; Set protected mode flag mov eax, cr0 or eax, 1 @@ -326,4 +347,14 @@ enable_paging: nop .branch: + ret + +; Function for displaying debug text in protected mode +protstr: + + mov edi, 0xb8000 + mov ax, 0x0941 + mov ecx, 10 + rep stosw + ret \ No newline at end of file diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 4ce1eb69..c530869f 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -390,6 +390,9 @@ void v8086_BIOS_timer_interrupt() int kmain() { + //uint16_t* vga_ptr = VGA_MODE_03H_BASE_ADDR; + //vga_ptr[0] = 0xf041; + //while(1); clear_bss(); startup(); From c5d0f223b0553be3a940860169b06e0085a5988c Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Thu, 22 Jul 2021 01:13:55 +0200 Subject: [PATCH 152/165] things gone wrong with v8086 --- .../src/filesystems/partitions/partitions.c | 8 +-- os/kernel/src/kernel.c | 53 +++++++++---------- .../v8086/operations/arithmetic_operations.c | 33 ++++++------ .../operations/ascii_adjustments_operations.c | 14 +++-- .../src/v8086/operations/stack_operations.c | 6 +-- .../src/v8086/operations/string_operations.c | 38 ++++++++++++- os/kernel/src/v8086/v8086.c | 10 +++- os/kernel/src/v8086/v8086.h | 2 +- 8 files changed, 108 insertions(+), 56 deletions(-) diff --git a/os/kernel/src/filesystems/partitions/partitions.c b/os/kernel/src/filesystems/partitions/partitions.c index 239c4a13..2bca9fc1 100644 --- a/os/kernel/src/filesystems/partitions/partitions.c +++ b/os/kernel/src/filesystems/partitions/partitions.c @@ -7,10 +7,10 @@ void partitions_init() { partitions_init_floppy(); - partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); - partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); - partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); - partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_SECONDARY_BUS); + //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_PRIMARY_BUS); + ///partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_PRIMARY_BUS); + //partitions_init_harddisks(HARDDISK_ATA_MASTER, HARDDISK_ATA_SECONDARY_BUS); + //partitions_init_harddisks(HARDDISK_ATA_SLAVE, HARDDISK_ATA_SECONDARY_BUS); } void partitions_init_floppy() diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index c530869f..3dabbb32 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -277,7 +277,7 @@ void startup() // NOTE: it doesn't work well, so assume for now that floppy controller is always present // if(fdc_is_present()) { - fdc_init(); + //fdc_init(); logger_log_ok("Floppy Disc Controller"); } @@ -288,7 +288,7 @@ void startup() keyboard_init(); logger_log_ok("Keyboard"); - partitions_init(); + //partitions_init(); logger_log_ok("Partitions"); tss_init(); @@ -409,7 +409,7 @@ int kmain() // create_terminal(&d); // create_terminal(&d); uint32_t d = 0; - for (int i = 0; i < 4; i++) + /*for (int i = 0; i < 4; i++) { char args[16]; itoa(i, args, 10); @@ -420,18 +420,18 @@ int kmain() uint32_t terminal_number = i; const terminal_struct* ts = get_terminals(&terminal_number); attach_process_to_terminal(ts[i].terminal_id, process_manager_get_process(p)); - } + }*/ vga_clear_screen(); - switch_active_terminal(0); + //switch_active_terminal(0); - process_manager_run(); - //keyboard_scan_ascii_pair kb; - //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); - //while(!keyboard_get_key_from_buffer(&kb)); + //process_manager_run(); + keyboard_scan_ascii_pair kb; + vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); + while(!keyboard_get_key_from_buffer(&kb)); -// serial_init(COM1_PORT, 921600, 8, 1, PARITY_NONE); + serial_init(COM1_PORT, 115200, 8, 1, PARITY_NONE); // v8086_machine = v8086_create_machine(); // v8086_set_386_instruction_set(v8086_machine); @@ -460,30 +460,26 @@ int kmain() } }*/ - /*v8086_machine = v8086_create_machine(); + v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); uint8_t result_text[80]; uint32_t list_timings[8]; + int16_t statuses[8]; uint8_t iiii = 0; v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x03; uint32_t start = timer_get_system_clock(); - int status = v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); uint32_t stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; - //generic_vga_set_video_mode(0x03); - - //vga_printstring("PIERDOLONA MAC!!!!"); - //vga_newline(); - - v8086_machine->regs.h.ah = 0x0; + /*v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x13; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; @@ -491,13 +487,13 @@ int kmain() v8086_machine->regs.h.al = 0x41; v8086_machine->regs.h.bl = 0xf; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; v8086_machine->regs.h.ah = 0x0f; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; @@ -505,7 +501,7 @@ int kmain() v8086_machine->sregs.es = 0x0; v8086_machine->regs.x.di = 0x7e00; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; @@ -514,27 +510,28 @@ int kmain() v8086_machine->regs.x.di = 0x7e00; v8086_machine->regs.x.cx = 0x13; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; v8086_machine->regs.x.ax = 0x4f02; v8086_machine->regs.x.bx = 0x13; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; v8086_machine->regs.x.ax = 0x4f03; start = timer_get_system_clock(); - v8086_call_int(v8086_machine, 0x10); + statuses[iiii] = v8086_call_int(v8086_machine, 0x10); stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x3; - v8086_call_int(v8086_machine, 0x10); + v8086_call_int(v8086_machine, 0x10);*/ + video_card_set_video_mode(0x3); vga_clear_screen(); vga_color c; c.color_without_blink.background=VGA_COLOR_BLACK; @@ -549,9 +546,11 @@ int kmain() vga_printstring(": "); itoa(list_timings[ii], buff, 10); vga_printstring(buff); + vga_printstring(" status: "); + itoa(statuses[ii], buff, 10); + vga_printstring(buff); vga_newline(); } -*/ /*vga_printchar('x'); uint32_t s = timer_get_system_clock(); while(timer_get_system_clock() - s < 10000); diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index 8ba9c3a9..a98e6b99 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -189,6 +189,7 @@ int16_t perform_shl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { else if (width == 32) __asm__ __volatile__("shll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return V8086_BAD_WIDTH; + if((arg & 0b11111) == 0) return 0; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); @@ -208,6 +209,7 @@ int16_t perform_shr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { else if (width == 32) __asm__ __volatile__("shrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); else return V8086_BAD_WIDTH; + if((arg & 0b11111) == 0) return 0; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); @@ -228,6 +230,7 @@ int16_t perform_sar(v8086* machine, void* dest, uint8_t arg, uint8_t width) else if(width == 32) __asm__ __volatile__("sarl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t*) dest)) : "a" (*((uint32_t*) dest)), "c" (arg)); else return -1; + if((arg & 0b11111) == 0) return 0; if(arg == 1) bit_write(machine->regs.w.flags, 1u<regs.w.flags, 1u<regs.w.flags, 1u<regs.w.ax / (int16_t)(*((int8_t *) source)); if((temp > (int8_t)0x7f) || (temp < (int8_t)0x80)) return V8086_DIVISION_OVERFLOW; - machine->regs.h.al = temp; machine->regs.h.ah = (int16_t) machine->regs.w.ax % *((int8_t *) source); + machine->regs.h.al = temp; } else if (width == 16) { - if(*((uint16_t *) source) == 0) + if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; int32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; int32_t temp = dividend / *((int16_t *) source); if((temp > (int16_t)0x7fff) || (temp < (int16_t)0x8000)) return V8086_DIVISION_OVERFLOW; - machine->regs.x.ax = temp; machine->regs.x.dx = dividend % *((int16_t *) source); + machine->regs.x.ax = temp; } else if (width == 32) { - if(*((uint32_t *) source) == 0) + if(*((uint32_t *) source) == 0) return V8086_DIVISION_BY_ZERO; int64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; int64_t temp = dividend / *((int32_t *) source); if((temp > (int32_t)0x7fffffff) || (temp < (int32_t)0x80000000)) return V8086_DIVISION_OVERFLOW; - machine->regs.d.eax = temp; machine->regs.d.edx = dividend % *((int32_t *) source); + machine->regs.d.eax = temp; } else return V8086_BAD_WIDTH; } else { if (width == 8) { - if(*((uint8_t *) source) == 0) + if(*((uint8_t *) source) == 0) return V8086_DIVISION_BY_ZERO; uint16_t temp = machine->regs.w.ax / *((uint8_t *) source); if(temp > 0xff) return V8086_DIVISION_OVERFLOW; + machine->regs.h.ah = ((uint16_t)machine->regs.w.ax % (*((uint8_t *) source))); machine->regs.h.al = temp; - machine->regs.h.ah = machine->regs.w.ax % *((uint8_t *) source); } else if (width == 16) { - if(*((uint16_t *) source) == 0) + if(*((uint16_t *) source) == 0) return V8086_DIVISION_BY_ZERO; uint32_t dividend = ((uint32_t)(machine->regs.x.dx) << 16u) | machine->regs.x.ax; uint32_t temp = dividend / *((uint16_t *) source); if(temp > 0xffff) return V8086_DIVISION_OVERFLOW; - machine->regs.x.ax = temp; machine->regs.x.dx = dividend % *((uint16_t *) source); + machine->regs.x.ax = temp; } else if (width == 32) { if(*((uint32_t *) source) == 0) { - + return V8086_DIVISION_BY_ZERO; } uint64_t dividend = ((uint64_t)(machine->regs.d.edx) << 32u) | machine->regs.d.eax; uint64_t temp = dividend / *((uint32_t *) source); if(temp > 0xffffffff) return V8086_DIVISION_OVERFLOW; - machine->regs.d.eax = temp; machine->regs.d.edx = dividend % *((uint32_t *) source); + machine->regs.d.eax = temp; } else return V8086_BAD_WIDTH; } return V8086_OK; diff --git a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c index 5c456b08..e9322724 100644 --- a/os/kernel/src/v8086/operations/ascii_adjustments_operations.c +++ b/os/kernel/src/v8086/operations/ascii_adjustments_operations.c @@ -47,9 +47,12 @@ int16_t adjust_after_add_sub_packed(v8086* machine, bool sub) } else if(!sub) bit_clear(machine->regs.w.flags, 1u <regs.h.al & 1u; + uint8_t parrity = 0; + for(uint8_t i = 0; i < 8; i++) parrity += (uint8_t)(machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, ((parrity % 2 == 0) ? 1: 0)); //PARRITY FLAG + /*uint8_t parrity = machine->regs.h.al & 1u; for(uint8_t i = 1; i < 8; i++) parrity ^= (uint8_t)(machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG return V8086_OK; @@ -72,9 +75,14 @@ int16_t adjust_after_mul_div(v8086* machine, bool div) machine->regs.h.ah = 0; } + uint8_t parrity = 0; + for(uint8_t i = 0; i < 8; i++) parrity += (uint8_t)(machine->regs.h.al >> i) & 1u; + bit_write(machine->regs.d.eflags, 1u << PARITY_FLAG_BIT, ((parrity % 2 == 0) ? 1: 0)); //PARRITY FLAG + /* uint8_t parrity = machine->regs.h.al & 1u; for(uint8_t i = 1; i < 8; i++) parrity ^= (uint8_t)(machine->regs.h.al >> i) & 1u; - bit_write(machine->regs.d.eflags, 1u <regs.d.eflags, 1u < regs.d.eflags, 1u <regs.h.al == 0); //ZERO FLAG bit_write(machine->regs.d.eflags, 1u <regs.h.al >> (7u)); //SIGN FLAG diff --git a/os/kernel/src/v8086/operations/stack_operations.c b/os/kernel/src/v8086/operations/stack_operations.c index edeb5ce0..dd74bde5 100644 --- a/os/kernel/src/v8086/operations/stack_operations.c +++ b/os/kernel/src/v8086/operations/stack_operations.c @@ -35,12 +35,12 @@ int16_t pop_rm(v8086* machine) machine->internal_state.IPOffset += 1; uint8_t width = 16; if(machine->internal_state.operand_32_bit) width = 32; - + uint32_t temp = width == 16 ? pop_word(machine) : pop_dword(machine); void* dest = get_memory_from_mode(machine, mod_rm, width); if(width == 16) - *((uint16_t*)dest) = pop_word(machine); + *((uint16_t*)dest) = (uint16_t)temp; else - *((uint32_t*)dest) = pop_dword(machine); + *((uint32_t*)dest) = temp; return V8086_OK; } diff --git a/os/kernel/src/v8086/operations/string_operations.c b/os/kernel/src/v8086/operations/string_operations.c index d491a7be..1f67fb6a 100644 --- a/os/kernel/src/v8086/operations/string_operations.c +++ b/os/kernel/src/v8086/operations/string_operations.c @@ -225,7 +225,23 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.d.edi), width); else dest = get_variable_length_pointer(machine->Memory, get_absolute_address(*dest_segment, machine->regs.w.di), width); - if(width == 8){ + + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("cmpb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); + else if (width == 16) + __asm__ __volatile__("cmpw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); + else if (width == 32) + __asm__ __volatile__("cmpl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + + /*if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); } else if(width == 16){ @@ -245,6 +261,7 @@ uint16_t perform_cmps(v8086* machine, uint8_t width) bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + */ if(machine->internal_state.address_32_bit){ machine->regs.d.esi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); @@ -314,7 +331,23 @@ uint16_t perform_scas(v8086* machine, uint8_t width) else source = get_variable_length_pointer(machine->Memory, get_absolute_address(*source_segment, machine->regs.w.di), width); if(dest == NULL) return V8086_UNDEFINED_REGISTER; - if(width == 8){ + + uint16_t temp_flags = 0; + if (width == 8) + __asm__ __volatile__("cmpb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint8_t *) dest)), "c" (*((uint8_t *) source))); + else if (width == 16) + __asm__ __volatile__("cmpw %%cx, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint16_t *) dest)), "c" (*((uint16_t *) source))); + else if (width == 32) + __asm__ __volatile__("cmpl %%ecx, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags) : "a" (*((uint32_t *) dest)), "c" (*((uint32_t *) source))); + else return V8086_BAD_WIDTH; + bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << CARRY_FLAG_BIT, bit_get(temp_flags, 1u << CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << SIGN_FLAG_BIT, bit_get(temp_flags, 1u << SIGN_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << ZERO_FLAG_BIT, bit_get(temp_flags, 1u << ZERO_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << AUX_CARRY_FLAG_BIT, bit_get(temp_flags, 1u << AUX_CARRY_FLAG_BIT) != 0); + bit_write(machine->regs.w.flags, 1u << PARITY_FLAG_BIT, bit_get(temp_flags, 1u << PARITY_FLAG_BIT) != 0); + + /*if(width == 8){ dest_before = *((uint8_t*)dest); source_before = *((uint8_t*)source); } else if(width == 16){ @@ -334,6 +367,7 @@ uint16_t perform_scas(v8086* machine, uint8_t width) bit_write(machine-> regs.d.eflags, 1u <regs.d.eflags, 1u <> (width - 1u)); //SIGN FLAG bit_write(machine->regs.d.eflags, 1u <> (width - 1u)) != (dest_before >> (width - 1u)))); //OVERFLOW FLAG + */ if(machine->internal_state.address_32_bit) machine->regs.d.edi += bit_get(machine->regs.w.flags, 1u << DIRECTION_FLAG_BIT) ? -(width/8) : (width/8); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 3ecc10ee..6878ff9b 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - //#define DEBUG_V8086_INTERACTIVE + #define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; @@ -362,17 +362,25 @@ void v8086_set_386_instruction_set(v8086* machine) v8086* v8086_create_machine() { + vga_printstring("HERE\n"); v8086* machine = (v8086*) heap_kernel_alloc(sizeof(v8086), 0); + if(machine == NULL) vga_printstring("NULL \n"); + vga_printstring("NOT HERE\n"); if(machine == NULL) return NULL; + vga_printstring("HERE\n"); memset(machine, 0, sizeof(v8086)); + vga_printstring("NOT HERE\n"); machine->regs.x.flags = 0x2; machine->sregs.cs = 0xf000; machine->IP.w.ip = 0xfff0; machine->sregs.ss = 0x0; machine->regs.d.ebp = 0x7bff; machine->regs.d.esp = 0x7bff; + vga_printstring("HERE\n"); memcpy(machine->Memory, (void*)0xc0000000, 0x100000); + vga_printstring("NOT HERE\n"); v8086_set_8086_instruction_set(machine); + vga_printstring("HERE?\n"); return machine; } diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index b970f277..c328e83d 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -9,7 +9,7 @@ #define bit_set(p,m) ((p) |= (m)) #define bit_clear(p,m) ((p) &= ~(m)) #define bit_flip(p,m) ((p) ^= (m)) -#define bit_write(p,m,v) (v ? bit_set(p,m) : bit_clear(p,m)) +#define bit_write(p,m,v) ((v) ? bit_set(p,m) : bit_clear(p,m)) #define CARRY_FLAG_BIT 0u #define PARITY_FLAG_BIT 2u From f6a070274678d83a03b07b854170f4e1edc39d5c Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Fri, 23 Jul 2021 20:21:33 +0200 Subject: [PATCH 153/165] Corrections --- os/kernel/src/kernel.c | 11 +++++++++-- os/kernel/src/v8086/v8086.c | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 3dabbb32..22e75c45 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -476,7 +476,7 @@ int kmain() uint32_t stop = timer_get_system_clock(); list_timings[iiii++] = stop - start; - /*v8086_machine->regs.h.ah = 0x0; + v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x13; start = timer_get_system_clock(); statuses[iiii] = v8086_call_int(v8086_machine, 0x10); @@ -529,7 +529,7 @@ int kmain() v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x3; - v8086_call_int(v8086_machine, 0x10);*/ + v8086_call_int(v8086_machine, 0x10); video_card_set_video_mode(0x3); vga_clear_screen(); @@ -550,6 +550,13 @@ int kmain() itoa(statuses[ii], buff, 10); vga_printstring(buff); vga_newline(); + vga_printstring("CS: "); + itoa(v8086_machine->sregs.cs, buff, 16); + vga_printstring(buff); + vga_printstring(" IP: "); + itoa(v8086_machine->IP.w.ip, buff, 16); + vga_printstring(buff); + vga_newline(); } /*vga_printchar('x'); uint32_t s = timer_get_system_clock(); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 6878ff9b..8951e25d 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - #define DEBUG_V8086_INTERACTIVE + //#define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; @@ -202,6 +202,8 @@ void v8086_set_8086_instruction_set(v8086* machine) //NOT DEFINED IN 8086 processor ASSIGN_NULL(0xc8u); ASSIGN_NULL(0xc9u); + ASSIGN_OPCODE(0xcau, retf_imm); + ASSIGN_OPCODE(0xcbu, retf); GROUP_OF_OPCODES(0xccu, 0xceu, interrupt); ASSIGN_OPCODE(0xcfu, iret); GROUP_OF_OPCODES(0xd0u, 0xd3u, group_2); From d0cd41eef36136b41e4936a865ac1f13e8c4e6ce Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Sat, 24 Jul 2021 01:38:24 +0200 Subject: [PATCH 154/165] Fix things --- os/kernel/src/kernel.c | 2 +- .../v8086/operations/arithmetic_operations.c | 20 +++++++++++++------ os/kernel/src/v8086/v8086.c | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 22e75c45..61208ba6 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -462,7 +462,7 @@ int kmain() v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); - idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); + //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); uint8_t result_text[80]; uint32_t list_timings[8]; diff --git a/os/kernel/src/v8086/operations/arithmetic_operations.c b/os/kernel/src/v8086/operations/arithmetic_operations.c index a98e6b99..8934264d 100644 --- a/os/kernel/src/v8086/operations/arithmetic_operations.c +++ b/os/kernel/src/v8086/operations/arithmetic_operations.c @@ -150,12 +150,16 @@ int16_t perform_rol(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { int16_t perform_rcl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; if (arg == 0) return V8086_OK; + + __asm__("pushfw; pop %%bx" : "=b" (temp_flags)); + bit_write(temp_flags, 1u << CARRY_FLAG_BIT, (bit_get(machine->regs.w.flags, 1u << CARRY_FLAG_BIT) ? 1 : 0)); + if (width == 8) - __asm__ __volatile__("rclb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rclb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "b"(temp_flags), "c" (arg)); else if (width == 16) - __asm__ __volatile__("rclw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rclw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "b"(temp_flags), "c" (arg)); else if (width == 32) - __asm__ __volatile__("rcll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rcll %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "b"(temp_flags), "c" (arg)); else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); @@ -166,12 +170,16 @@ int16_t perform_rcl(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { int16_t perform_rcr(v8086 *machine, void *dest, uint8_t arg, uint8_t width) { uint16_t temp_flags; if (arg == 0) return V8086_OK; + + __asm__("pushfw; pop %%bx" : "=b" (temp_flags)); + bit_write(temp_flags, 1u << CARRY_FLAG_BIT, (bit_get(machine->regs.w.flags, 1u << CARRY_FLAG_BIT) ? 1 : 0)); + if (width == 8) - __asm__ __volatile__("rcrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rcrb %%cl, %%al; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint8_t *) dest)) : "a" (*((uint8_t *) dest)), "b"(temp_flags), "c" (arg)); else if (width == 16) - __asm__ __volatile__("rcrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rcrw %%cl, %%ax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint16_t *) dest)) : "a" (*((uint16_t *) dest)), "b"(temp_flags), "c" (arg)); else if (width == 32) - __asm__ __volatile__("rcrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "c" (arg)); + __asm__ __volatile__("push %%bx; popfw; rcrl %%cl, %%eax; pushfw; pop %%bx;" : "=b" (temp_flags), "=a" (*((uint32_t *) dest)) : "a" (*((uint32_t *) dest)), "b"(temp_flags), "c" (arg)); else return V8086_BAD_WIDTH; if (arg == 1) bit_write(machine->regs.w.flags, 1u << OVERFLOW_FLAG_BIT, bit_get(temp_flags, 1u << OVERFLOW_FLAG_BIT) != 0); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 8951e25d..bfd36ec6 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,7 +17,7 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - //#define DEBUG_V8086_INTERACTIVE + #define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; From d9140482e81a65aef4d6fc95a7fbcbaac3744847 Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Mon, 26 Jul 2021 01:49:39 +0200 Subject: [PATCH 155/165] Probably fixed another hardware problem with addressing --- os/kernel/src/kernel.c | 2 ++ os/kernel/src/v8086/mod_rm_parsing.c | 9 +++++---- os/kernel/src/v8086/v8086.c | 11 ++++++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 61208ba6..ee840d07 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -469,6 +469,8 @@ int kmain() int16_t statuses[8]; uint8_t iiii = 0; + setSkipDebugging(true); + v8086_machine->regs.h.ah = 0x0; v8086_machine->regs.h.al = 0x03; uint32_t start = timer_get_system_clock(); diff --git a/os/kernel/src/v8086/mod_rm_parsing.c b/os/kernel/src/v8086/mod_rm_parsing.c index c99bd954..5e99a03f 100644 --- a/os/kernel/src/v8086/mod_rm_parsing.c +++ b/os/kernel/src/v8086/mod_rm_parsing.c @@ -25,14 +25,15 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 segment_register = select_segment_register(machine, machine->internal_state.segment_reg_select); else { - if(((mod_rm & 7u) == 2) || ((mod_rm & 7u) == 3) || (((mod_rm & 7u) == 6) && ((mod_rm & 0xC0) == 0))){ + /*if(((mod_rm & 7u) == 2) || ((mod_rm & 7u) == 3) || (((mod_rm & 7u) == 6) && ((mod_rm & 0xC0) == 0))){ segment_register = select_segment_register(machine, V8086_SS); } else{ segment_register = select_segment_register(machine, V8086_DS); - } + }*/ + /*TODO: optimization screwed up on hardware*/ /*TODO: consider better optimization*/ - /*switch (mod_rm & 7u) + switch (mod_rm & 7u) { case 0: case 1: @@ -48,7 +49,7 @@ int16_t calculate_segment_offset_from_mode(v8086* machine, uint8_t mod_rm, uint1 default: segment_register = select_segment_register(machine, V8086_SS); break; - }*/ + } } if(segment_register == NULL) return V8086_UNDEFINED_SEGMENT_REGISTER; diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index bfd36ec6..dcc570af 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -17,12 +17,13 @@ #include "../drivers/vga/vga.h" //#define DEBUG_V8086_TEXT //#define DEBUG_V8086_BIN - #define DEBUG_V8086_INTERACTIVE + //#define DEBUG_V8086_INTERACTIVE #endif bool skipDebugging = false; int16_t parse_and_execute_instruction(v8086* machine); +uint8_t loop_flag = 0; #ifdef DEBUG_V8086 void send_reg_32(uint32_t reg) @@ -659,6 +660,14 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.previous_byte_was_prefix = 0; goto decode; } + + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0xaa5b && loop_flag == 0) {loop_flag = 1;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x36db && loop_flag == 1) {loop_flag = 2;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x3817 && loop_flag == 2) {loop_flag = 3;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0xa9c8 && loop_flag == 3) {loop_flag = 4;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 4) {setSkipDebugging(false); loop_flag = 5;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x52a8 && loop_flag == 5) setSkipDebugging(false); + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x529c && loop_flag == 5) setSkipDebugging(true); #ifdef DEBUG_V8086 #ifdef DEBUG_V8086_TEXT From 84a655a2ebecafbb99c66008351510c275169e6a Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Tue, 27 Jul 2021 00:35:20 +0200 Subject: [PATCH 156/165] Add Enabling A20 line --- os/bootloader/src/bootloader.asm | 2 - os/kernel/src/init/startup.asm | 189 ++++++++++++++++++++++++++++++- 2 files changed, 183 insertions(+), 8 deletions(-) diff --git a/os/bootloader/src/bootloader.asm b/os/bootloader/src/bootloader.asm index 33ecac3f..6dace057 100644 --- a/os/bootloader/src/bootloader.asm +++ b/os/bootloader/src/bootloader.asm @@ -125,8 +125,6 @@ Main: ; Load all kernel sectors call LoadKernel - - ; Enter protected mode and jump to the loaded kernel call JumpToKernel diff --git a/os/kernel/src/init/startup.asm b/os/kernel/src/init/startup.asm index d4fb2ce7..18d5244d 100644 --- a/os/kernel/src/init/startup.asm +++ b/os/kernel/src/init/startup.asm @@ -102,8 +102,6 @@ gdt_description: dd gdt_begin main: - ;call realstr - ;hlt ; Load memory map before we will switch to the protected mode ; Buffer segment mov bx, 0x0000 @@ -113,8 +111,6 @@ main: mov bx, 0x5C00 mov di, bx - - call load_memory_map ;call realstr @@ -123,7 +119,56 @@ main: ; Load GDT table lgdt [dword gdt_description] - +; Check If Line A20 Enabled + call check_a20 + or ax, ax + jnz a20_enabled + +; Try Enable via BIOS + jmp enable_A20_BIOS + +; Check if Enabled via BIOS +a20_check_after_bios: + call check_a20 + or ax, ax + jnz a20_enabled + +; Not Enabled via BIOS. Try by Keyboard Controller +a20_bios_failed: + call enable_A20_keyboard + mov cx, 0x20 + +; Check if Enabled via Keyboard Controller +a20_keyboard_check: + call check_a20 + or ax, ax + jnz a20_enabled + dec cx + jnz a20_keyboard_check + +; Not Enabled via Keyboard Controller, Try Fast A20 +a20_keyboard_failed: + in al, 0x92 + or al, 2 + out 0x92, al + mov cx, 0x20 + +; Check if enabled via Fast A20 +a20_fast_a20_check: + call check_a20 + or ax, ax + jnz a20_enabled + dec cx + jnz a20_fast_a20_check + +; Not Enabled via A20. No idea what to do here + call realstr + cli + hlt + +; Enabled Line A20 +a20_enabled: + ;call realstr ; Set protected mode flag mov eax, cr0 @@ -178,6 +223,122 @@ load_memory_map: mov [di], eax ret + +check_a20: + pushf + push ds + push es + push di + push si + + cli + + xor ax, ax ; ax = 0 + mov es, ax + + not ax ; ax = 0xFFFF + mov ds, ax + + mov di, 0x0500 + mov si, 0x0510 + + mov al, byte [es:di] + push ax + + mov al, byte [ds:si] + push ax + + mov byte [es:di], 0x00 + mov byte [ds:si], 0xFF + + cmp byte [es:di], 0xFF + + pop ax + mov byte [ds:si], al + + pop ax + mov byte [es:di], al + + mov ax, 0 + je check_a20__exit + + mov ax, 1 + +check_a20__exit: + pop si + pop di + pop es + pop ds + popf + + ret + +enable_A20_BIOS: + mov ax,2403h ;--- A20-Gate Support --- + int 15h + jb a20_bios_failed ;INT 15h is not supported + cmp ah,0 + jnz a20_bios_failed ;INT 15h is not supported + + mov ax,2402h ;--- A20-Gate Status --- + int 15h + jb a20_bios_failed ;couldn't get status + cmp ah,0 + jnz a20_bios_failed ;couldn't get status + + cmp al,1 + jz a20_enabled ;A20 is already activated + + mov ax,2401h ;--- A20-Gate Activate --- + int 15h + jb a20_bios_failed ;couldn't activate the gate + cmp ah,0 + jnz a20_bios_failed ;couldn't activate the gate + +enable_A20_keyboard: + cli + + call a20wait + mov al,0xAD + out 0x64,al + + call a20wait + mov al,0xD0 + out 0x64,al + + call a20wait2 + in al,0x60 + push eax + + call a20wait + mov al,0xD1 + out 0x64,al + + call a20wait + pop eax + or al,2 + out 0x60,al + + call a20wait + mov al,0xAE + out 0x64,al + + call a20wait + sti + ret + +a20wait: + in al,0x64 + test al,2 + jnz a20wait + ret + + +a20wait2: + in al,0x64 + test al,1 + jz a20wait2 + ret [BITS 32] main_protected_area: @@ -189,13 +350,25 @@ main_protected_area: mov gs, ax mov ss, ax + ;call protstr + ;cli + ;hlt + call clear_page_directory + ;call protstr + ;cli + ;hlt + call clear_page_tables + ;call protstr + ;cli + ;hlt + call create_page_directory call create_identity_page_table call create_kernel_page_table - call enable_paging + call enable_paging ; Set new stack with virtual address mov eax, 0xC1100000 @@ -246,6 +419,10 @@ clear_page_tables: cmp eax, 0x400000 jl clear_page_tables_loop + ;;call protstr + ;;cli + ;;hlt + ret ; Input: nothing From 4648d50cabe0c81694c4f5021121634765b49476 Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Thu, 29 Jul 2021 22:19:08 +0200 Subject: [PATCH 157/165] Fixed bootloop in startup --- os/kernel/src/init/startup.asm | 76 +++++++++++++++++++++++++++++----- os/kernel/src/kernel.c | 21 +++++----- os/kernel/src/v8086/v8086.c | 7 ++-- 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/os/kernel/src/init/startup.asm b/os/kernel/src/init/startup.asm index 18d5244d..581ad74f 100644 --- a/os/kernel/src/init/startup.asm +++ b/os/kernel/src/init/startup.asm @@ -32,6 +32,36 @@ realstr: ret +realstr2: + + mov ax, 0xb800 + mov es, ax + mov ax, 0xf941 + mov ecx, 10 + xor edi, edi + rep stosw + + ret + +realstr_status: + + mov al, ah + xor ah, ah + mov bl, 64 + div bl + xchg ah, al + add ah, 0x09 + add al, 48 + + mov bx, 0xb800 + mov es, bx + ;mov ax, 0x0c41 + mov ecx, 10 + xor edi, edi + rep stosw + + ret + ; Entry frame: https://wiki.osdev.org/GDT gdt_begin: ; Null segment, reserved by CPU @@ -123,9 +153,20 @@ main: call check_a20 or ax, ax jnz a20_enabled + ;jnz a20_check_true ; Try Enable via BIOS jmp enable_A20_BIOS + ;call realstr + ;jmp a20_check_false + +;a20_check_true: +; call realstr2 + +;a20_check_false: + +; cli +; hlt ; Check if Enabled via BIOS a20_check_after_bios: @@ -136,30 +177,31 @@ a20_check_after_bios: ; Not Enabled via BIOS. Try by Keyboard Controller a20_bios_failed: call enable_A20_keyboard - mov cx, 0x20 + ;mov cx, 0x20 ; Check if Enabled via Keyboard Controller a20_keyboard_check: call check_a20 or ax, ax jnz a20_enabled - dec cx - jnz a20_keyboard_check + ;dec cx + ;jnz a20_keyboard_check + ; Not Enabled via Keyboard Controller, Try Fast A20 a20_keyboard_failed: in al, 0x92 or al, 2 out 0x92, al - mov cx, 0x20 + ;mov cx, 0x20 ; Check if enabled via Fast A20 a20_fast_a20_check: call check_a20 or ax, ax jnz a20_enabled - dec cx - jnz a20_fast_a20_check + ;dec cx + ;jnz a20_fast_a20_check ; Not Enabled via A20. No idea what to do here call realstr @@ -169,7 +211,6 @@ a20_fast_a20_check: ; Enabled Line A20 a20_enabled: ;call realstr - ; Set protected mode flag mov eax, cr0 or eax, 1 @@ -273,15 +314,22 @@ check_a20__exit: ret +halt_a20: + call realstr_status + cli + hlt + enable_A20_BIOS: mov ax,2403h ;--- A20-Gate Support --- int 15h + ;cmp ah, 0x86 jb a20_bios_failed ;INT 15h is not supported cmp ah,0 jnz a20_bios_failed ;INT 15h is not supported mov ax,2402h ;--- A20-Gate Status --- int 15h + ;jmp halt_a20 jb a20_bios_failed ;couldn't get status cmp ah,0 jnz a20_bios_failed ;couldn't get status @@ -342,6 +390,9 @@ a20wait2: [BITS 32] main_protected_area: + ;call protstr + cli + ;hlt ; Set data and stack segments to the third GDI descriptor mov ax, 0x10 mov ds, ax @@ -350,9 +401,7 @@ main_protected_area: mov gs, ax mov ss, ax - ;call protstr - ;cli - ;hlt + call clear_page_directory ;call protstr @@ -369,7 +418,7 @@ main_protected_area: call create_identity_page_table call create_kernel_page_table call enable_paging - + ; Set new stack with virtual address mov eax, 0xC1100000 mov esp, eax @@ -377,6 +426,11 @@ main_protected_area: ; Init FPU finit + ;call protstr + ;cli + ;hlt + + ; Jump to kmain and start kernel work extern kmain call kmain diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index ee840d07..35c12d1d 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -277,7 +277,7 @@ void startup() // NOTE: it doesn't work well, so assume for now that floppy controller is always present // if(fdc_is_present()) { - //fdc_init(); + fdc_init(); logger_log_ok("Floppy Disc Controller"); } @@ -288,7 +288,7 @@ void startup() keyboard_init(); logger_log_ok("Keyboard"); - //partitions_init(); + partitions_init(); logger_log_ok("Partitions"); tss_init(); @@ -409,7 +409,7 @@ int kmain() // create_terminal(&d); // create_terminal(&d); uint32_t d = 0; - /*for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { char args[16]; itoa(i, args, 10); @@ -420,18 +420,18 @@ int kmain() uint32_t terminal_number = i; const terminal_struct* ts = get_terminals(&terminal_number); attach_process_to_terminal(ts[i].terminal_id, process_manager_get_process(p)); - }*/ + } vga_clear_screen(); - //switch_active_terminal(0); + switch_active_terminal(0); - //process_manager_run(); - keyboard_scan_ascii_pair kb; - vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); - while(!keyboard_get_key_from_buffer(&kb)); + process_manager_run(); + //keyboard_scan_ascii_pair kb; + //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); + //while(!keyboard_get_key_from_buffer(&kb)); - serial_init(COM1_PORT, 115200, 8, 1, PARITY_NONE); + //serial_init(COM1_PORT, 115200, 8, 1, PARITY_NONE); // v8086_machine = v8086_create_machine(); // v8086_set_386_instruction_set(v8086_machine); @@ -460,6 +460,7 @@ int kmain() } }*/ +/* v8086_machine = v8086_create_machine(); v8086_set_386_instruction_set(v8086_machine); //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index dcc570af..9e13b318 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -665,9 +665,10 @@ int16_t parse_and_execute_instruction(v8086* machine) if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x36db && loop_flag == 1) {loop_flag = 2;} if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x3817 && loop_flag == 2) {loop_flag = 3;} if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0xa9c8 && loop_flag == 3) {loop_flag = 4;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 4) {setSkipDebugging(false); loop_flag = 5;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x52a8 && loop_flag == 5) setSkipDebugging(false); - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x529c && loop_flag == 5) setSkipDebugging(true); + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 4) {loop_flag = 5;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 5) {setSkipDebugging(false); loop_flag = 6;} + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x52a8 && loop_flag == 6) setSkipDebugging(false); + if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x529c && loop_flag == 6) setSkipDebugging(true); #ifdef DEBUG_V8086 #ifdef DEBUG_V8086_TEXT From 98d216016a16a9115eec8783e97d644a7558f47e Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Thu, 29 Jul 2021 22:56:27 +0200 Subject: [PATCH 158/165] Fixed problem with Fesz's floppy boot --- os/kernel/src/drivers/floppy/floppy.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index 0d161702..c99c46d4 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -88,8 +88,29 @@ bool floppy_reset() { // Disable floppy controller io_out_byte(FLOPPY_DIGITAL_OUTPUT_REGISTER, 0); + + uint32_t before = timer_get_system_clock(); + + while(1) + { + if(timer_get_system_clock() - before > 10) + { + break; + } + } // Enable floppy controller (reset (0x04) | DMA (0x08)) + io_out_byte(FLOPPY_DIGITAL_OUTPUT_REGISTER, 0x04); + + before = timer_get_system_clock(); + while(1) + { + if(timer_get_system_clock() - before > 10) + { + break; + } + } + io_out_byte(FLOPPY_DIGITAL_OUTPUT_REGISTER, 0x0C); // Wait for interrupt and continue reset sequence @@ -102,6 +123,10 @@ bool floppy_reset() uint8_t st0, cylinder; floppy_confirm_interrupt(&st0, &cylinder); + uint8_t tmp[8]; + itoa(st0, tmp, 16); + logger_log_info(tmp); + if (st0 != 0xC0) { return false; From b9de433004c042a568e789e2b83cb42acdd181f8 Mon Sep 17 00:00:00 2001 From: Jakub Szatkowski Date: Mon, 9 Aug 2021 22:59:35 +0200 Subject: [PATCH 159/165] Clearing Debug Stuff --- os/kernel/src/kernel.c | 284 +----------------------------------- os/kernel/src/v8086/v8086.c | 9 -- os/kernel/src/v8086/v8086.h | 2 +- 3 files changed, 2 insertions(+), 293 deletions(-) diff --git a/os/kernel/src/kernel.c b/os/kernel/src/kernel.c index 35c12d1d..48e4a075 100644 --- a/os/kernel/src/kernel.c +++ b/os/kernel/src/kernel.c @@ -42,10 +42,6 @@ #include "debug_helpers/library/kernel_stdio.h" -#ifdef TEST_V8086 -#include "v8086/tests/tests.h" -#endif - typedef struct _linesStruct { uint16_t ax; @@ -390,9 +386,6 @@ void v8086_BIOS_timer_interrupt() int kmain() { - //uint16_t* vga_ptr = VGA_MODE_03H_BASE_ADDR; - //vga_ptr[0] = 0xf041; - //while(1); clear_bss(); startup(); @@ -402,12 +395,8 @@ int kmain() //startup_music_play(); logger_log_ok("READY."); - //while (1); - logger_log_ok("Loading shells..."); - // create_terminal(&d); - // create_terminal(&d); uint32_t d = 0; for (int i = 0; i < 4; i++) { @@ -426,279 +415,8 @@ int kmain() switch_active_terminal(0); - process_manager_run(); - //keyboard_scan_ascii_pair kb; - //vga_printstring("Press key to continue... (Sending Debug Informations via serial)\n"); - //while(!keyboard_get_key_from_buffer(&kb)); - - //serial_init(COM1_PORT, 115200, 8, 1, PARITY_NONE); - -// v8086_machine = v8086_create_machine(); - // v8086_set_386_instruction_set(v8086_machine); - //v8086_machine->regs.x.ax = 0x3; - //int dupa = v8086_call_int(v8086_machine, 0x10); - - //video_card_set_video_mode(0x3); - - /*uint8_t pre_com[1024]; - memcpy(pre_com, v8086_machine -> Memory, 1024); - idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); - vga_printstring("Starting DOS Program\n"); - int16_t stat = v8086_call_com_program(v8086_machine, "A:/TC.COM"); - vga_printstring("OUT\n"); - uint8_t post_com[1024]; - memcpy(post_com, v8086_machine -> Memory, 1024); - //memcpy((uint8_t*) 0xc0000000 + 0xb8000, v8086_machine->Memory + 0xb8000, 0xFFFF); - - for(int i =0; i<1024; i++){ - uint8_t tmp[100]; - if(post_com[i]!=pre_com[i]){ - vga_printstring("Roznica: "); - itoa(i, tmp, 10); - vga_printstring(tmp); - vga_newline(); - } - }*/ - -/* - v8086_machine = v8086_create_machine(); - v8086_set_386_instruction_set(v8086_machine); - //idt_attach_interrupt_handler(0, v8086_BIOS_timer_interrupt); + process_manager_run(); - uint8_t result_text[80]; - uint32_t list_timings[8]; - int16_t statuses[8]; - uint8_t iiii = 0; - - setSkipDebugging(true); - - v8086_machine->regs.h.ah = 0x0; - v8086_machine->regs.h.al = 0x03; - uint32_t start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - uint32_t stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.h.ah = 0x0; - v8086_machine->regs.h.al = 0x13; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.h.ah = 0x0e; - v8086_machine->regs.h.al = 0x41; - v8086_machine->regs.h.bl = 0xf; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.h.ah = 0x0f; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.x.ax = 0x4f00; - v8086_machine->sregs.es = 0x0; - v8086_machine->regs.x.di = 0x7e00; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.x.ax = 0x4f01; - v8086_machine->sregs.es = 0x0; - v8086_machine->regs.x.di = 0x7e00; - v8086_machine->regs.x.cx = 0x13; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.x.ax = 0x4f02; - v8086_machine->regs.x.bx = 0x13; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.x.ax = 0x4f03; - start = timer_get_system_clock(); - statuses[iiii] = v8086_call_int(v8086_machine, 0x10); - stop = timer_get_system_clock(); - list_timings[iiii++] = stop - start; - - v8086_machine->regs.h.ah = 0x0; - v8086_machine->regs.h.al = 0x3; - v8086_call_int(v8086_machine, 0x10); - - video_card_set_video_mode(0x3); - vga_clear_screen(); - vga_color c; - c.color_without_blink.background=VGA_COLOR_BLACK; - c.color_without_blink.letter=VGA_COLOR_WHITE; - vga_set_color(0, 0, c); - - for(int ii = 0; ii < 8; ii++){ - //kernel_sprintf(result_text, "FUNKCJA %d: %d", ii, list_timings[ii]); - vga_printstring("FUNKCJA "); - itoa(ii, buff, 10); - vga_printstring(buff); - vga_printstring(": "); - itoa(list_timings[ii], buff, 10); - vga_printstring(buff); - vga_printstring(" status: "); - itoa(statuses[ii], buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("CS: "); - itoa(v8086_machine->sregs.cs, buff, 16); - vga_printstring(buff); - vga_printstring(" IP: "); - itoa(v8086_machine->IP.w.ip, buff, 16); - vga_printstring(buff); - vga_newline(); - } - /*vga_printchar('x'); - uint32_t s = timer_get_system_clock(); - while(timer_get_system_clock() - s < 10000); - vga_printchar('y');*/ - - #define FUN_9 - - #ifdef FUN_1 - mode13h_set_mode(); - drawLenaIn13H(); - #endif - - #ifdef FUN_2 - v8086* machine = v8086_create_machine(); - v8086_set_386_instruction_set(machine); - machine->regs.x.ax = 0x13; - v8086_call_int(machine, 0x10); - drawLenaIn13H(); - #endif - - - #ifdef FUN_3 - char buff[100]; - VBE_initialize(); - setSkipDebugging(true); - //VBE_set_video_mode(0x18c, false); - svga_mode_information mode_info; - //VBE_get_vesa_mode_information(&mode_info, 0x105); - VBEStatus status = VBE_check_existance_of_VESA(); - if(status != VBE_OK) - { - vga_printstring("Problems with VBE: \n"); - vga_printstring(itoa(status, buff, 10)); - vga_newline(); - } - svga_information* svga_info_ptr; - status = VBE_get_svga_information(&svga_info_ptr); - if(status == VBE_OK){ - vga_printstring(svga_info_ptr->signature); - vga_newline(); - vga_printstring(svga_info_ptr->producent_text); - vga_newline(); - vga_printstring("VESA VERSION: "); - itoa(svga_info_ptr->vesa_standard_number, buff, 16); - vga_printstring(buff); - vga_newline(); - vga_printstring("VESA NUMBER OF MODES: "); - itoa(svga_info_ptr->number_of_modes, buff, 10); - vga_printstring(buff); - vga_newline(); - uint16_t mode_number = 0; - uint32_t max_width = 0; - uint32_t max_height = 0; - uint16_t max_bit_per_pixel = 0; - uint32_t physBufforAddress = 0; - for(int i=0; i < svga_info_ptr->number_of_modes; i++) - //for(int i=0x11b; i < 0x11c; i++) - { - svga_mode_information mode_info; - status = VBE_get_vesa_mode_information(&mode_info, svga_info_ptr->mode_array[i]); - if(status != VBE_OK){ - itoa(svga_info_ptr->mode_array[i], buff, 16); - vga_printstring("Unable to get SVGA MODE INFORMATION: "); - vga_printstring(buff); - vga_newline(); - //while(!keyboard_get_key_from_buffer(&kb)); - } - else{ - physBufforAddress = mode_info.frame_buffor_phys_address; - /*if(mode_info.mode_height == 200 && mode_info.mode_width == 320 && mode_info.bits_per_pixel == 24) - { - mode_number = svga_info_ptr->mode_array[i]; - max_width = mode_info.mode_width; - max_height = mode_info.mode_height; - max_bit_per_pixel = mode_info.bits_per_pixel; - break; - }*/ - if((max_width * max_height) <= ((uint32_t)mode_info.mode_width * (uint32_t)mode_info.mode_height)) - { - if(max_bit_per_pixel <= mode_info.bits_per_pixel){ - mode_number = svga_info_ptr->mode_array[i]; - max_width = mode_info.mode_width; - max_height = mode_info.mode_height; - max_bit_per_pixel = mode_info.bits_per_pixel; - } - } - } - } - vga_printstring("BEST MODE: "); - itoa(mode_number, buff, 16); - vga_printstring(buff); - vga_newline(); - vga_printstring("MAX WIDTH: "); - itoa(max_width, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("MAX HEIGHT: "); - itoa(max_height, buff, 10); - vga_printstring(buff); - vga_newline(); - vga_printstring("BITS PER COLOR: "); - itoa(max_bit_per_pixel, buff, 10); - vga_printstring(buff); - vga_newline(); - - /*if(physBufforAddress != 0) - { - VBEStatus x = VBE_set_video_mode(0x10f|(1<<14), true); - VBE_set_current_bank(0); - paging_map_page(physBufforAddress/0x400000, 12, false); - uint8_t* color = 12*0x400000 + 0xc00000000; - drawLenaIn10fH_linear(color); - paging_unmap_page(12); - }*/ - } - else{ - vga_printstring("Unable to get SVGA INFORMATION\n"); - } - #endif - - #ifdef FUN_4 - VBE_initialize(); - VBEStatus x = VBE_set_video_mode(0x10f, true); - svga_mode_information mode_info; - VBE_get_vesa_mode_information(&mode_info, 0x10f); - VBE_display_window_control_set_16bit(0, 0); - for(int yy = 0; yy < 200; yy++) - for(int xx = 0; xx < 320; xx++) - VBE_draw_pixel_8_8_8(mode_info.mode_width, mode_info.mode_height, mode_info.windows_size, mode_info.granularity, xx, yy, 0, 0, 255); - - #endif - - #ifdef FUN_5 - VBE_initialize(); - VBEStatus x = VBE_set_video_mode(0x10f, true); - VBE_display_window_control_set_16bit(0, 0); - drawLenaIn10fH(); - #endif while (1); return 0; } diff --git a/os/kernel/src/v8086/v8086.c b/os/kernel/src/v8086/v8086.c index 9e13b318..37855fec 100644 --- a/os/kernel/src/v8086/v8086.c +++ b/os/kernel/src/v8086/v8086.c @@ -660,15 +660,6 @@ int16_t parse_and_execute_instruction(v8086* machine) machine->internal_state.previous_byte_was_prefix = 0; goto decode; } - - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0xaa5b && loop_flag == 0) {loop_flag = 1;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x36db && loop_flag == 1) {loop_flag = 2;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x3817 && loop_flag == 2) {loop_flag = 3;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0xa9c8 && loop_flag == 3) {loop_flag = 4;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 4) {loop_flag = 5;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x23e0 && loop_flag == 5) {setSkipDebugging(false); loop_flag = 6;} - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x52a8 && loop_flag == 6) setSkipDebugging(false); - if(machine->sregs.cs == 0xc000 && machine->IP.w.ip == 0x529c && loop_flag == 6) setSkipDebugging(true); #ifdef DEBUG_V8086 #ifdef DEBUG_V8086_TEXT diff --git a/os/kernel/src/v8086/v8086.h b/os/kernel/src/v8086/v8086.h index c328e83d..36f319d9 100644 --- a/os/kernel/src/v8086/v8086.h +++ b/os/kernel/src/v8086/v8086.h @@ -20,7 +20,7 @@ #define DIRECTION_FLAG_BIT 10u #define OVERFLOW_FLAG_BIT 11u -#define DEBUG_V8086 +//#define DEBUG_V8086 //#define TEST_V8086 typedef enum _segment_register_select { From 40cf3156387fcaacb0f7198449964b10a5dc27fe Mon Sep 17 00:00:00 2001 From: Jakub Przystasz Date: Tue, 12 Oct 2021 21:14:59 +0000 Subject: [PATCH 160/165] WTF? --- os/kernel/src/init/startup.asm | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/os/kernel/src/init/startup.asm b/os/kernel/src/init/startup.asm index 581ad74f..8076e06d 100644 --- a/os/kernel/src/init/startup.asm +++ b/os/kernel/src/init/startup.asm @@ -143,15 +143,19 @@ main: call load_memory_map - ;call realstr - ;hlt - ; Load GDT table lgdt [dword gdt_description] +; OK +; call realstr + ; Check If Line A20 Enabled call check_a20 + + call realstr + or ax, ax + jnz a20_enabled ;jnz a20_check_true @@ -168,6 +172,7 @@ main: ; cli ; hlt + ; Check if Enabled via BIOS a20_check_after_bios: call check_a20 @@ -315,6 +320,13 @@ check_a20__exit: ret halt_a20: + + mov ah, 0Ah + mov al, 'b' + mov bh, 0 + mov cx, 3 + int 10h + call realstr_status cli hlt From 32cab9ef1205eb344b6ba599f0ba7f00ee7e5eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Wojto=C5=84?= Date: Fri, 29 Oct 2021 17:49:29 +0200 Subject: [PATCH 161/165] Patch list: * startup.asm + Fixed booting on VirtualBox * DMA + Changed DMA init transfer to include data length *Streams + Increased chunk size in streams to 20KiB + Fixed setting filename of stream (lack of null termination) * Floppy + added floppy_read_sectors + added floppy_track_from_floppy + added floppy_read_continuous * partitions + changed read from device function to floppy_read_continous from floppy_read_sector * FAT + Added ability to read many sectors with one call * HEAP + Fixed heap_realloc (not checking if given pointer is NULL) * VitrualBox IS NOW RUNNING --- library/src/stdio/streams/file_stream.c | 2 +- library/src/stdio/streams/file_stream.h | 2 +- os/kernel/src/cpu/dma/dma.c | 6 +- os/kernel/src/cpu/dma/dma.h | 2 +- os/kernel/src/drivers/floppy/floppy.c | 327 +++++++++++++++++- os/kernel/src/drivers/floppy/floppy.h | 4 + os/kernel/src/filesystems/fat/fat.c | 52 +-- .../src/filesystems/partitions/partition.h | 2 +- .../src/filesystems/partitions/partitions.c | 2 +- os/kernel/src/init/startup.asm | 19 +- os/kernel/src/memory/heap/heap.c | 2 + 11 files changed, 373 insertions(+), 47 deletions(-) diff --git a/library/src/stdio/streams/file_stream.c b/library/src/stdio/streams/file_stream.c index 7876947c..031b077c 100644 --- a/library/src/stdio/streams/file_stream.c +++ b/library/src/stdio/streams/file_stream.c @@ -29,7 +29,7 @@ FILE *streams_set_stream_as_file(const char *filename, const char *mode, FILE *s stream->fetch = streams_file_fetch; stream->flush = streams_file_flush; - memcpy(stream->filename, filename, strlen(filename)); + memcpy(stream->filename, filename, strlen(filename)+1); return stream; } diff --git a/library/src/stdio/streams/file_stream.h b/library/src/stdio/streams/file_stream.h index 2d5a8569..3e3b6ec8 100644 --- a/library/src/stdio/streams/file_stream.h +++ b/library/src/stdio/streams/file_stream.h @@ -1,7 +1,7 @@ #ifndef FILE_STREAM_H #define FILE_STREAM_H -#define CHUNK_SIZE 512 +#define CHUNK_SIZE 20480 #include #include "../../stdio.h" diff --git a/os/kernel/src/cpu/dma/dma.c b/os/kernel/src/cpu/dma/dma.c index 096cf660..10cda903 100644 --- a/os/kernel/src/cpu/dma/dma.c +++ b/os/kernel/src/cpu/dma/dma.c @@ -7,7 +7,7 @@ void dma_init(uint32_t buffer_address) dma_buffer_address = buffer_address; } -void dma_init_transfer(uint8_t channel, bool read) +void dma_init_transfer(uint8_t channel, bool read, uint16_t dataLen) { // Tell DMA that we want to configure floppy (channel 2) io_out_byte(DMA_SINGLE_CHANNEL_MASK_REGISTER, channel); @@ -23,8 +23,8 @@ void dma_init_transfer(uint8_t channel, bool read) io_out_byte(DMA_FLIP_FLOP_RESET_REGISTER, 0xff); // Count to 0x01ff (number of bytes in a 3.5" floppy disk track) - io_out_byte(DMA_COUNT_REGISTER_CHANNEL, (0xff)); - io_out_byte(DMA_COUNT_REGISTER_CHANNEL, 0x01); + io_out_byte(DMA_COUNT_REGISTER_CHANNEL, ((dataLen-1) & 0xff)); + io_out_byte(DMA_COUNT_REGISTER_CHANNEL, (((dataLen-1) >> 8 ) & 0xff)); // We don't want to have external page register io_out_byte(DMA_EXTERNAL_PAGE_REGISTER, 0); diff --git a/os/kernel/src/cpu/dma/dma.h b/os/kernel/src/cpu/dma/dma.h index d5d9cab8..204f05b6 100644 --- a/os/kernel/src/cpu/dma/dma.h +++ b/os/kernel/src/cpu/dma/dma.h @@ -12,7 +12,7 @@ #define DMA_MODE_REGISTER 0x0B void dma_init(uint32_t buffer_address); -void dma_init_transfer(uint8_t channel, bool read); +void dma_init_transfer(uint8_t channel, bool read, uint16_t dataLen); uint8_t *dma_get_buffer(); #endif \ No newline at end of file diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index c99c46d4..980cc98b 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -304,12 +304,10 @@ uint8_t *floppy_do_operation_on_sector(uint8_t head, uint8_t track, uint8_t sect floppy_enable_motor(); //sleep(500); - - for (int i = 0; i < 10; i++) { // Init DMA - dma_init_transfer(0x06, read); + dma_init_transfer(0x06, read, 512); if (!floppy_seek(track, head)) { @@ -528,4 +526,325 @@ bool floppy_timer_interrupt() } return false; -} \ No newline at end of file +} + +uint8_t* floppy_read_continous(int device_number, int sector, int count){ + uint8_t* buffer = heap_kernel_alloc(count*512, 0); + size_t offset = 0; + uint8_t starting_head, starting_track, starting_true_sector; + uint8_t head, track, true_sector; + + floppy_lba_to_chs(sector, &starting_head, &starting_track, &starting_true_sector); + if (starting_true_sector != 1) + { + if (count < 18-starting_true_sector+1) + { + offset += count; + } + else + { + offset += 18-starting_true_sector+1; + } + uint8_t* tmp = floppy_read_sectors(device_number, starting_head, starting_track, starting_true_sector, offset); + memcpy(buffer, tmp, offset*512); + } + + for (; offset < count; offset+=18) + { + floppy_lba_to_chs(sector+offset, &head, &track, &true_sector); + if (offset+18 <= count) + { + if(true_sector != 1) vga_printstring("DUPA"); + uint8_t* tmp = read_track_from_floppy(device_number, head, track); + //uint8_t* tmp = floppy_read_sectors(device_number, head, track, true_sector, 18); + memcpy(buffer+(offset*512), tmp, 18*512); + } + else + { + uint8_t* tmp = floppy_read_sectors(device_number, head, track, true_sector, count-offset); + memcpy(buffer+(offset*512), tmp, (count-offset)*512); + } + } + return buffer; +} + +uint8_t* floppy_read_sectors(int device_number, uint8_t head, uint8_t track, uint8_t sector, uint32_t count) +{ + //logger_log_info("DUPA CONT"); + if (sector-1 + count > 18) + { + return NULL; + } + // Run floppy motor and wait some time + floppy_enable_motor(); + //sleep(500); + + for (int i = 0; i < 10; i++) + { + // Init DMA + dma_init_transfer(0x06, true, (count*512)); + + if (!floppy_seek(track, head)) + { + logger_log_warning("[FLOPPY] SEEK failed"); + sleep(10); + continue; + } + + // Send command to read sector + // 0x06 - read sector command + // 0x40 - double density mode + // 0x80 - operate on both tracks of the cylinder + floppy_send_command(0x06| 0x40 | 0x80); + + // _ _ _ _ _ HEAD DEV1 DEV2 + floppy_send_command(head << 2 | DEVICE_NUMBER); + + // Track number + floppy_send_command(track); + + // Head number + floppy_send_command(head); + + // Sector number + floppy_send_command(sector); + + // Sector size (2 = 512) + floppy_send_command(2); + + // uint8_t x[80]; + // kernel_sprintf(x, "%d, %d, %d, %d", track, head, sector, sector+count); + // logger_log_warning(x); + // Sectors per track + floppy_send_command(sector+count < 18 ? sector+count : 18); + //floppy_send_command(sectors_per_track); + + // Length of gap (0x1B = floppy 3,5) + floppy_send_command(0x1B); + + // Data length + floppy_send_command(0xff); + + // Wait for interrupt + if(!floppy_wait_for_interrupt()) + { + return false; + } + + // Read command status + /*uint8_t st0 =*/ floppy_read_data(); + uint8_t st1 = floppy_read_data(); + uint8_t st2 = floppy_read_data(); + /*uint8_t cylinder_data =*/ floppy_read_data(); + /*uint8_t head_data =*/ floppy_read_data(); + /*uint8_t sector_data =*/ floppy_read_data(); + uint8_t bps = floppy_read_data(); + + if (st1 & 0x80) + { + logger_log_error("[Floppy] End of cylinder"); + } + if (st1 & 0x20) + { + logger_log_error("[Floppy] Data error"); + } + if (st1 & 0x04) + { + logger_log_error("[Floppy] No data"); + } + if (st1 & 0x02) + { + logger_log_error("[Floppy] Not writable"); + } + if (st1 & 0x01) + { + logger_log_error("[Floppy] Missing address mark"); + } + + if (st2 & 0x40) + { + logger_log_error("[Floppy] Control mask"); + } + if (st2 & 0x20) + { + logger_log_error("[Floppy] Data error in data field"); + } + if (st2 & 0x10) + { + logger_log_error("[Floppy] Wrong cylinder"); + } + if (st2 & 0x02) + { + logger_log_error("[Floppy] Bad cylinder"); + } + if (st2 & 0x01) + { + logger_log_error("[Floppy] Missing data address mark"); + } + + if (bps != 0x2) + { + logger_log_error("[Floppy] Invalid bps"); + } + + if (st1 != 0 || st2 != 0) + { + for (int i = 0; i < 10; i++) + { + if (!floppy_calibrate()) + { + sleep(10); + logger_log_warning("[FLOPPY] Calibration failed"); + + if (i + 1 == 10) + { + return false; + } + } + else{break;} + } + + sleep(100); + continue; + } + return st1 == 0 ? (uint8_t *)dma_get_buffer() : NULL; + } + return NULL; +} + +uint8_t* read_track_from_floppy(int device_number, int head, int track) +{ + // Run floppy motor and wait some time + floppy_enable_motor(); + //sleep(500); + + for (int i = 0; i < 10; i++) + { + // Init DMA + dma_init_transfer(0x06, true, 0x2400); + + if (!floppy_seek(track, head)) + { + logger_log_warning("[FLOPPY] SEEK failed"); + sleep(10); + continue; + } + + // Send command to read sector + // 0x02 - read entire track + // 0x40 - double density mode + // can operate only on one track of the cylinder + floppy_send_command(0x02 | 0x40); + + // _ _ _ _ _ HEAD DEV1 DEV2 + floppy_send_command(head << 2 | DEVICE_NUMBER); + + // Track number + floppy_send_command(track); + + // Head number + floppy_send_command(head); + + // Sector number - ignored by read track command + floppy_send_command(1); + + // Sector size (2 = 512) + floppy_send_command(2); + + uint8_t sectors_per_track = floppy_sectors_per_track; + + // Sectors per track, technically should be ignored by read track command + floppy_send_command(sectors_per_track); + + // Length of gap (0x1B = floppy 3,5) + floppy_send_command(0x1B); + + // Data length + floppy_send_command(0xff); + + // Wait for interrupt + if(!floppy_wait_for_interrupt()) + { + return false; + } + + // Read command status + /*uint8_t st0 =*/ floppy_read_data(); + uint8_t st1 = floppy_read_data(); + uint8_t st2 = floppy_read_data(); + /*uint8_t cylinder_data =*/ floppy_read_data(); + /*uint8_t head_data =*/ floppy_read_data(); + /*uint8_t sector_data =*/ floppy_read_data(); + uint8_t bps = floppy_read_data(); + + if (st1 & 0x80) + { + logger_log_error("[Floppy] End of cylinder"); + } + if (st1 & 0x20) + { + logger_log_error("[Floppy] Data error"); + } + if (st1 & 0x04) + { + logger_log_error("[Floppy] No data"); + } + if (st1 & 0x02) + { + logger_log_error("[Floppy] Not writable"); + } + if (st1 & 0x01) + { + logger_log_error("[Floppy] Missing address mark"); + } + + if (st2 & 0x40) + { + logger_log_error("[Floppy] Control mask"); + } + if (st2 & 0x20) + { + logger_log_error("[Floppy] Data error in data field"); + } + if (st2 & 0x10) + { + logger_log_error("[Floppy] Wrong cylinder"); + } + if (st2 & 0x02) + { + logger_log_error("[Floppy] Bad cylinder"); + } + if (st2 & 0x01) + { + logger_log_error("[Floppy] Missing data address mark"); + } + + if (bps != 0x2) + { + logger_log_error("[Floppy] Invalid bps"); + } + + if (st1 != 0 || st2 != 0) + { + for (int i = 0; i < 10; i++) + { + if (!floppy_calibrate()) + { + sleep(10); + logger_log_warning("[FLOPPY] Calibration failed"); + + if (i + 1 == 10) + { + return false; + } + } + else{break;} + } + + sleep(100); + continue; + } + return st1 == 0 ? (uint8_t *)dma_get_buffer() : NULL; + } + return NULL; +} diff --git a/os/kernel/src/drivers/floppy/floppy.h b/os/kernel/src/drivers/floppy/floppy.h index 7c116a2f..d7829ab3 100644 --- a/os/kernel/src/drivers/floppy/floppy.h +++ b/os/kernel/src/drivers/floppy/floppy.h @@ -46,4 +46,8 @@ bool floppy_wait_for_interrupt(); bool floppy_interrupt(); bool floppy_timer_interrupt(); +uint8_t* floppy_read_continous(int device_number, int sector, int count); +uint8_t* floppy_read_sectors(int device_number, uint8_t head, uint8_t track, uint8_t sector, uint32_t count); +uint8_t* read_track_from_floppy(int device_number, int head, int track); + #endif \ No newline at end of file diff --git a/os/kernel/src/filesystems/fat/fat.c b/os/kernel/src/filesystems/fat/fat.c index 118b0e8e..9205fb78 100644 --- a/os/kernel/src/filesystems/fat/fat.c +++ b/os/kernel/src/filesystems/fat/fat.c @@ -45,7 +45,7 @@ void fat_load_fat() { uint16_t cluster_number = i + current_partition->first_sector; uint32_t fat_offset = (uint32_t)current_partition->fat + (i - current_partition->header->reserved_sectors) * current_partition->header->bytes_per_sector; - uint8_t *buffer = current_partition->read_from_device(current_partition->device_number, cluster_number); + uint8_t *buffer = current_partition->read_from_device(current_partition->device_number, cluster_number, 1); memcpy((void *)fat_offset, buffer, current_partition->header->bytes_per_sector); } @@ -83,7 +83,7 @@ void fat_load_root() vga_newline(); */ - uint8_t *buffer = current_partition->read_from_device(current_partition->device_number, cluster_number); + uint8_t *buffer = current_partition->read_from_device(current_partition->device_number, cluster_number, 1); memcpy((void *)root_offset, buffer, current_partition->header->bytes_per_sector); } } @@ -379,38 +379,50 @@ uint8_t *fat_read_file_from_cluster(uint16_t initial_cluster, uint16_t cluster_o } } - uint8_t *buffer = heap_kernel_alloc(current_partition->header->bytes_per_sector, 0); + uint8_t *buffer = NULL; *read_clusters = 0; while (*read_clusters < clusters_count && cluster < current_partition->last_valid_cluster_mark) { - int cluster_to_read = ((cluster - 2) * current_partition->header->sectors_per_cluster) + + int starting_cluster = ((cluster - 2) * current_partition->header->sectors_per_cluster) + current_partition->header->fat_count * current_partition->header->sectors_per_fat + current_partition->header->directory_entries * 32 / current_partition->header->bytes_per_sector + current_partition->header->reserved_sectors + current_partition->first_sector; - buffer = heap_kernel_realloc(buffer, current_partition->header->bytes_per_sector * (*read_clusters + 1) * current_partition->header->sectors_per_cluster, 0); + uint32_t counter = 1; + while (cluster + 1 == (cluster = fat_read_cluster_value(cluster))) + { + counter += 1; + } + + uint32_t sectors_to_read = counter*current_partition->header->sectors_per_cluster; + + buffer = heap_kernel_realloc(buffer, current_partition->header->bytes_per_sector * (*read_clusters + counter) * current_partition->header->sectors_per_cluster, 0); uint8_t *buffer_ptr = buffer + *read_clusters * current_partition->header->bytes_per_sector * current_partition->header->sectors_per_cluster; - for (int i = 0; i < current_partition->header->sectors_per_cluster; i++) - { - keyboard_scan_ascii_pair kb; - /*vga_newline(); - vga_printstring("Loading files... Press any key to test next file"); - vga_newline(); - while(!keyboard_get_key_from_buffer(&kb)); + //After read_from_device dealloc is needed at pointer received. + uint8_t *read_data = current_partition->read_from_device(current_partition->device_number, starting_cluster, sectors_to_read); + memcpy(buffer_ptr, read_data, sectors_to_read * current_partition->header->bytes_per_sector); + // for (int i = 0; i < current_partition->header->sectors_per_cluster; i++) + // { + // keyboard_scan_ascii_pair kb; + // /*vga_newline(); + // vga_printstring("Loading files... Press any key to test next file"); + // vga_newline(); + // while(!keyboard_get_key_from_buffer(&kb)); - logger_log_info("[FAT] Copy to buffer");*/ - uint8_t *read_data = current_partition->read_from_device(current_partition->device_number, cluster_to_read + i); - if(read_data == NULL) logger_log_error("[FAT] FLOPPY RETURN NULL!"); - memcpy(buffer_ptr, read_data, current_partition->header->bytes_per_sector); + // logger_log_info("[FAT] Copy to buffer");*/ + // uint8_t *read_data = current_partition->read_from_device(current_partition->device_number, cluster_to_read + i); + // if(read_data == NULL) logger_log_error("[FAT] FLOPPY RETURN NULL!"); + // memcpy(buffer_ptr, read_data, current_partition->header->bytes_per_sector); - buffer_ptr += current_partition->header->bytes_per_sector; - } + // buffer_ptr += current_partition->header->bytes_per_sector; + // } - cluster = fat_read_cluster_value(cluster); - (*read_clusters)++; + //cluster = fat_read_cluster_value(cluster); + (*read_clusters)+=counter; + heap_kernel_dealloc(read_data); } return buffer; diff --git a/os/kernel/src/filesystems/partitions/partition.h b/os/kernel/src/filesystems/partitions/partition.h index eddd4f8d..a6df373a 100644 --- a/os/kernel/src/filesystems/partitions/partition.h +++ b/os/kernel/src/filesystems/partitions/partition.h @@ -14,7 +14,7 @@ typedef struct partition device_type device_type; int device_number; void (*write_on_device)(int device_number, int sector, uint8_t *data); - uint8_t *(*read_from_device)(int device_number, int sector); + uint8_t *(*read_from_device)(int device_number, int sector, int count); uint8_t *fat; fat_directory_entry *root; diff --git a/os/kernel/src/filesystems/partitions/partitions.c b/os/kernel/src/filesystems/partitions/partitions.c index 2bca9fc1..7215df6e 100644 --- a/os/kernel/src/filesystems/partitions/partitions.c +++ b/os/kernel/src/filesystems/partitions/partitions.c @@ -30,7 +30,7 @@ void partitions_init_floppy() floppy_partition->device_type = device_type_floppy; floppy_partition->device_number = 0; floppy_partition->write_on_device = floppy_write_sector; - floppy_partition->read_from_device = floppy_read_sector; + floppy_partition->read_from_device = floppy_read_continous; floppy_partition->first_sector = 0; diff --git a/os/kernel/src/init/startup.asm b/os/kernel/src/init/startup.asm index 8076e06d..afad1a0c 100644 --- a/os/kernel/src/init/startup.asm +++ b/os/kernel/src/init/startup.asm @@ -143,19 +143,15 @@ main: call load_memory_map + ;call realstr + ;hlt + ; Load GDT table lgdt [dword gdt_description] -; OK -; call realstr - ; Check If Line A20 Enabled call check_a20 - - call realstr - or ax, ax - jnz a20_enabled ;jnz a20_check_true @@ -172,7 +168,6 @@ main: ; cli ; hlt - ; Check if Enabled via BIOS a20_check_after_bios: call check_a20 @@ -320,13 +315,6 @@ check_a20__exit: ret halt_a20: - - mov ah, 0Ah - mov al, 'b' - mov bh, 0 - mov cx, 3 - int 10h - call realstr_status cli hlt @@ -354,6 +342,7 @@ enable_A20_BIOS: jb a20_bios_failed ;couldn't activate the gate cmp ah,0 jnz a20_bios_failed ;couldn't activate the gate + jmp a20_check_after_bios enable_A20_keyboard: cli diff --git a/os/kernel/src/memory/heap/heap.c b/os/kernel/src/memory/heap/heap.c index bdd40d32..64f96014 100644 --- a/os/kernel/src/memory/heap/heap.c +++ b/os/kernel/src/memory/heap/heap.c @@ -164,6 +164,8 @@ uint32_t heap_get_object_size(void *ptr) void *heap_realloc(void *ptr, uint32_t size, uint32_t align, bool supervisor) { + if(ptr == NULL) return heap_alloc(size, align, supervisor); + uint32_t old_entry_size = ((heap_entry *)((uint32_t)ptr - ENTRY_HEADER_SIZE))->size; void *new_ptr = heap_alloc(size, align, supervisor); From b5ad810c89940218d1d28369a665c75807b7a37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Wojto=C5=84?= Date: Fri, 29 Oct 2021 18:56:19 +0200 Subject: [PATCH 162/165] Fixes ALOT of stuff (list will be added later) --- library/src/micros/micros_console.c | 10 + library/src/micros/micros_console.h | 4 + library/src/micros/micros_generic_vga.c | 5 + library/src/stdio/fgetc.c | 2 +- library/src/stdio/fread.c | 2 +- library/src/string.h | 4 +- os/kernel/src/cpu/panic/panic_screen.c | 18 +- .../src/drivers/dal/videocard/videocard.c | 5 + .../src/drivers/dal/videocard/videocard.h | 3 + os/kernel/src/drivers/vga/genericvga.c | 229 ++++++++++++++++-- os/kernel/src/drivers/vga/genericvga.h | 16 ++ .../src/drivers/vga/modes/mode_00h/mode_00h.c | 1 + .../src/drivers/vga/modes/mode_01h/mode_01h.c | 1 + .../src/drivers/vga/modes/mode_02h/mode_02h.c | 1 + .../src/drivers/vga/modes/mode_03h/mode_03h.c | 1 + .../src/drivers/vga/modes/mode_04h/mode_04h.c | 1 + .../src/drivers/vga/modes/mode_05h/mode_05h.c | 1 + .../src/drivers/vga/modes/mode_06h/mode_06h.c | 1 + .../src/drivers/vga/modes/mode_07h/mode_07h.c | 1 + .../src/drivers/vga/modes/mode_0dh/mode_0dh.c | 1 + .../src/drivers/vga/modes/mode_0eh/mode_0eh.c | 1 + .../src/drivers/vga/modes/mode_0fh/mode_0fh.c | 1 + .../src/drivers/vga/modes/mode_10h/mode_10h.c | 1 + .../src/drivers/vga/modes/mode_11h/mode_11h.c | 1 + .../src/drivers/vga/modes/mode_12h/mode_12h.c | 1 + .../src/drivers/vga/modes/mode_13h/mode_13h.c | 109 +++++++-- .../src/drivers/vga/modes/mode_13h/mode_13h.h | 15 ++ .../src/drivers/vga/modes/mode_y/mode_y.c | 1 + os/kernel/src/filesystems/fat/fat.c | 2 +- .../process/syscalls/handlers/generic_vga.c | 5 + .../process/syscalls/handlers/generic_vga.h | 3 + .../syscalls/handlers/terminal_calls.c | 10 + .../syscalls/handlers/terminal_calls.h | 3 + .../src/process/syscalls/syscalls_manager.c | 5 + os/kernel/src/terminal/terminal_manager.c | 8 + os/kernel/src/terminal/terminal_manager.h | 1 + 36 files changed, 416 insertions(+), 58 deletions(-) diff --git a/library/src/micros/micros_console.c b/library/src/micros/micros_console.c index 856e5b4c..5f90d329 100644 --- a/library/src/micros/micros_console.c +++ b/library/src/micros/micros_console.c @@ -46,4 +46,14 @@ void micros_console_clear() void micros_console_set_cursor_visibility(bool visibility) { micros_interrupt_1a(0x16, (uint32_t)visibility); +} + +void micros_console_set_video_mode(uint8_t mode) +{ + micros_interrupt_1a(0xE0, mode); +} + +void micros_console_copy_from_buffer(uint8_t* buffer, uint32_t how_many) +{ + micros_interrupt_2a(0xE1, (uint32_t)buffer, how_many); } \ No newline at end of file diff --git a/library/src/micros/micros_console.h b/library/src/micros/micros_console.h index fd1f418e..8dd34455 100644 --- a/library/src/micros/micros_console.h +++ b/library/src/micros/micros_console.h @@ -103,6 +103,10 @@ void micros_console_clear(); */ void micros_console_set_cursor_visibility(bool visibility); +//TODO document these +void micros_console_set_video_mode(uint8_t mode); +void micros_console_copy_from_buffer(uint8_t* buffer, uint32_t how_many); + #ifdef __cplusplus } #endif diff --git a/library/src/micros/micros_generic_vga.c b/library/src/micros/micros_generic_vga.c index d5d1cd2a..362fd4ed 100644 --- a/library/src/micros/micros_generic_vga.c +++ b/library/src/micros/micros_generic_vga.c @@ -13,4 +13,9 @@ bool micros_generic_vga_is_text_mode() uint16_t micros_generic_vga_get_current_video_mode() { return micros_interrupt_0a(0x19); +} + +uint8_t micros_generic_vga_is_vretrace() +{ + return micros_interrupt_0a(0x1A); } \ No newline at end of file diff --git a/library/src/stdio/fgetc.c b/library/src/stdio/fgetc.c index e80d4d8e..3cbaab43 100644 --- a/library/src/stdio/fgetc.c +++ b/library/src/stdio/fgetc.c @@ -10,5 +10,5 @@ int fgetc(FILE *stream) } } - return stream->buffer[stream->pos++ - stream->base]; + return (unsigned char)stream->buffer[stream->pos++ - stream->base]; } \ No newline at end of file diff --git a/library/src/stdio/fread.c b/library/src/stdio/fread.c index fabf2115..b05e78e4 100644 --- a/library/src/stdio/fread.c +++ b/library/src/stdio/fread.c @@ -2,7 +2,7 @@ size_t fread(void *ptr, size_t size, size_t count, FILE *stream) { - char c = fgetc(stream); + int c = fgetc(stream); int i = 0; int total_size = size * count; diff --git a/library/src/string.h b/library/src/string.h index d76c56eb..968138a6 100644 --- a/library/src/string.h +++ b/library/src/string.h @@ -1,8 +1,8 @@ #ifndef STRING_H #define STRING_H -#include -#include +#include "stdint.h" +#include "stddef.h" //! Unsigned integral type. typedef size_t uint32_t; diff --git a/os/kernel/src/cpu/panic/panic_screen.c b/os/kernel/src/cpu/panic/panic_screen.c index b6a47cc1..97db1f01 100644 --- a/os/kernel/src/cpu/panic/panic_screen.c +++ b/os/kernel/src/cpu/panic/panic_screen.c @@ -44,16 +44,16 @@ void panic_screen_show(exception_state *state, uint32_t code, const char *optStr void panic_screen_display_intro(exception_state *state, uint32_t code, const char *optString) { char buff[100]; - //if(vga_gmode_get_mode() != 0x3) + // if(vga_gmode_get_mode() != 0x3) // set3Hvideo_mode(); - //if(!video_card_is_text_mode()) - // video_card_set_video_mode(0x3); - //vga_clear_screen(); - //for (int i = 0; i < 20; i++) - //{ - // vga_printstring(img[i]); - // vga_printchar('\n'); - //} + if(!video_card_is_text_mode()) + video_card_set_video_mode(0x3); + vga_clear_screen(); + for (int i = 0; i < 20; i++) + { + vga_printstring(img[i]); + vga_printchar('\n'); + } vga_printstring("Robimy to z bolem serca, ale musimy Ciebie o tym poinformowac... Zjebalo sie.\n"); vga_printstring(panic_screen_value_to_string(buff, code)); vga_printchar(' '); diff --git a/os/kernel/src/drivers/dal/videocard/videocard.c b/os/kernel/src/drivers/dal/videocard/videocard.c index 4e072308..d417c4a5 100644 --- a/os/kernel/src/drivers/dal/videocard/videocard.c +++ b/os/kernel/src/drivers/dal/videocard/videocard.c @@ -478,4 +478,9 @@ uint8_t* video_card_create_external_buffer(uint16_t mode){ } void video_card_destroy_external_buffer(uint8_t* buffer){ return (*_destroy_external_buffer)(buffer); +} + +void video_card_set_swap_external_buffer(int8_t (*swap_external_buffer(uint8_t*, uint16_t))) +{ + _swap_external_buffer = swap_external_buffer; } \ No newline at end of file diff --git a/os/kernel/src/drivers/dal/videocard/videocard.h b/os/kernel/src/drivers/dal/videocard/videocard.h index 83983ae3..b8bb8720 100644 --- a/os/kernel/src/drivers/dal/videocard/videocard.h +++ b/os/kernel/src/drivers/dal/videocard/videocard.h @@ -301,6 +301,9 @@ int8_t video_card_set_char(uint16_t x, uint16_t y, char character); */ int8_t video_card_get_char(uint16_t x, uint16_t y, char* character); +//TODO add documentation +void video_card_set_swap_external_buffer(int8_t (*swap_external_buffer(uint8_t*, uint16_t))); + //! Set character color on given point on screen. /*! Set character color on given point on screen without changing letter. diff --git a/os/kernel/src/drivers/vga/genericvga.c b/os/kernel/src/drivers/vga/genericvga.c index 029f68c0..e8230aee 100644 --- a/os/kernel/src/drivers/vga/genericvga.c +++ b/os/kernel/src/drivers/vga/genericvga.c @@ -18,6 +18,8 @@ #include "modes/mode_y/mode_y.h" #include "memory/heap/heap.h" +#include "../../assembly/io.h" + video_mode current_video_mode; uint8_t text_mode; @@ -52,25 +54,25 @@ void generic_vga_driver_init() s.turn_cursor_on = mode03h_turn_cursor_on; s.turn_cursor_off = mode03h_turn_cursor_off; - s.print_char_external_buffer = mode03h_print_char_external_buffer; - s.print_char_color_external_buffer = mode03h_print_char_color_external_buffer; - s.print_string_external_buffer = mode03h_print_string_external_buffer; - s.print_string_color_external_buffer = mode03h_print_string_color_external_buffer; - s.set_char_external_buffer = mode03h_set_char_external_buffer; - s.get_char_external_buffer = mode03h_get_char_external_buffer; - s.set_color_external_buffer = mode03h_set_color_external_buffer; - s.get_color_external_buffer = mode03h_get_color_external_buffer; - s.set_char_and_color_external_buffer = mode03h_set_char_and_color_external_buffer; - s.get_char_and_color_external_buffer = mode03h_get_char_and_color_external_buffer; + s.print_char_external_buffer = generic_vga_print_char_external_buffer; + s.print_char_color_external_buffer = generic_vga_print_char_color_external_buffer; + s.print_string_external_buffer = generic_vga_print_string_external_buffer; + s.print_string_color_external_buffer = generic_vga_print_string_color_external_buffer; + s.set_char_external_buffer = generic_vga_set_char_external_buffer; + s.get_char_external_buffer = generic_vga_get_char_external_buffer; + s.set_color_external_buffer = generic_vga_set_color_external_buffer; + s.get_color_external_buffer = generic_vga_get_color_external_buffer; + s.set_char_and_color_external_buffer = generic_vga_set_char_and_color_external_buffer; + s.get_char_and_color_external_buffer = generic_vga_get_char_and_color_external_buffer; - s.draw_pixel_external_buffer = mode03h_draw_pixel_external_buffer; - s.draw_line_external_buffer = mode03h_draw_line_external_buffer; - s.draw_circle_external_buffer = mode03h_draw_circle_external_buffer; - s.draw_rectangle_external_buffer = mode03h_draw_rectangle_external_buffer; - s.clear_screen_external_buffer = mode03h_clear_screen_external_buffer; + s.draw_pixel_external_buffer = generic_vga_draw_pixel_external_buffer; + s.draw_line_external_buffer = generic_vga_draw_line_external_buffer; + s.draw_circle_external_buffer = generic_vga_draw_circle_external_buffer; + s.draw_rectangle_external_buffer = generic_vga_draw_rectangle_external_buffer; + s.clear_screen_external_buffer = generic_vga_clear_screen_external_buffer; - s.swap_external_buffer = mode03h_swap_external_buffer; - s.create_external_buffer = mode03h_create_external_buffer; + s.swap_external_buffer = generic_vga_swap_external_buffer; + s.create_external_buffer = generic_vga_create_external_buffer; s.destroy_external_buffer = generic_vga_destroy_external_buffer; video_card_init_with_driver(&s); @@ -508,7 +510,8 @@ int8_t generic_vga_swap_external_buffer(uint8_t* buffer, uint16_t mode){ default: return -1; } } -uint8_t* generic_vga_create_external_buffer(uint16_t mode){ +uint8_t* generic_vga_create_external_buffer(uint16_t mode) +{ switch(mode) { case 0x00: @@ -546,6 +549,194 @@ uint8_t* generic_vga_create_external_buffer(uint16_t mode){ default: return NULL; } } -void generic_vga_destroy_external_buffer(uint8_t* buffer){ + +int8_t generic_vga_print_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, char character) +{ + switch(mode) + { + case 0x00: + return mode00h_print_char_external_buffer(buffer, mode, x, y, character); + case 0x01: + return mode01h_print_char_external_buffer(buffer, mode, x, y, character); + case 0x02: + return mode02h_print_char_external_buffer(buffer, mode, x, y, character); + case 0x03: + return mode03h_print_char_external_buffer(buffer, mode, x, y, character); + case 0x07: + return mode07h_print_char_external_buffer(buffer, mode, x, y, character); + default: + return -1; + } +} +int8_t generic_vga_print_char_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, char character, uint8_t color) +{ + switch(mode) + { + case 0x00: + return mode00h_print_char_color_external_buffer(buffer, mode, x, y, character, color); + case 0x01: + return mode01h_print_char_color_external_buffer(buffer, mode, x, y, character, color); + case 0x02: + return mode02h_print_char_color_external_buffer(buffer, mode, x, y, character, color); + case 0x03: + return mode03h_print_char_color_external_buffer(buffer, mode, x, y, character, color); + case 0x07: + return mode07h_print_char_color_external_buffer(buffer, mode, x, y, character, color); + default: + return -1; + } +} +int8_t generic_vga_print_string_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, const char* string) +{ + switch(mode) + { + case 0x00: + return mode00h_print_string_external_buffer(buffer, mode, x, y, string); + case 0x01: + return mode01h_print_string_external_buffer(buffer, mode, x, y, string); + case 0x02: + return mode02h_print_string_external_buffer(buffer, mode, x, y, string); + case 0x03: + return mode03h_print_string_external_buffer(buffer, mode, x, y, string); + case 0x07: + return mode07h_print_string_external_buffer(buffer, mode, x, y, string); + default: + return -1; + } +} +int8_t generic_vga_print_string_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, const char* string, uint8_t color) +{ + switch(mode) + { + case 0x00: + return mode00h_print_string_color_external_buffer(buffer, mode, x, y, string, color); + case 0x01: + return mode01h_print_string_color_external_buffer(buffer, mode, x, y, string, color); + case 0x02: + return mode02h_print_string_color_external_buffer(buffer, mode, x, y, string, color); + case 0x03: + return mode03h_print_string_color_external_buffer(buffer, mode, x, y, string, color); + case 0x07: + return mode07h_print_string_color_external_buffer(buffer, mode, x, y, string, color); + default: + return -1; + } +} +int8_t generic_vga_set_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char character) +{ + switch(mode) + { + case 0x00: + return mode00h_set_char_external_buffer(buffer, mode, x, y, character); + case 0x01: + return mode01h_set_char_external_buffer(buffer, mode, x, y, character); + case 0x02: + return mode02h_set_char_external_buffer(buffer, mode, x, y, character); + case 0x03: + return mode03h_set_char_external_buffer(buffer, mode, x, y, character); + case 0x07: + return mode07h_set_char_external_buffer(buffer, mode, x, y, character); + default: + return -1; + } +} +int8_t generic_vga_get_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char* character) +{ + switch(mode) + { + case 0x00: + return mode00h_get_char_external_buffer(buffer, mode, x, y, character); + case 0x01: + return mode01h_get_char_external_buffer(buffer, mode, x, y, character); + case 0x02: + return mode02h_get_char_external_buffer(buffer, mode, x, y, character); + case 0x03: + return mode03h_get_char_external_buffer(buffer, mode, x, y, character); + case 0x07: + return mode07h_get_char_external_buffer(buffer, mode, x, y, character); + default: + return -1; + } +} +int8_t generic_vga_set_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, uint8_t color) +{ + switch(mode) + { + case 0x00: + return mode00h_set_color_external_buffer(buffer, mode, x, y, color); + case 0x01: + return mode01h_set_color_external_buffer(buffer, mode, x, y, color); + case 0x02: + return mode02h_set_color_external_buffer(buffer, mode, x, y, color); + case 0x03: + return mode03h_set_color_external_buffer(buffer, mode, x, y, color); + case 0x07: + return mode07h_set_color_external_buffer(buffer, mode, x, y, color); + default: + return -1; + } +} +int8_t generic_vga_get_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, uint8_t* color) +{ + switch(mode) + { + case 0x00: + return mode00h_get_color_external_buffer(buffer, mode, x, y, color); + case 0x01: + return mode01h_get_color_external_buffer(buffer, mode, x, y, color); + case 0x02: + return mode02h_get_color_external_buffer(buffer, mode, x, y, color); + case 0x03: + return mode03h_get_color_external_buffer(buffer, mode, x, y, color); + case 0x07: + return mode07h_get_color_external_buffer(buffer, mode, x, y, color); + default: + return -1; + } +} +int8_t generic_vga_set_char_and_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char character, uint8_t color) +{ + switch(mode) + { + case 0x00: + return mode00h_set_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x01: + return mode01h_set_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x02: + return mode02h_set_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x03: + return mode03h_set_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x07: + return mode07h_set_char_and_color_external_buffer(buffer, mode, x, y, character, color); + default: + return -1; + } +} +int8_t generic_vga_get_char_and_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char* character, uint8_t* color) +{ + switch(mode) + { + case 0x00: + return mode00h_get_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x01: + return mode01h_get_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x02: + return mode02h_get_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x03: + return mode03h_get_char_and_color_external_buffer(buffer, mode, x, y, character, color); + case 0x07: + return mode07h_get_char_and_color_external_buffer(buffer, mode, x, y, character, color); + default: + return -1; + } +} + +void generic_vga_destroy_external_buffer(uint8_t* buffer) +{ heap_kernel_dealloc(buffer); +} + +uint8_t generic_vga_is_vretrace() +{ + return io_in_byte(INPUT_STATUS_1) & VRETRACE; } \ No newline at end of file diff --git a/os/kernel/src/drivers/vga/genericvga.h b/os/kernel/src/drivers/vga/genericvga.h index 744a5fa8..97a56c5a 100644 --- a/os/kernel/src/drivers/vga/genericvga.h +++ b/os/kernel/src/drivers/vga/genericvga.h @@ -4,6 +4,9 @@ #include #include "drivers/dal/videocard/videocard.h" +#define INPUT_STATUS_1 0x03da +#define VRETRACE 0x08 + void generic_vga_driver_init(); int16_t generic_vga_set_video_mode(uint16_t mode); uint8_t generic_vga_is_text_mode(); @@ -15,8 +18,21 @@ int8_t generic_vga_draw_circle_external_buffer(uint8_t* buffer, uint16_t mode, u int8_t generic_vga_draw_rectangle_external_buffer(uint8_t* buffer, uint16_t mode, uint8_t color, uint16_t ax, uint16_t ay, uint16_t bx, uint16_t by); int8_t generic_vga_clear_screen_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y); +int8_t generic_vga_print_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, char character); +int8_t generic_vga_print_char_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, char character, uint8_t color); +int8_t generic_vga_print_string_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, const char* string); +int8_t generic_vga_print_string_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t* x, uint16_t* y, const char* string, uint8_t color); +int8_t generic_vga_set_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char character); +int8_t generic_vga_get_char_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char* character); +int8_t generic_vga_set_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, uint8_t color); +int8_t generic_vga_get_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, uint8_t* color); +int8_t generic_vga_set_char_and_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char character, uint8_t color); +int8_t generic_vga_get_char_and_color_external_buffer(uint8_t* buffer, uint16_t mode, uint16_t x, uint16_t y, char* character, uint8_t* color); + int8_t generic_vga_swap_external_buffer(uint8_t* buffer, uint16_t mode); uint8_t* generic_vga_create_external_buffer(uint16_t mode); void generic_vga_destroy_external_buffer(uint8_t* buffer); +uint8_t generic_vga_is_vretrace(); + #endif \ No newline at end of file diff --git a/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c b/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c index d4a520c5..02202236 100644 --- a/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c +++ b/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c @@ -395,6 +395,7 @@ int8_t mode00h_set_mode() video_card_set_draw_circle_func(mode00h_draw_circle); video_card_set_draw_rectangle_func(mode00h_draw_rectangle); video_card_set_clear_screen_func(mode00h_clear_screen); + video_card_set_swap_external_buffer(&mode00h_swap_external_buffer); video_card_set_print_char_external_buffer(mode00h_print_char_external_buffer); video_card_set_print_char_color_external_buffer(mode00h_print_char_color_external_buffer); diff --git a/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c b/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c index e3a27eb1..d10fc309 100644 --- a/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c +++ b/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c @@ -395,6 +395,7 @@ int8_t mode01h_set_mode() video_card_set_draw_circle_func(mode01h_draw_circle); video_card_set_draw_rectangle_func(mode01h_draw_rectangle); video_card_set_clear_screen_func(mode01h_clear_screen); + video_card_set_swap_external_buffer(&mode01h_swap_external_buffer); video_card_set_print_char_external_buffer(mode01h_print_char_external_buffer); video_card_set_print_char_color_external_buffer(mode01h_print_char_color_external_buffer); diff --git a/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c b/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c index 4ab52868..10c9812c 100644 --- a/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c +++ b/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c @@ -395,6 +395,7 @@ int8_t mode02h_set_mode() video_card_set_draw_circle_func(mode02h_draw_circle); video_card_set_draw_rectangle_func(mode02h_draw_rectangle); video_card_set_clear_screen_func(mode02h_clear_screen); + video_card_set_swap_external_buffer(&mode02h_swap_external_buffer); video_card_set_print_char_external_buffer(mode02h_print_char_external_buffer); video_card_set_print_char_color_external_buffer(mode02h_print_char_color_external_buffer); diff --git a/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c b/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c index 8a1fe6f3..8e4c6ee1 100644 --- a/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c +++ b/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c @@ -395,6 +395,7 @@ int8_t mode03h_set_mode() video_card_set_draw_circle_func(mode03h_draw_circle); video_card_set_draw_rectangle_func(mode03h_draw_rectangle); video_card_set_clear_screen_func(mode03h_clear_screen); + video_card_set_swap_external_buffer(&mode03h_swap_external_buffer); video_card_set_print_char_external_buffer(mode03h_print_char_external_buffer); video_card_set_print_char_color_external_buffer(mode03h_print_char_color_external_buffer); diff --git a/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c b/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c index 8450f436..ed4990c9 100644 --- a/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c +++ b/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c @@ -95,6 +95,7 @@ int8_t mode04h_set_mode() video_card_set_draw_circle_func(&mode04h_draw_circle); video_card_set_draw_rectangle_func(&mode04h_draw_rectangle); video_card_set_clear_screen_func(&mode04h_clear_screen); + video_card_set_swap_external_buffer(&mode04h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c b/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c index bffb94f4..13551d9e 100644 --- a/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c +++ b/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c @@ -95,6 +95,7 @@ int8_t mode05h_set_mode() video_card_set_draw_circle_func(&mode05h_draw_circle); video_card_set_draw_rectangle_func(&mode05h_draw_rectangle); video_card_set_clear_screen_func(&mode05h_clear_screen); + video_card_set_swap_external_buffer(&mode05h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c b/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c index 28c84e48..ca7dbcf8 100644 --- a/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c +++ b/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c @@ -95,6 +95,7 @@ int8_t mode06h_set_mode() video_card_set_draw_circle_func(&mode06h_draw_circle); video_card_set_draw_rectangle_func(&mode06h_draw_rectangle); video_card_set_clear_screen_func(&mode06h_clear_screen); + video_card_set_swap_external_buffer(&mode06h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c b/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c index 7efacc60..e4e25c19 100644 --- a/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c +++ b/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c @@ -395,6 +395,7 @@ int8_t mode07h_set_mode() video_card_set_draw_circle_func(mode07h_draw_circle); video_card_set_draw_rectangle_func(mode07h_draw_rectangle); video_card_set_clear_screen_func(mode07h_clear_screen); + video_card_set_swap_external_buffer(&mode07h_swap_external_buffer); video_card_set_print_char_external_buffer(mode07h_print_char_external_buffer); video_card_set_print_char_color_external_buffer(mode07h_print_char_color_external_buffer); diff --git a/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c b/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c index 64d29e05..92c2b34d 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c @@ -95,6 +95,7 @@ int8_t mode0dh_set_mode() video_card_set_draw_circle_func(&mode0dh_draw_circle); video_card_set_draw_rectangle_func(&mode0dh_draw_rectangle); video_card_set_clear_screen_func(&mode0dh_clear_screen); + video_card_set_swap_external_buffer(&mode0dh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c b/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c index ef68cc45..20acf025 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c @@ -95,6 +95,7 @@ int8_t mode0eh_set_mode() video_card_set_draw_circle_func(&mode0eh_draw_circle); video_card_set_draw_rectangle_func(&mode0eh_draw_rectangle); video_card_set_clear_screen_func(&mode0eh_clear_screen); + video_card_set_swap_external_buffer(&mode0eh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c b/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c index 4fdb48a0..1b0b5209 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c @@ -95,6 +95,7 @@ int8_t mode0fh_set_mode() video_card_set_draw_circle_func(&mode0fh_draw_circle); video_card_set_draw_rectangle_func(&mode0fh_draw_rectangle); video_card_set_clear_screen_func(&mode0fh_clear_screen); + video_card_set_swap_external_buffer(&mode0fh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c b/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c index 230e01db..a76fc378 100644 --- a/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c +++ b/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c @@ -95,6 +95,7 @@ int8_t mode10h_set_mode() video_card_set_draw_circle_func(&mode10h_draw_circle); video_card_set_draw_rectangle_func(&mode10h_draw_rectangle); video_card_set_clear_screen_func(&mode10h_clear_screen); + video_card_set_swap_external_buffer(&mode10h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c b/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c index 1ab22bc7..239424f5 100644 --- a/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c +++ b/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c @@ -95,6 +95,7 @@ int8_t mode11h_set_mode() video_card_set_draw_circle_func(&mode11h_draw_circle); video_card_set_draw_rectangle_func(&mode11h_draw_rectangle); video_card_set_clear_screen_func(&mode11h_clear_screen); + video_card_set_swap_external_buffer(&mode11h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c b/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c index 9474bdf3..35c9d83e 100644 --- a/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c +++ b/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c @@ -95,6 +95,7 @@ int8_t mode12h_set_mode() video_card_set_draw_circle_func(&mode12h_draw_circle); video_card_set_draw_rectangle_func(&mode12h_draw_rectangle); video_card_set_clear_screen_func(&mode12h_clear_screen); + video_card_set_swap_external_buffer(&mode12h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.c b/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.c index 512b799c..d17d2617 100644 --- a/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.c +++ b/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.c @@ -97,34 +97,93 @@ int8_t mode13h_set_mode() video_card_set_draw_rectangle_func(&mode13h_draw_rectangle); video_card_set_clear_screen_func(&mode13h_clear_screen); - video_card_set_print_char_func(NULL); - video_card_set_print_char_color_func(NULL); - video_card_set_print_string_func(NULL); - video_card_set_print_string_color_func(NULL); - video_card_set_set_char_func(NULL); - video_card_set_get_char_func(NULL); - video_card_set_set_color_func(NULL); - video_card_set_get_color_func(NULL); - video_card_set_set_char_and_color_func(NULL); - video_card_set_get_char_and_color_func(NULL); - video_card_set_set_cursor_pos_func(NULL); - video_card_set_get_cursor_pos_func(NULL); - video_card_set_turn_cursor_on_func(NULL); - video_card_set_turn_cursor_off_func(NULL); - - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); + video_card_set_print_char_func(&mode13h_print_char); + video_card_set_print_char_color_func(&mode13h_print_char_color); + video_card_set_print_string_func(&mode13h_print_string); + video_card_set_print_string_color_func(&mode13h_print_string_color); + video_card_set_set_char_func(&mode13h_set_char); + video_card_set_get_char_func(&mode13h_get_char); + video_card_set_set_color_func(&mode13h_set_color); + video_card_set_get_color_func(&mode13h_get_color); + video_card_set_set_char_and_color_func(&mode13h_set_char_and_color); + video_card_set_get_char_and_color_func(&mode13h_get_char_and_color); + video_card_set_set_cursor_pos_func(&mode13h_set_cursor_pos); + video_card_set_get_cursor_pos_func(&mode13h_get_cursor_pos); + video_card_set_turn_cursor_on_func(&mode13h_turn_cursor_on); + video_card_set_turn_cursor_off_func(&mode13h_turn_cursor_off); return 0x13; } +int8_t mode13h_print_char(char character) +{ + return -1; +} + +int8_t mode13h_print_char_color(char character, uint8_t color) +{ + return -1; +} + +int8_t mode13h_print_string(const char* string) +{ + return -1; +} + +int8_t mode13h_print_string_color(const char* string, uint8_t color) +{ + return -1; +} + +int8_t mode13h_set_char(uint16_t x, uint16_t y, char character) +{ + return -1; +} + +int8_t mode13h_get_char(uint16_t x, uint16_t y, char* character) +{ + return -1; +} + +int8_t mode13h_set_color(uint16_t x, uint16_t y, uint8_t color) +{ + return -1; +} + +int8_t mode13h_get_color(uint16_t x, uint16_t y, uint8_t* color) +{ + return -1; +} + +int8_t mode13h_set_char_and_color(uint16_t x, uint16_t y, char character, uint8_t color) +{ + return -1; +} + +int8_t mode13h_get_char_and_color(uint16_t x, uint16_t y, char* character, uint8_t* color) +{ + return -1; +} + +int8_t mode13h_set_cursor_pos(uint16_t x, uint16_t y) +{ + return -1; +} + +int8_t mode13h_get_cursor_pos(uint16_t* x, uint16_t* y) +{ + return -1; +} + +int8_t mode13h_turn_cursor_on() +{ + return -1; +} + +int8_t mode13h_turn_cursor_off() +{ + return -1; +} + int8_t mode13h_turn_on_buffer() { if(mode13h_buffer != NULL) return -1; diff --git a/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.h b/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.h index 98f75203..b317f8b8 100644 --- a/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.h +++ b/os/kernel/src/drivers/vga/modes/mode_13h/mode_13h.h @@ -35,4 +35,19 @@ int8_t mode13h_clear_screen_external_buffer(uint8_t* buffer, uint16_t mode, uint int8_t mode13h_swap_external_buffer(uint8_t* buffer, uint16_t mode); uint8_t* mode13h_create_external_buffer(uint16_t mode); +int8_t mode13h_print_char(char character); +int8_t mode13h_print_char_color(char character, uint8_t color); +int8_t mode13h_print_string(const char* string); +int8_t mode13h_print_string_color(const char* string, uint8_t color); +int8_t mode13h_set_char(uint16_t x, uint16_t y, char character); +int8_t mode13h_get_char(uint16_t x, uint16_t y, char* character); +int8_t mode13h_set_color(uint16_t x, uint16_t y, uint8_t color); +int8_t mode13h_get_color(uint16_t x, uint16_t y, uint8_t* color); +int8_t mode13h_set_char_and_color(uint16_t x, uint16_t y, char character, uint8_t color); +int8_t mode13h_get_char_and_color(uint16_t x, uint16_t y, char* character, uint8_t* color); +int8_t mode13h_set_cursor_pos(uint16_t x, uint16_t y); +int8_t mode13h_get_cursor_pos(uint16_t* x, uint16_t* y); +int8_t mode13h_turn_cursor_on(); +int8_t mode13h_turn_cursor_off(); + #endif \ No newline at end of file diff --git a/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c b/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c index 9765341a..dc8b6f2a 100644 --- a/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c +++ b/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c @@ -95,6 +95,7 @@ int8_t modey_set_mode() video_card_set_draw_circle_func(&modey_draw_circle); video_card_set_draw_rectangle_func(&modey_draw_rectangle); video_card_set_clear_screen_func(&modey_clear_screen); + video_card_set_swap_external_buffer(&modey_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); diff --git a/os/kernel/src/filesystems/fat/fat.c b/os/kernel/src/filesystems/fat/fat.c index 9205fb78..ec1b0c43 100644 --- a/os/kernel/src/filesystems/fat/fat.c +++ b/os/kernel/src/filesystems/fat/fat.c @@ -391,7 +391,7 @@ uint8_t *fat_read_file_from_cluster(uint16_t initial_cluster, uint16_t cluster_o current_partition->first_sector; uint32_t counter = 1; - while (cluster + 1 == (cluster = fat_read_cluster_value(cluster))) + while (cluster + 1 == (cluster = fat_read_cluster_value(cluster)) && counter < clusters_count) { counter += 1; } diff --git a/os/kernel/src/process/syscalls/handlers/generic_vga.c b/os/kernel/src/process/syscalls/handlers/generic_vga.c index 02b8fab0..da6ed311 100644 --- a/os/kernel/src/process/syscalls/handlers/generic_vga.c +++ b/os/kernel/src/process/syscalls/handlers/generic_vga.c @@ -13,4 +13,9 @@ void syscall_generic_vga_is_text_mode(interrupt_state *state) void syscall_generic_vga_get_current_video_mode(interrupt_state *state) { state->registers.eax = generic_vga_get_current_video_mode()->id; +} + +void syscall_generic_vga_is_vretrace(interrupt_state* state) +{ + state->registers.eax = generic_vga_is_vretrace(); } \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/handlers/generic_vga.h b/os/kernel/src/process/syscalls/handlers/generic_vga.h index d137ea5b..4d060635 100644 --- a/os/kernel/src/process/syscalls/handlers/generic_vga.h +++ b/os/kernel/src/process/syscalls/handlers/generic_vga.h @@ -8,4 +8,7 @@ void syscall_generic_vga_set_video_mode(interrupt_state *state); void syscall_generic_vga_is_text_mode(interrupt_state *state); void syscall_generic_vga_get_current_video_mode(interrupt_state *state); +//TODO NO DAL +void syscall_generic_vga_is_vretrace(interrupt_state* state); + #endif \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/handlers/terminal_calls.c b/os/kernel/src/process/syscalls/handlers/terminal_calls.c index b03edee0..9b969f4c 100644 --- a/os/kernel/src/process/syscalls/handlers/terminal_calls.c +++ b/os/kernel/src/process/syscalls/handlers/terminal_calls.c @@ -88,4 +88,14 @@ void syscall_terminal_set_cursor_visibility(interrupt_state *state) { terminal_manager_turn_cursor_off(process_manager_get_current_process()->id); } +} + +void syscall_terminal_set_video_mode(interrupt_state *state) +{ + terminal_manager_set_mode(process_manager_get_current_process()->id, state->registers.ebx); +} + +void syscall_terminal_copy_from_buffer(interrupt_state *state) +{ + terminal_manager_copy_from_buffer(process_manager_get_current_process()->id, (uint8_t*)(state->registers.ebx), state->registers.ecx); } \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/handlers/terminal_calls.h b/os/kernel/src/process/syscalls/handlers/terminal_calls.h index 412b8221..60c1180b 100644 --- a/os/kernel/src/process/syscalls/handlers/terminal_calls.h +++ b/os/kernel/src/process/syscalls/handlers/terminal_calls.h @@ -14,4 +14,7 @@ void syscall_terminal_get_cursor_position(interrupt_state *state); void syscall_terminal_clear(); void syscall_terminal_set_cursor_visibility(interrupt_state *state); +void syscall_terminal_set_video_mode(interrupt_state *state); +void syscall_terminal_copy_from_buffer(interrupt_state *state); + #endif \ No newline at end of file diff --git a/os/kernel/src/process/syscalls/syscalls_manager.c b/os/kernel/src/process/syscalls/syscalls_manager.c index eaf2c272..bdc764fb 100644 --- a/os/kernel/src/process/syscalls/syscalls_manager.c +++ b/os/kernel/src/process/syscalls/syscalls_manager.c @@ -26,6 +26,7 @@ void syscalls_manager_init() syscalls_manager_attach_handler(0x17, syscall_generic_vga_set_video_mode); syscalls_manager_attach_handler(0x18, syscall_generic_vga_is_text_mode); syscalls_manager_attach_handler(0x19, syscall_generic_vga_get_current_video_mode); + syscalls_manager_attach_handler(0x1A, syscall_generic_vga_is_vretrace); // 0x2X - Keyboard syscalls_manager_attach_handler(0x20, syscall_keyboard_is_key_pressed); @@ -100,6 +101,10 @@ void syscalls_manager_init() syscalls_manager_attach_handler(0xD3, syscall_serial_send); syscalls_manager_attach_handler(0xD4, syscall_serial_send_string); syscalls_manager_attach_handler(0xD5, syscall_serial_receive); + + //0xEX - Terminal Manager Graphics Functions + syscalls_manager_attach_handler(0xE0, syscall_terminal_set_video_mode); + syscalls_manager_attach_handler(0xE1, syscall_terminal_copy_from_buffer); } void syscalls_manager_attach_handler(uint8_t function_number, void (*handler)(interrupt_state *state)) diff --git a/os/kernel/src/terminal/terminal_manager.c b/os/kernel/src/terminal/terminal_manager.c index 8bab392e..4404087a 100644 --- a/os/kernel/src/terminal/terminal_manager.c +++ b/os/kernel/src/terminal/terminal_manager.c @@ -522,4 +522,12 @@ bool terminal_manager_keyboard_interrupt_handler(interrupt_state *state) return false; } +int8_t terminal_manager_copy_from_buffer(uint32_t process_id, uint8_t* buffer, size_t how_many) +{ + terminal_struct* terminal = find_terminal_for_process(process_id); + if(terminal == NULL) return -1; + memcpy(terminal->screen_buffer, buffer, how_many); + if(terminal->terminal_id == active_terminal_id) video_card_swap_external_buffer(buffer, terminal->screen_mode); + return 0; +} //TODO: Functions for writting to chars and pixels, changing modes, changing active terminal and get list of terminals \ No newline at end of file diff --git a/os/kernel/src/terminal/terminal_manager.h b/os/kernel/src/terminal/terminal_manager.h index 9e1aabda..ca324d14 100644 --- a/os/kernel/src/terminal/terminal_manager.h +++ b/os/kernel/src/terminal/terminal_manager.h @@ -56,6 +56,7 @@ int8_t terminal_manager_draw_line(uint32_t process_id, uint8_t color, uint16_t a int8_t terminal_manager_draw_circle(uint32_t process_id, uint8_t color, uint16_t x, uint16_t y, uint16_t radius); int8_t terminal_manager_draw_rectangle(uint32_t process_id, uint8_t color, uint16_t ax, uint16_t ay, uint16_t bx, uint16_t by); int8_t terminal_manager_clear_screen(uint32_t process_id); +int8_t terminal_manager_copy_from_buffer(uint32_t process_id, uint8_t* buffer, size_t how_many); uint32_t terminal_manager_get_active_terminal_id(); bool terminal_manager_keyboard_interrupt_handler(interrupt_state *state); From 7786d4ad6c32e74924b42351ce2a6fa2665c5475 Mon Sep 17 00:00:00 2001 From: MatiF100 Date: Fri, 29 Oct 2021 19:07:50 +0200 Subject: [PATCH 163/165] Graphical modes * Removed repetetive and unnecessary functions sets from graphical modes in vga driver --- os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c | 12 +----------- os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c | 13 +------------ os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c | 12 +----------- os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c | 12 +----------- os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c | 12 +----------- os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c | 12 +----------- os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c | 11 ----------- os/kernel/src/drivers/vga/modes/mode_y/mode_y.c | 11 ----------- 15 files changed, 6 insertions(+), 166 deletions(-) diff --git a/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c b/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c index 02202236..7ad637f2 100644 --- a/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c +++ b/os/kernel/src/drivers/vga/modes/mode_00h/mode_00h.c @@ -395,18 +395,8 @@ int8_t mode00h_set_mode() video_card_set_draw_circle_func(mode00h_draw_circle); video_card_set_draw_rectangle_func(mode00h_draw_rectangle); video_card_set_clear_screen_func(mode00h_clear_screen); - video_card_set_swap_external_buffer(&mode00h_swap_external_buffer); - video_card_set_print_char_external_buffer(mode00h_print_char_external_buffer); - video_card_set_print_char_color_external_buffer(mode00h_print_char_color_external_buffer); - video_card_set_print_string_external_buffer(mode00h_print_string_external_buffer); - video_card_set_print_string_color_external_buffer(mode00h_print_string_color_external_buffer); - video_card_set_set_char_external_buffer(mode00h_set_char_external_buffer); - video_card_set_get_char_external_buffer(mode00h_get_char_external_buffer); - video_card_set_set_color_external_buffer(mode00h_set_color_external_buffer); - video_card_set_get_color_external_buffer(mode00h_get_color_external_buffer); - video_card_set_set_char_and_color_external_buffer(mode00h_set_char_and_color_external_buffer); - video_card_set_get_char_and_color_external_buffer(mode00h_get_char_and_color_external_buffer); + return 0x00; } diff --git a/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c b/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c index d10fc309..35577288 100644 --- a/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c +++ b/os/kernel/src/drivers/vga/modes/mode_01h/mode_01h.c @@ -395,18 +395,7 @@ int8_t mode01h_set_mode() video_card_set_draw_circle_func(mode01h_draw_circle); video_card_set_draw_rectangle_func(mode01h_draw_rectangle); video_card_set_clear_screen_func(mode01h_clear_screen); - video_card_set_swap_external_buffer(&mode01h_swap_external_buffer); - video_card_set_print_char_external_buffer(mode01h_print_char_external_buffer); - video_card_set_print_char_color_external_buffer(mode01h_print_char_color_external_buffer); - video_card_set_print_string_external_buffer(mode01h_print_string_external_buffer); - video_card_set_print_string_color_external_buffer(mode01h_print_string_color_external_buffer); - video_card_set_set_char_external_buffer(mode01h_set_char_external_buffer); - video_card_set_get_char_external_buffer(mode01h_get_char_external_buffer); - video_card_set_set_color_external_buffer(mode01h_set_color_external_buffer); - video_card_set_get_color_external_buffer(mode01h_get_color_external_buffer); - video_card_set_set_char_and_color_external_buffer(mode01h_set_char_and_color_external_buffer); - video_card_set_get_char_and_color_external_buffer(mode01h_get_char_and_color_external_buffer); return 0x01; } diff --git a/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c b/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c index 10c9812c..7fcdf817 100644 --- a/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c +++ b/os/kernel/src/drivers/vga/modes/mode_02h/mode_02h.c @@ -395,18 +395,7 @@ int8_t mode02h_set_mode() video_card_set_draw_circle_func(mode02h_draw_circle); video_card_set_draw_rectangle_func(mode02h_draw_rectangle); video_card_set_clear_screen_func(mode02h_clear_screen); - video_card_set_swap_external_buffer(&mode02h_swap_external_buffer); - video_card_set_print_char_external_buffer(mode02h_print_char_external_buffer); - video_card_set_print_char_color_external_buffer(mode02h_print_char_color_external_buffer); - video_card_set_print_string_external_buffer(mode02h_print_string_external_buffer); - video_card_set_print_string_color_external_buffer(mode02h_print_string_color_external_buffer); - video_card_set_set_char_external_buffer(mode02h_set_char_external_buffer); - video_card_set_get_char_external_buffer(mode02h_get_char_external_buffer); - video_card_set_set_color_external_buffer(mode02h_set_color_external_buffer); - video_card_set_get_color_external_buffer(mode02h_get_color_external_buffer); - video_card_set_set_char_and_color_external_buffer(mode02h_set_char_and_color_external_buffer); - video_card_set_get_char_and_color_external_buffer(mode02h_get_char_and_color_external_buffer); return 0x02; } diff --git a/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c b/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c index 8e4c6ee1..8a61b06f 100644 --- a/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c +++ b/os/kernel/src/drivers/vga/modes/mode_03h/mode_03h.c @@ -395,18 +395,7 @@ int8_t mode03h_set_mode() video_card_set_draw_circle_func(mode03h_draw_circle); video_card_set_draw_rectangle_func(mode03h_draw_rectangle); video_card_set_clear_screen_func(mode03h_clear_screen); - video_card_set_swap_external_buffer(&mode03h_swap_external_buffer); - - video_card_set_print_char_external_buffer(mode03h_print_char_external_buffer); - video_card_set_print_char_color_external_buffer(mode03h_print_char_color_external_buffer); - video_card_set_print_string_external_buffer(mode03h_print_string_external_buffer); - video_card_set_print_string_color_external_buffer(mode03h_print_string_color_external_buffer); - video_card_set_set_char_external_buffer(mode03h_set_char_external_buffer); - video_card_set_get_char_external_buffer(mode03h_get_char_external_buffer); - video_card_set_set_color_external_buffer(mode03h_set_color_external_buffer); - video_card_set_get_color_external_buffer(mode03h_get_color_external_buffer); - video_card_set_set_char_and_color_external_buffer(mode03h_set_char_and_color_external_buffer); - video_card_set_get_char_and_color_external_buffer(mode03h_get_char_and_color_external_buffer); + return 0x03; } diff --git a/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c b/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c index ed4990c9..c312a805 100644 --- a/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c +++ b/os/kernel/src/drivers/vga/modes/mode_04h/mode_04h.c @@ -95,7 +95,6 @@ int8_t mode04h_set_mode() video_card_set_draw_circle_func(&mode04h_draw_circle); video_card_set_draw_rectangle_func(&mode04h_draw_rectangle); video_card_set_clear_screen_func(&mode04h_clear_screen); - video_card_set_swap_external_buffer(&mode04h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode04h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x04; } diff --git a/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c b/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c index 13551d9e..dfaeccd5 100644 --- a/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c +++ b/os/kernel/src/drivers/vga/modes/mode_05h/mode_05h.c @@ -95,7 +95,6 @@ int8_t mode05h_set_mode() video_card_set_draw_circle_func(&mode05h_draw_circle); video_card_set_draw_rectangle_func(&mode05h_draw_rectangle); video_card_set_clear_screen_func(&mode05h_clear_screen); - video_card_set_swap_external_buffer(&mode05h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,7 @@ int8_t mode05h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); + return 0x05; } diff --git a/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c b/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c index ca7dbcf8..4fff1db3 100644 --- a/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c +++ b/os/kernel/src/drivers/vga/modes/mode_06h/mode_06h.c @@ -95,7 +95,6 @@ int8_t mode06h_set_mode() video_card_set_draw_circle_func(&mode06h_draw_circle); video_card_set_draw_rectangle_func(&mode06h_draw_rectangle); video_card_set_clear_screen_func(&mode06h_clear_screen); - video_card_set_swap_external_buffer(&mode06h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,7 @@ int8_t mode06h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); + return 0x06; } diff --git a/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c b/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c index e4e25c19..c9297bc0 100644 --- a/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c +++ b/os/kernel/src/drivers/vga/modes/mode_07h/mode_07h.c @@ -395,18 +395,8 @@ int8_t mode07h_set_mode() video_card_set_draw_circle_func(mode07h_draw_circle); video_card_set_draw_rectangle_func(mode07h_draw_rectangle); video_card_set_clear_screen_func(mode07h_clear_screen); - video_card_set_swap_external_buffer(&mode07h_swap_external_buffer); - video_card_set_print_char_external_buffer(mode07h_print_char_external_buffer); - video_card_set_print_char_color_external_buffer(mode07h_print_char_color_external_buffer); - video_card_set_print_string_external_buffer(mode07h_print_string_external_buffer); - video_card_set_print_string_color_external_buffer(mode07h_print_string_color_external_buffer); - video_card_set_set_char_external_buffer(mode07h_set_char_external_buffer); - video_card_set_get_char_external_buffer(mode07h_get_char_external_buffer); - video_card_set_set_color_external_buffer(mode07h_set_color_external_buffer); - video_card_set_get_color_external_buffer(mode07h_get_color_external_buffer); - video_card_set_set_char_and_color_external_buffer(mode07h_set_char_and_color_external_buffer); - video_card_set_get_char_and_color_external_buffer(mode07h_get_char_and_color_external_buffer); + return 0x07; } diff --git a/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c b/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c index 92c2b34d..7f37dc83 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0dh/mode_0dh.c @@ -95,7 +95,6 @@ int8_t mode0dh_set_mode() video_card_set_draw_circle_func(&mode0dh_draw_circle); video_card_set_draw_rectangle_func(&mode0dh_draw_rectangle); video_card_set_clear_screen_func(&mode0dh_clear_screen); - video_card_set_swap_external_buffer(&mode0dh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode0dh_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x0D; } diff --git a/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c b/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c index 20acf025..71813964 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0eh/mode_0eh.c @@ -95,7 +95,6 @@ int8_t mode0eh_set_mode() video_card_set_draw_circle_func(&mode0eh_draw_circle); video_card_set_draw_rectangle_func(&mode0eh_draw_rectangle); video_card_set_clear_screen_func(&mode0eh_clear_screen); - video_card_set_swap_external_buffer(&mode0eh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,7 @@ int8_t mode0eh_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); + return 0x0E; } diff --git a/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c b/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c index 1b0b5209..54a00b93 100644 --- a/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c +++ b/os/kernel/src/drivers/vga/modes/mode_0fh/mode_0fh.c @@ -95,7 +95,6 @@ int8_t mode0fh_set_mode() video_card_set_draw_circle_func(&mode0fh_draw_circle); video_card_set_draw_rectangle_func(&mode0fh_draw_rectangle); video_card_set_clear_screen_func(&mode0fh_clear_screen); - video_card_set_swap_external_buffer(&mode0fh_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode0fh_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x0F; } diff --git a/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c b/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c index a76fc378..132bc8de 100644 --- a/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c +++ b/os/kernel/src/drivers/vga/modes/mode_10h/mode_10h.c @@ -95,7 +95,6 @@ int8_t mode10h_set_mode() video_card_set_draw_circle_func(&mode10h_draw_circle); video_card_set_draw_rectangle_func(&mode10h_draw_rectangle); video_card_set_clear_screen_func(&mode10h_clear_screen); - video_card_set_swap_external_buffer(&mode10h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode10h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x10; } diff --git a/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c b/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c index 239424f5..2134e131 100644 --- a/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c +++ b/os/kernel/src/drivers/vga/modes/mode_11h/mode_11h.c @@ -95,7 +95,6 @@ int8_t mode11h_set_mode() video_card_set_draw_circle_func(&mode11h_draw_circle); video_card_set_draw_rectangle_func(&mode11h_draw_rectangle); video_card_set_clear_screen_func(&mode11h_clear_screen); - video_card_set_swap_external_buffer(&mode11h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode11h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x11; } diff --git a/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c b/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c index 35c9d83e..7ec83504 100644 --- a/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c +++ b/os/kernel/src/drivers/vga/modes/mode_12h/mode_12h.c @@ -95,7 +95,6 @@ int8_t mode12h_set_mode() video_card_set_draw_circle_func(&mode12h_draw_circle); video_card_set_draw_rectangle_func(&mode12h_draw_rectangle); video_card_set_clear_screen_func(&mode12h_clear_screen); - video_card_set_swap_external_buffer(&mode12h_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t mode12h_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x12; } diff --git a/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c b/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c index dc8b6f2a..c60c6d26 100644 --- a/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c +++ b/os/kernel/src/drivers/vga/modes/mode_y/mode_y.c @@ -95,7 +95,6 @@ int8_t modey_set_mode() video_card_set_draw_circle_func(&modey_draw_circle); video_card_set_draw_rectangle_func(&modey_draw_rectangle); video_card_set_clear_screen_func(&modey_clear_screen); - video_card_set_swap_external_buffer(&modey_swap_external_buffer); video_card_set_print_char_func(NULL); video_card_set_print_char_color_func(NULL); @@ -112,16 +111,6 @@ int8_t modey_set_mode() video_card_set_turn_cursor_on_func(NULL); video_card_set_turn_cursor_off_func(NULL); - video_card_set_print_char_external_buffer(NULL); - video_card_set_print_char_color_external_buffer(NULL); - video_card_set_print_string_external_buffer(NULL); - video_card_set_print_string_color_external_buffer(NULL); - video_card_set_set_char_external_buffer(NULL); - video_card_set_get_char_external_buffer(NULL); - video_card_set_set_color_external_buffer(NULL); - video_card_set_get_color_external_buffer(NULL); - video_card_set_set_char_and_color_external_buffer(NULL); - video_card_set_get_char_and_color_external_buffer(NULL); return 0x69; } From 4d0a5ccd2220594d0edc02ff6e4b0ad5f961691a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Wojto=C5=84?= Date: Fri, 29 Oct 2021 21:07:32 +0200 Subject: [PATCH 164/165] Fix was unassified --- os/kernel/src/drivers/floppy/floppy.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/os/kernel/src/drivers/floppy/floppy.c b/os/kernel/src/drivers/floppy/floppy.c index 980cc98b..ca7a40dd 100644 --- a/os/kernel/src/drivers/floppy/floppy.c +++ b/os/kernel/src/drivers/floppy/floppy.c @@ -554,7 +554,6 @@ uint8_t* floppy_read_continous(int device_number, int sector, int count){ floppy_lba_to_chs(sector+offset, &head, &track, &true_sector); if (offset+18 <= count) { - if(true_sector != 1) vga_printstring("DUPA"); uint8_t* tmp = read_track_from_floppy(device_number, head, track); //uint8_t* tmp = floppy_read_sectors(device_number, head, track, true_sector, 18); memcpy(buffer+(offset*512), tmp, 18*512); @@ -570,7 +569,6 @@ uint8_t* floppy_read_continous(int device_number, int sector, int count){ uint8_t* floppy_read_sectors(int device_number, uint8_t head, uint8_t track, uint8_t sector, uint32_t count) { - //logger_log_info("DUPA CONT"); if (sector-1 + count > 18) { return NULL; From e71a09294c9d33a122c036ac19b743505a615f6b Mon Sep 17 00:00:00 2001 From: AzuxDario Date: Sun, 31 Oct 2021 12:53:15 +0100 Subject: [PATCH 165/165] Fix erf functions --- library/src/math/erf.c | 27 +----------------------- library/src/math/erff.c | 27 +----------------------- library/src/math/erfl.c | 46 +++++++++++++++++++++++++---------------- 3 files changed, 30 insertions(+), 70 deletions(-) diff --git a/library/src/math/erf.c b/library/src/math/erf.c index e37c1d12..f22c1803 100644 --- a/library/src/math/erf.c +++ b/library/src/math/erf.c @@ -2,30 +2,5 @@ double erf(double x) { - if(x == 0) - { - return 0; - } - double sign; - double factorial_of_j = 1; - double sum = 0; - for(int i = 1, j = 0; i < 22; i+=2, j++) - { - if(j % 2 == 0) - { - sign = 1; - } - else - { - sign = -1; - } - // Calculate factorial od j - if(j > 0) - { - factorial_of_j *= j; - } - sum = sum + (sign * pow(x, (double)i)/((double)i * factorial_of_j)); - } - sum = sum * 2/sqrt(M_PI); - return sum; + return (double)erfl((long double)x); } \ No newline at end of file diff --git a/library/src/math/erff.c b/library/src/math/erff.c index 8382c470..de8c31ad 100644 --- a/library/src/math/erff.c +++ b/library/src/math/erff.c @@ -2,30 +2,5 @@ float erff(float x) { - if(x == 0) - { - return 0; - } - float sign; - float factorial_of_j = 1; - float sum = 0; - for(int i = 1, j = 0; i < 22; i+=2, j++) - { - if(j % 2 == 0) - { - sign = 1; - } - else - { - sign = -1; - } - // Calculate factorial od j - if(j > 0) - { - factorial_of_j *= j; - } - sum = sum + (sign * powf(x, (float)i)/((float)i * factorial_of_j)); - } - sum = sum * 2/sqrt(M_PI); - return sum; + return (float)erfl((long double)x); } \ No newline at end of file diff --git a/library/src/math/erfl.c b/library/src/math/erfl.c index 830b3ae1..ef38c8b2 100644 --- a/library/src/math/erfl.c +++ b/library/src/math/erfl.c @@ -2,30 +2,40 @@ long double erfl(long double x) { + // Make it faster for obivious values if(x == 0) { return 0; } - long double sign; - long double factorial_of_j = 1; + if(x > 3.56) + { + return 1; + } + if(x < -3.56) + { + return -1; + } + long double sum = 0; - for(int i = 1, j = 0; i < 22; i+=2, j++) + long double span = 0.000000001; + long double current_piece = 0; + + for(current_piece; current_piece < x; current_piece += span) + { + sum += exp(-pow(current_piece, 2)) * span; + } + sum = sum * (2.0/sqrt(M_PI)); + + // Mke sure result isn't higher than 1.0 + if(sum > 1.0) { - if(j % 2 == 0) - { - sign = 1; - } - else - { - sign = -1; - } - // Calculate factorial od j - if(j > 0) - { - factorial_of_j *= j; - } - sum = sum + (sign * powl(x, (long double)i)/((long double)i * factorial_of_j)); + sum = 1.0; } - sum = sum * 2/sqrt(M_PI); + // If argument was negative, neagte result + if(x < 0) + { + sum *= -1; + } + return sum; } \ No newline at end of file