├── srcs ├── fuzzers │ ├── word.h │ ├── r2.h │ ├── font.h │ ├── defender.h │ ├── chrome.h │ ├── helpers.h │ ├── chrome │ │ ├── ipcgen.h │ │ └── ipcgen.dc │ ├── pdf.h │ ├── chrome.dc │ ├── r2.dc │ ├── font.dc │ ├── defender.dc │ └── word.c ├── vm │ ├── x86_passthrough.h │ ├── x86_user.h │ ├── x86_user.c │ ├── vm.h │ ├── svm.asm │ ├── vm_x86.h │ ├── svm.h │ ├── vm_x86.c │ ├── vm.c │ └── x86_passthrough.c ├── disk │ ├── ide.h │ └── ide.c ├── disp │ ├── disp.h │ └── disp.c ├── perf │ ├── perf.h │ └── perf.c ├── time │ ├── time.h │ └── time.c ├── interrupts │ ├── interrupts.h │ └── interrupts.asm ├── generic │ ├── locks.h │ ├── stdlib.h │ └── locks.c ├── dstruc │ ├── hash_table.h │ └── hash_table.c ├── task │ ├── task.h │ └── task.c ├── net │ ├── x540.h │ └── net.h ├── rstate │ ├── rstate.c │ └── rstate.h ├── cpu │ ├── cpu.h │ ├── acpi.h │ └── cpu.c ├── boot │ └── boot.c ├── mm │ └── mm.h ├── grilled_cheese.h └── emu │ └── mips.h ├── LICENSE ├── TODO └── README.md /srcs/fuzzers/word.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | rstate_t 4 | fuzz_word(void); 5 | 6 | -------------------------------------------------------------------------------- /srcs/fuzzers/r2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | _Success_(return == RSTATE_SUCCESS) 4 | _Ret_maybenull_ 5 | rstate_t 6 | fuzz_r2(void); 7 | 8 | -------------------------------------------------------------------------------- /srcs/fuzzers/font.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | _Success_(return == RSTATE_SUCCESS) 4 | _Ret_maybenull_ 5 | rstate_t 6 | fuzz_font(void); 7 | 8 | -------------------------------------------------------------------------------- /srcs/fuzzers/defender.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | _Success_(return == RSTATE_SUCCESS) 4 | _Ret_maybenull_ 5 | rstate_t 6 | fuzz_defender(void); 7 | 8 | -------------------------------------------------------------------------------- /srcs/vm/x86_passthrough.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | _Success_(return == RSTATE_SUCCESS) 4 | _Ret_maybenull_ 5 | _Must_inspect_result_ 6 | rstate_t 7 | x86_passthrough_start(void); 8 | 9 | -------------------------------------------------------------------------------- /srcs/disk/ide.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | rstate_t 4 | ide_pio_read_sectors( 5 | _In_ uint64_t lba, 6 | _Out_writes_bytes_all_(512) uint8_t *buf, 7 | _In_ size_t buf_len); 8 | 9 | -------------------------------------------------------------------------------- /srcs/disp/disp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void 4 | disp_err_mode(void); 5 | 6 | void 7 | puts_nolock(_In_z_ const char *str); 8 | 9 | void 10 | printf(_In_z_ _Printf_format_string_ const char *format, ...) 11 | __attribute__((format(printf, 1, 2))); 12 | 13 | -------------------------------------------------------------------------------- /srcs/perf/perf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct _pmc_desc { 4 | unsigned int event; 5 | unsigned int umask; 6 | 7 | const char *name; 8 | }; 9 | 10 | rstate_t 11 | perf_get_pmc_by_id( 12 | unsigned int perf_id, 13 | const struct _pmc_desc **pmc); 14 | 15 | -------------------------------------------------------------------------------- /srcs/time/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void 4 | rdtsc_calibrate(void); 5 | 6 | uint64_t 7 | rdtsc_freq(void); 8 | 9 | uint64_t 10 | rdtsc_future(_In_ uint64_t microseconds); 11 | 12 | uint64_t 13 | rdtsc_uptime(void); 14 | 15 | void 16 | rdtsc_sleep(_In_ uint64_t microseconds); 17 | 18 | -------------------------------------------------------------------------------- /srcs/fuzzers/chrome.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_IPC_SIZE (4 * 1024) 4 | #define NUM_IPC_MESSAGES 64 5 | 6 | struct _ipc_stream { 7 | struct { 8 | int filled; 9 | uint8_t msg[MAX_IPC_SIZE]; 10 | } ipc[NUM_IPC_MESSAGES]; 11 | }; 12 | 13 | rstate_t 14 | fuzz_chrome(void); 15 | 16 | -------------------------------------------------------------------------------- /srcs/interrupts/interrupts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void 4 | interrupts_enable(void); 5 | 6 | void 7 | interrupts_disable(void); 8 | 9 | void 10 | iret_stub(void); 11 | 12 | uintptr_t 13 | enter_um_guest(const struct _iret *iret, struct _iret *save, 14 | uint64_t *x86_regs); 15 | 16 | void 17 | profiling_dump(void); 18 | 19 | void 20 | request_soft_reboot(const void *dev); 21 | 22 | void 23 | pic_init(void); 24 | 25 | rstate_t 26 | interrupts_init(void); 27 | 28 | -------------------------------------------------------------------------------- /srcs/generic/locks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* All spinlock definitions on the system. To add a new spinlock, simply 4 | * add another definition to this enum. Make sure that that last entry in the 5 | * enum is MAX_SPINLOCK_ID 6 | */ 7 | enum spinlock_id { 8 | PAGE_TABLE_LOCK, 9 | DISP_LOCK, 10 | NUMA_MEMORY_LOCK, 11 | MAX_SPINLOCK_ID 12 | }; 13 | 14 | struct _spinlock { 15 | volatile unsigned int lock; 16 | volatile unsigned int unlock; 17 | }; 18 | 19 | void 20 | spinlock_acquire(_In_ enum spinlock_id id); 21 | 22 | void 23 | spinlock_release(_In_ enum spinlock_id id); 24 | 25 | -------------------------------------------------------------------------------- /srcs/dstruc/hash_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct _hash_table { 4 | uint64_t bits; 5 | uint64_t entries; 6 | 7 | void ***seq_data; 8 | 9 | struct { 10 | __m128i hash; 11 | void *data; 12 | } entry[1]; 13 | }; 14 | 15 | rstate_t 16 | ht_create(_In_ uint64_t size, _Outptr_ struct _hash_table **out_ht); 17 | 18 | void* 19 | ht_rand(_In_ volatile struct _hash_table *ht); 20 | 21 | int 22 | ht_fetch_or_lock( 23 | _In_ volatile struct _hash_table *ht, 24 | _In_ __m128i hash, 25 | _Outptr_ void **ret); 26 | 27 | void* 28 | ht_probe( 29 | _In_ volatile struct _hash_table *ht, 30 | _In_ __m128i hash); 31 | 32 | -------------------------------------------------------------------------------- /srcs/vm/x86_user.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct _x86_user_state { 4 | uintptr_t guest_cr3; 5 | 6 | void *pivot_addr; 7 | }; 8 | 9 | rstate_t 10 | x86_user_create(_In_ struct _vm *vm); 11 | 12 | rstate_t 13 | x86_user_step(_In_ struct _vm *vm); 14 | 15 | rstate_t 16 | x86_user_map_phys( 17 | _In_ struct _vm *vm, 18 | _In_ uint64_t address, 19 | _In_ int readable, 20 | _In_ int writable, 21 | _In_ int executable, 22 | _In_ uint64_t backing_page); 23 | 24 | void 25 | x86_user_dump_state(_In_ struct _vm *vm); 26 | 27 | rstate_t 28 | x86_user_guest_virt_to_host_phys( 29 | _In_ struct _vm *vm, 30 | _In_ uint64_t guest_vaddr, 31 | _In_ int is_read, 32 | _In_ int is_write, 33 | _In_ int is_exec, 34 | _Out_ uintptr_t *host_paddr); 35 | 36 | -------------------------------------------------------------------------------- /srcs/task/task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct _task { 4 | /* 0 if this task is available for use, 1 if it is already in use */ 5 | int in_use; 6 | 7 | /* 0 if this is not an init task, 1 if it is */ 8 | int is_init; 9 | 10 | /* Stack and depth used by the rstate subsystem */ 11 | const struct _return_state *rstate_stack[RSTATE_STACK_ENTRIES]; 12 | int rstate_stack_depth; 13 | 14 | /* Interrupts that are allowed when this task is running. If an interrupt 15 | * occurs which is not allowed during a task a panic will occur. 16 | */ 17 | uint8_t interrupt_allowed[256]; 18 | 19 | /* Physical 4k page free list */ 20 | uintptr_t free_list; 21 | size_t free_list_entries; 22 | }; 23 | 24 | void 25 | task_create_init(void); 26 | 27 | struct _task* 28 | task_create(void); 29 | 30 | void 31 | task_destroy(struct _task *task); 32 | 33 | -------------------------------------------------------------------------------- /srcs/net/x540.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define X540_NUM_RX 1024 6 | #define X540_NUM_TX 1024 7 | 8 | struct _x540_rx_ring { 9 | uintptr_t addr; 10 | uint64_t status; 11 | }; 12 | 13 | struct _x540_tx_ring { 14 | uintptr_t addr; 15 | 16 | union { 17 | struct { 18 | uint64_t length:16; 19 | uint64_t cso:8; 20 | uint64_t cmd:8; 21 | uint64_t dd:1; 22 | uint64_t rsvd:7; 23 | uint64_t css:8; 24 | uint64_t vlan:16; 25 | } b; 26 | uint64_t val; 27 | } status; 28 | }; 29 | 30 | struct _x540_queue { 31 | uintptr_t rx_ring_phys; 32 | uintptr_t tx_ring_phys; 33 | struct _x540_rx_ring *rx_ring; 34 | struct _x540_tx_ring *tx_ring; 35 | 36 | void *rx_bufs[X540_NUM_RX]; 37 | void *tx_bufs[X540_NUM_TX]; 38 | 39 | uint64_t rx_head; 40 | uint64_t tx_head; 41 | uint64_t tx_tail; 42 | }; 43 | 44 | rstate_t 45 | x540_init(struct _net_device *device); 46 | 47 | rstate_t 48 | x540_queue_init(struct _net_queue *queue); 49 | 50 | -------------------------------------------------------------------------------- /srcs/rstate/rstate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const struct _return_state rstate_invalid = 5 | { RSTATE_CODE_INVALID, __LINE__, __FILE__, "Invalid rstate", "" }; 6 | 7 | void 8 | rstate_push(rstate_t rstate) 9 | { 10 | if(current_task->rstate_stack_depth == RSTATE_STACK_ENTRIES){ 11 | return; 12 | } 13 | 14 | current_task->rstate_stack[current_task->rstate_stack_depth] = rstate; 15 | current_task->rstate_stack_depth++; 16 | 17 | return; 18 | } 19 | 20 | void 21 | rstate_clear(void) 22 | { 23 | current_task->rstate_stack_depth = 0; 24 | return; 25 | } 26 | 27 | void 28 | rstate_unwind(void) 29 | { 30 | int i; 31 | 32 | for(i = 0; i < current_task->rstate_stack_depth; i++){ 33 | printf("%s:%u %s() %s", 34 | current_task->rstate_stack[i]->source_fn, 35 | current_task->rstate_stack[i]->source_line, 36 | current_task->rstate_stack[i]->funcname, 37 | current_task->rstate_stack[i]->str); 38 | } 39 | 40 | return; 41 | } 42 | 43 | void 44 | rstate_panic(void) 45 | { 46 | printf("!!! PANIC !!!"); 47 | rstate_unwind(); 48 | panic("rstate_panic() invoked"); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gamozo Labs, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /srcs/vm/x86_user.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | rstate_t 5 | x86_user_create(_In_ struct _vm *vm) 6 | { 7 | vm->step = x86_user_step; 8 | vm->map_phys = x86_user_map_phys; 9 | vm->dump_state = x86_user_dump_state; 10 | vm->guest_phys_to_host_phys = x86_user_guest_virt_to_host_phys; 11 | vm->guest_virt_to_host_phys = x86_user_guest_virt_to_host_phys; 12 | 13 | return RSTATE_SUCCESS; 14 | } 15 | 16 | rstate_t 17 | x86_user_step(_In_ struct _vm *vm) 18 | { 19 | return RSTATE_SUCCESS; 20 | } 21 | 22 | rstate_t 23 | x86_user_map_phys( 24 | _In_ struct _vm *vm, 25 | _In_ uint64_t address, 26 | _In_ int readable, 27 | _In_ int writable, 28 | _In_ int executable, 29 | _In_ uint64_t backing_page) 30 | { 31 | return RSTATE_SUCCESS; 32 | } 33 | 34 | void 35 | x86_user_dump_state(_In_ struct _vm *vm) 36 | { 37 | vm_x86_dump_state(vm); 38 | return; 39 | } 40 | 41 | rstate_t 42 | x86_user_guest_virt_to_host_phys( 43 | _In_ struct _vm *vm, 44 | _In_ uint64_t guest_vaddr, 45 | _In_ int is_read, 46 | _In_ int is_write, 47 | _In_ int is_exec, 48 | _Out_ uintptr_t *host_paddr) 49 | { 50 | return RSTATE_SUCCESS; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Code cleanup 2 | - Since free lists are contained by the task. Do not nuke the task free 3 | lists on new task creations or destroys. 4 | 5 | - Why is there a mm_cow_pf_handler() and a manual implementation in 6 | page_fault()? 7 | 8 | - mm_for_each_dirty_page() could use a more in depth audit 9 | 10 | - Move rng_seed to task structure? 11 | 12 | ===================================================== 13 | Code Audit 14 | 15 | - Ensure prototypes are correct and sane 16 | - Ensure code does not exceed 80 character lines 17 | - Write documentation for any undocumented functions 18 | - Read through code and make sure usage is sane and safe 19 | - Add to the TODO list for any things that cannot be immediately fixed, or 20 | future ideas 21 | - Check for security bugs 22 | - Check for race conditions on globals and current_cpu 23 | - Make sure SAL annotations are correct and as verbose as possible 24 | ===================================================== 25 | 26 | Current code audit status 27 | Started 2016/10/24 28 | 29 | [complete] mm/mm.c 30 | [complete] time/time.c 31 | [complete] cpu/cpu.c 32 | [complete] cpu/acpi.c 33 | [complete] ide/ide.c 34 | [complete] disp/disp.c 35 | [complete] dstruc/hash_table.c 36 | [complete] generic/locks.c 37 | [complete] generic/stdlib.c 38 | 39 | -------------------------------------------------------------------------------- /srcs/task/task.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NUM_TASKS_PER_CPU 4 6 | 7 | struct _cpu_task { 8 | struct _task init; 9 | struct _task tasks[NUM_TASKS_PER_CPU]; 10 | }; 11 | 12 | static struct _cpu_task cpu_tasks[256] = { { { 0 } } }; 13 | 14 | void 15 | task_create_init(void) 16 | { 17 | struct _task *tmp = &cpu_tasks[current_cpu->apic_id].init; 18 | 19 | /* Set task in use */ 20 | tmp->in_use = 1; 21 | 22 | /* Set that this is the init task */ 23 | tmp->is_init = 1; 24 | 25 | /* Allow all interrupts */ 26 | memset(tmp->interrupt_allowed, 1, 256); 27 | 28 | /* Swap in this task */ 29 | current_cpu->task = tmp; 30 | 31 | return; 32 | } 33 | 34 | struct _task* 35 | task_create(void) 36 | { 37 | int ii; 38 | struct _task *tmp; 39 | 40 | /* Look for a free task */ 41 | for(ii = 0; ii < NUM_TASKS_PER_CPU; ii++){ 42 | if(!cpu_tasks[current_cpu->apic_id].tasks[ii].in_use){ 43 | break; 44 | } 45 | } 46 | 47 | if(ii == NUM_TASKS_PER_CPU){ 48 | return NULL; 49 | } 50 | 51 | tmp = &cpu_tasks[current_cpu->apic_id].tasks[ii]; 52 | 53 | /* Zero out the task */ 54 | memset(tmp, 0, sizeof(*tmp)); 55 | 56 | /* Set task in use */ 57 | tmp->in_use = 1; 58 | 59 | /* Allow all exceptions */ 60 | memset(tmp->interrupt_allowed, 1, 32); 61 | 62 | return tmp; 63 | } 64 | 65 | void 66 | task_destroy(struct _task *task) 67 | { 68 | task->in_use = 0; 69 | return; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /srcs/cpu/cpu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Different CPU types */ 4 | enum _cpu_type { 5 | UNKNOWN, 6 | INTEL, 7 | AMD 8 | }; 9 | 10 | struct _cpu* 11 | get_current_cpu(void); 12 | 13 | void 14 | halt(void); 15 | 16 | void 17 | panic(_In_z_ const char *reason); 18 | 19 | int 20 | sync_bool_compare_and_swap_si128( 21 | _In_ volatile __m128i *src, _In_ __m128i cmp, _In_ __m128i val); 22 | 23 | uint64_t 24 | rdpmc(_In_ uint32_t ctr_id); 25 | 26 | void 27 | interrupts_enable_force(void); 28 | 29 | void 30 | interrupts_disable_force(void); 31 | 32 | void 33 | writedr0(_In_ uint64_t val); 34 | 35 | void 36 | writedr1(_In_ uint64_t val); 37 | 38 | void 39 | writedr2(_In_ uint64_t val); 40 | 41 | void 42 | writedr3(_In_ uint64_t val); 43 | 44 | void 45 | invlpg(_In_ void *addr); 46 | 47 | void 48 | lgdt(_In_ void *gdt); 49 | 50 | void 51 | lidt(_In_ void *idt); 52 | 53 | void 54 | ltr(_In_ uint16_t tr); 55 | 56 | void 57 | outb(_In_ uint16_t port, _In_ uint8_t val); 58 | 59 | void 60 | outd(_In_ uint16_t port, _In_ uint32_t val); 61 | 62 | uint8_t 63 | inb(_In_ uint16_t port); 64 | 65 | uint32_t 66 | ind(_In_ uint16_t port); 67 | 68 | uintptr_t 69 | readcr2(void); 70 | 71 | uintptr_t 72 | readcr3(void); 73 | 74 | void 75 | cpuid(_In_ uint32_t val, _Out_writes_bytes_all_(16) uint32_t *output); 76 | 77 | void 78 | wrmsr(_In_ uint32_t msr_id, _In_ uint64_t val); 79 | 80 | uint64_t 81 | rdmsr(_In_ uint32_t msr_id); 82 | 83 | enum _cpu_type 84 | get_cpu_type(void); 85 | 86 | int 87 | is_bsp(void); 88 | 89 | void 90 | cpu_start_aps(void); 91 | 92 | -------------------------------------------------------------------------------- /srcs/cpu/acpi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CPU_MAX_NUMA_ID 256 4 | #define CPU_MAX_REGIONS 8 5 | 6 | struct _cpu_info { 7 | int present; 8 | 9 | uint32_t apic_id; 10 | uint32_t numa_id; 11 | }; 12 | 13 | struct _node_info { 14 | int present; 15 | 16 | uint32_t numa_id; 17 | uint32_t num_regions; 18 | 19 | struct { 20 | uint64_t base; 21 | uint64_t size; 22 | int avail; 23 | } regions[CPU_MAX_REGIONS]; 24 | 25 | uint64_t cur_base; 26 | uint64_t cur_remain; 27 | }; 28 | 29 | #pragma pack(push, 1) 30 | struct _rsdp { 31 | char signature[8]; 32 | uint8_t checksum; 33 | char oem_id[6]; 34 | uint8_t revision; 35 | uint32_t rsdt_addr; 36 | }; 37 | 38 | struct _acpi_standard_header { 39 | char signature[4]; 40 | uint32_t length; 41 | uint8_t revision; 42 | uint8_t checksum; 43 | char oem_id[6]; 44 | char oem_table_id[8]; 45 | uint32_t oem_revision; 46 | uint32_t creator_id; 47 | uint32_t creator_revision; 48 | }; 49 | 50 | struct _rsdt { 51 | struct _acpi_standard_header hdr; 52 | 53 | uint32_t tables[128]; 54 | }; 55 | 56 | struct _madt { 57 | struct _acpi_standard_header hdr; 58 | 59 | uint32_t local_controller_addr; 60 | uint32_t flags; 61 | 62 | uint8_t payload[2048]; 63 | }; 64 | 65 | struct _srat { 66 | struct _acpi_standard_header hdr; 67 | 68 | uint32_t reserved1; 69 | uint64_t reserved2; 70 | 71 | uint8_t payload[8 * 1024]; 72 | }; 73 | #pragma pack(pop) 74 | 75 | rstate_t 76 | acpi_get_node_memory( 77 | _In_ uint32_t node_id, 78 | _In_ size_t amount, 79 | _Out_ uintptr_t *out_paddr); 80 | 81 | uint32_t 82 | acpi_get_node_id(_In_ uint32_t apic_id); 83 | 84 | rstate_t 85 | acpi_init(void); 86 | 87 | void 88 | cpu_dump_topology(void); 89 | 90 | -------------------------------------------------------------------------------- /srcs/fuzzers/helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX_MODULES 128 4 | 5 | struct _modlist { 6 | uint64_t base; 7 | uint64_t len; 8 | uint64_t end; 9 | 10 | __m128i hash; 11 | 12 | unsigned int namelen; 13 | uint8_t name[256]; 14 | }; 15 | 16 | struct _input_ent { 17 | uint64_t len; 18 | uint8_t buf[1]; 19 | }; 20 | 21 | struct _cc_entry { 22 | __m128i hash; 23 | }; 24 | 25 | struct _crash_entry { 26 | __m128i hash; 27 | }; 28 | 29 | struct _fuzzer { 30 | struct _hash_table *cc_db; 31 | struct _hash_table *input_db; 32 | struct _hash_table *crash_db; 33 | }; 34 | 35 | rstate_t 36 | fuzzer_create(struct _fuzzer **fuzzer_out); 37 | 38 | void 39 | rand_ftar( 40 | const void *ftar, 41 | uint64_t ftar_len, 42 | uint8_t **entry, 43 | uint64_t *entry_len); 44 | 45 | rstate_t 46 | fuzz_get_cc_db(struct _hash_table **db); 47 | 48 | rstate_t 49 | fuzz_get_input_db(struct _hash_table **db); 50 | 51 | rstate_t 52 | fuzz_get_crash_db(struct _hash_table **db); 53 | 54 | struct _input_ent* 55 | fuzz_get_input(__m128i input_hash); 56 | 57 | rstate_t 58 | fuzz_input_create(const void *buf, uint64_t len, __m128i *out_hash, 59 | int *new_entry); 60 | 61 | rstate_t 62 | fuzz_cc_report( 63 | struct _vm *vm, 64 | uint64_t from, 65 | uint64_t to, 66 | const void *buf, 67 | uint64_t len, 68 | int *new_ent); 69 | 70 | rstate_t 71 | fuzz_report_crash(struct _vm *vm, void *buf, size_t len, int *new_entry); 72 | 73 | rstate_t 74 | win32_gen_modlist(struct _vm *vm); 75 | 76 | struct _modlist* 77 | win32_resolve_module(struct _vm *vm, uint64_t rip); 78 | 79 | int 80 | win32_symhash(struct _vm *vm, uint64_t rip, __m128i *hash); 81 | 82 | __m128i 83 | win32_classify_crash(struct _vm *vm); 84 | 85 | -------------------------------------------------------------------------------- /srcs/fuzzers/chrome/ipcgen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum _chrome_ipctype { 4 | IPCTYPE_INT, 5 | IPCTYPE_STD_STRING, 6 | IPCTYPE_BOOL, 7 | IPCTYPE_GURL, 8 | IPCTYPE_INT64, 9 | IPCTYPE_STRING16, 10 | 11 | IPCTYPE_HOSTRESOURCE, 12 | IPCTYPE_SHARED_MEMORY_HANDLE, 13 | IPCTYPE_POINT, 14 | IPCTYPE_SIZE, 15 | IPCTYPE_RECT, 16 | IPCTYPE_DOUBLE, 17 | }; 18 | 19 | struct _chrome_ipc { 20 | const char *msg_class; 21 | 22 | void *func; 23 | uint32_t ipc_id; 24 | 25 | int in_params; 26 | int out_params; 27 | 28 | enum _chome_ipctype params[32]; 29 | }; 30 | 31 | #pragma pack(push, 1) 32 | struct _cipc_hostresource { 33 | int32_t instance; 34 | int32_t host_resource; 35 | }; 36 | 37 | struct _cipc_point { 38 | int32_t x; 39 | int32_t y; 40 | }; 41 | 42 | struct _cipc_size { 43 | int32_t width; 44 | int32_t height; 45 | }; 46 | 47 | struct _cipc_rect { 48 | struct _cipc_point origin; 49 | struct _cipc_size size; 50 | }; 51 | 52 | struct _cipc_shared_memory_handle { 53 | uint64_t handle; 54 | uint32_t pid; 55 | }; 56 | 57 | struct _chrome_ipc_header { 58 | uint32_t length; 59 | uint32_t route; 60 | uint32_t msg_id; 61 | 62 | union { 63 | struct { 64 | uint32_t priority_mask:2; 65 | uint32_t sync:1; 66 | uint32_t reply:1; 67 | uint32_t reply_error:1; 68 | uint32_t unblock:1; 69 | uint32_t pumping_msgs:1; 70 | uint32_t has_sent_time:1; 71 | 72 | uint32_t ref_number:24; 73 | } fields; 74 | 75 | uint32_t backing; 76 | } flags; 77 | 78 | uint32_t unknown; 79 | }; 80 | #pragma pack(pop) 81 | 82 | uint64_t 83 | gen_ipc_stream(_Out_writes_bytes_(len) uint8_t *payload, _In_ uint64_t len, 84 | _In_ uint64_t max_messages); 85 | 86 | uint64_t 87 | gen_ipc_rand(_Out_writes_bytes_(len) uint8_t *payload, _In_ uint64_t len, 88 | _In_ uint64_t max_messages); 89 | 90 | -------------------------------------------------------------------------------- /srcs/vm/vm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct _vm; 4 | 5 | enum _vm_type { 6 | GUEST_X86 7 | }; 8 | 9 | enum _vm_subtype { 10 | X86_USER, 11 | X86_SVM, 12 | X86_VTX 13 | }; 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | struct _vm { 20 | enum _vm_type type; 21 | enum _vm_subtype subtype; 22 | 23 | /* Register state for each arch */ 24 | union { 25 | struct _x86_regs x86_regs; 26 | } regs; 27 | 28 | union { 29 | /* State for SVM based x86 VMs */ 30 | struct _svm_vm *svm_state; 31 | } state; 32 | 33 | struct _modlist *modlist; 34 | uint64_t modlist_ents; 35 | 36 | rstate_t (*step)(struct _vm *vm); 37 | 38 | rstate_t (*map_phys)(struct _vm *vm, uint64_t address, 39 | int readable, int writable, int executable, 40 | uint64_t backing_page); 41 | 42 | rstate_t (*npf_handler)(struct _vm *vm, uint64_t address, 43 | int read_access, int write_access, int exec_access, 44 | int *handled); 45 | 46 | rstate_t (*guest_phys_to_host_phys)( 47 | struct _vm *vm, 48 | uint64_t guest_paddr, 49 | int is_read, 50 | int is_write, 51 | int is_exec, 52 | uint64_t *host_paddr); 53 | 54 | rstate_t (*guest_virt_to_host_phys)( 55 | struct _vm *vm, 56 | uint64_t guest_vaddr, 57 | int is_read, 58 | int is_write, 59 | int is_exec, 60 | uint64_t *host_paddr); 61 | 62 | void (*dump_state)(struct _vm *vm); 63 | }; 64 | 65 | rstate_t 66 | vm_create(const char *core_fn, struct _vm **out_vm); 67 | 68 | rstate_t 69 | vm_read_phys( 70 | struct _vm *vm, 71 | uint64_t guest_paddr, 72 | void *buf, 73 | uint64_t len); 74 | 75 | rstate_t 76 | vm_write_phys( 77 | struct _vm *vm, 78 | uint64_t guest_paddr, 79 | const void *buf, 80 | uint64_t len); 81 | 82 | rstate_t 83 | vm_read_virt( 84 | struct _vm *vm, 85 | uint64_t guest_vaddr, 86 | void *buf, 87 | uint64_t len); 88 | 89 | rstate_t 90 | vm_write_virt( 91 | struct _vm *vm, 92 | uint64_t guest_vaddr, 93 | const void *buf, 94 | uint64_t len); 95 | 96 | -------------------------------------------------------------------------------- /srcs/rstate/rstate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Success states */ 4 | #define RSTATE_SUCCESS NULL 5 | 6 | /* Error code used indicating invalid rstate. This occurs if an uninitialized 7 | * rstate is returned. 8 | */ 9 | #define RSTATE_CODE_INVALID 0xe1f2e965 10 | 11 | /* Error code indicating rstate is nested */ 12 | #define RSTATE_CODE_NESTED 0x9f1c0505 13 | 14 | /* Number of entires in the rstate stack */ 15 | #define RSTATE_STACK_ENTRIES 512 16 | 17 | /* Invalid state. Used for initializing rstate at a function start. */ 18 | extern const struct _return_state rstate_invalid; 19 | 20 | /* Quick defines for locals in any function that uses rstates. */ 21 | #define RSTATE_LOCALS rstate_t rstate = (&rstate_invalid), \ 22 | rstate_ret = (&rstate_invalid); 23 | 24 | #define RSTATE_RETURN \ 25 | if(rstate_ret != RSTATE_SUCCESS){ \ 26 | if(rstate_ret->code != RSTATE_CODE_NESTED) \ 27 | rstate_clear(); \ 28 | rstate_push(rstate_ret); \ 29 | } \ 30 | return rstate_ret; 31 | 32 | #define RSCHECK(statement, str) \ 33 | if(!(statement)){ \ 34 | static const struct _return_state rs = \ 35 | { 0, __LINE__, __FILE__, str, __FUNCTION__ }; \ 36 | rstate_ret = &rs; \ 37 | goto cleanup; \ 38 | } 39 | 40 | #define RSCHECK_NESTED(str) \ 41 | if(rstate != RSTATE_SUCCESS){ \ 42 | static const struct _return_state rs = \ 43 | { RSTATE_CODE_NESTED, __LINE__, __FILE__, str, __FUNCTION__ }; \ 44 | rstate_ret = &rs; \ 45 | goto cleanup; \ 46 | } 47 | 48 | #define RSTATE_PANIC \ 49 | if(rstate_ret != RSTATE_SUCCESS){ \ 50 | if(rstate_ret->code != RSTATE_CODE_NESTED) \ 51 | rstate_clear(); \ 52 | rstate_push(rstate_ret); \ 53 | } \ 54 | rstate_panic(); 55 | 56 | struct _return_state { 57 | const uint32_t code; 58 | const uint32_t source_line; 59 | const char *source_fn; 60 | const char *str; 61 | const char *funcname; 62 | }; 63 | 64 | typedef const struct _return_state *rstate_t; 65 | 66 | void 67 | rstate_push(rstate_t rstate); 68 | 69 | void 70 | rstate_clear(void); 71 | 72 | void 73 | rstate_unwind(void); 74 | 75 | void 76 | rstate_panic(void); 77 | 78 | -------------------------------------------------------------------------------- /srcs/generic/stdlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int 4 | overlaps(_In_ uint64_t x1, _In_ uint64_t x2, _In_ uint64_t y1, 5 | _In_ uint64_t y2); 6 | 7 | int 8 | contains(_In_ uint64_t x1, _In_ uint64_t x2, _In_ uint64_t y1, 9 | _In_ uint64_t y2); 10 | 11 | void* 12 | memset( 13 | _Out_writes_bytes_all_(size) void *dest, 14 | _In_ uint8_t c, 15 | _In_ size_t size); 16 | 17 | void* 18 | memcpy( 19 | _Out_writes_bytes_all_(size) void *dest, 20 | _In_reads_bytes_(size) const void *src, 21 | _In_ size_t size); 22 | 23 | int 24 | memcmp( 25 | _In_reads_bytes_(size) const void *a, 26 | _In_reads_bytes_(size) const void *b, 27 | _In_ size_t size); 28 | 29 | size_t 30 | strlen(_In_z_ const void *str); 31 | 32 | __m128i 33 | falkhash(_In_reads_bytes_(len) const void *pbuf, _In_ size_t len); 34 | 35 | uint64_t 36 | aes_rand(void); 37 | 38 | size_t 39 | vsnprintf( 40 | _Out_writes_bytes_(len) char *buf, 41 | _In_ size_t len, 42 | _In_z_ _Printf_format_string_ const char *format, 43 | _In_ va_list ap); 44 | 45 | size_t 46 | snprintf( 47 | _Out_writes_bytes_(len) char *buf, 48 | _In_ size_t len, 49 | _In_z_ _Printf_format_string_ const char *format, 50 | ...) 51 | __attribute__((format(printf, 3, 4))); 52 | 53 | void* 54 | memrmem( 55 | _In_reads_bytes_(haystack_len) const void *haystack, 56 | _In_ size_t haystack_len, 57 | _In_reads_bytes_(needle_len) const void *needle, 58 | _In_ size_t needle_len); 59 | 60 | int 61 | isalnum(_In_ uint8_t c); 62 | 63 | int 64 | isdigit(_In_ uint8_t c); 65 | 66 | int 67 | isxdigit(_In_ uint8_t c); 68 | 69 | size_t 70 | atoi(_In_z_ const char *buf); 71 | 72 | size_t 73 | nonnullcount(_In_reads_bytes_(len) const uint8_t *buf, _In_ size_t len); 74 | 75 | size_t 76 | nonnulllast(_In_reads_bytes_(len) const uint8_t *buf, _In_ size_t len); 77 | 78 | int 79 | hasheq(_In_ __m128i a, _In_ __m128i b); 80 | 81 | int 82 | hashnull(_In_ __m128i hash); 83 | 84 | -------------------------------------------------------------------------------- /srcs/generic/locks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* Storage for all locks */ 7 | static volatile struct _spinlock spinlocks[MAX_SPINLOCK_ID] = { { 0 } }; 8 | 9 | /* spinlock_acquire() 10 | * 11 | * Summary: 12 | * 13 | * This function acquires the spinlock corresponding to id. If the spinlock 14 | * is already held on this CPU, a deadlock will occur. We track this and are 15 | * able to panic when a deadlock is about to happen. 16 | * 17 | * In the special case that the spinlock is the display lock, we will output 18 | * to the screen without a lock. This may result in mangled output on the 19 | * screen. 20 | * 21 | * Parameters: 22 | * 23 | * _In_ id - Spinlock ID to acquire 24 | */ 25 | void 26 | spinlock_acquire(_In_ enum spinlock_id id) 27 | { 28 | unsigned int ticket; 29 | 30 | /* Bounds check */ 31 | if(id >= MAX_SPINLOCK_ID){ 32 | panic("Spinlock ID invalid for acquire"); 33 | } 34 | 35 | /* First, validate that this cpu doesn't already have this spinlock 36 | * held 37 | */ 38 | if(__sync_val_compare_and_swap( 39 | ¤t_cpu->spinlocks_held[id], 0, 1) != 0){ 40 | if(id == DISP_LOCK){ 41 | disp_err_mode(); 42 | puts_nolock("Disp lock deadlock"); 43 | halt(); 44 | } else { 45 | printf("Already held lock %d", id); 46 | panic("Spinlock already held on CPU, deadlock"); 47 | } 48 | } 49 | 50 | /* Grab a ticket to wait in queue until it's our turn */ 51 | ticket = __sync_fetch_and_add(&spinlocks[id].lock, 1); 52 | while(ticket != spinlocks[id].unlock){ 53 | _mm_pause(); 54 | } 55 | 56 | return; 57 | } 58 | 59 | /* spinlock_release() 60 | * 61 | * Summary: 62 | * 63 | * This function releases a spinlock acquired by spinlock_acquire(). If the 64 | * spinlock is not held on this CPU we will panic as we're trying to release a 65 | * lock not owned by us. 66 | * 67 | * Parameters: 68 | * 69 | * _In_ id - Spinlock ID to release 70 | */ 71 | void 72 | spinlock_release(_In_ enum spinlock_id id) 73 | { 74 | /* Bounds check */ 75 | if(id >= MAX_SPINLOCK_ID){ 76 | panic("Spinlock ID invalid for release"); 77 | } 78 | 79 | /* First, validate that this lock is held on this CPU */ 80 | if(__sync_val_compare_and_swap( 81 | ¤t_cpu->spinlocks_held[id], 1, 0) != 1){ 82 | printf("Not held lock %d", id); 83 | panic("Spinlock not held at time of release"); 84 | } 85 | 86 | /* Bump up the unlock count */ 87 | spinlocks[id].unlock++; 88 | 89 | return; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /srcs/fuzzers/pdf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PDF_OBJECTS_MAX 500 4 | 5 | enum _pdf_type { 6 | INVALID, 7 | DICT, 8 | NAME, 9 | NUMBER, 10 | REFERENCE, 11 | HEXSTR, 12 | ARRAY, 13 | STRING, 14 | OBJECT, 15 | BOOLEAN, 16 | STREAM, 17 | PDF_FILE, 18 | NULL_OBJ 19 | }; 20 | 21 | struct _pdf_xref { 22 | uint64_t obj_num; 23 | uint64_t gen_num; 24 | uint8_t type; 25 | }; 26 | 27 | struct _pdf_dict { 28 | uint64_t num_objects; 29 | struct _pdf_object *objects[PDF_OBJECTS_MAX]; 30 | }; 31 | 32 | struct _pdf_array { 33 | uint64_t num_objects; 34 | struct _pdf_object *objects[PDF_OBJECTS_MAX]; 35 | }; 36 | 37 | struct _pdf_name { 38 | char name[1024]; 39 | struct _pdf_object *object; 40 | }; 41 | 42 | struct _pdf_boolean { 43 | int val; 44 | }; 45 | 46 | struct _pdf_reference { 47 | uint64_t obj_num; 48 | uint64_t gen_num; 49 | }; 50 | 51 | struct _pdf_hexstr { 52 | uint8_t *str; 53 | uint64_t len; 54 | }; 55 | 56 | struct _pdf_str { 57 | uint8_t *str; 58 | uint64_t len; 59 | }; 60 | 61 | struct _pdf_stream { 62 | uint8_t *payload; 63 | uint64_t length; 64 | }; 65 | 66 | struct _pdf_indirect_object { 67 | uint64_t obj_num; 68 | uint64_t gen_num; 69 | 70 | struct _pdf_object *object; 71 | struct _pdf_object *stream; 72 | }; 73 | 74 | struct _pdf_number { 75 | int64_t number; 76 | uint64_t decimal; 77 | 78 | int is_float; 79 | }; 80 | 81 | struct _pdf_file { 82 | uint64_t num_objects; 83 | struct _pdf_object *objects[PDF_OBJECTS_MAX]; 84 | struct _pdf_object *trailer; 85 | }; 86 | 87 | struct _pdf_object { 88 | enum _pdf_type type; 89 | 90 | union { 91 | struct _pdf_name name; 92 | struct _pdf_number number; 93 | struct _pdf_reference reference; 94 | struct _pdf_hexstr hexstr; 95 | struct _pdf_dict dict; 96 | struct _pdf_array array; 97 | struct _pdf_str str; 98 | struct _pdf_indirect_object indirect; 99 | struct _pdf_boolean boolean; 100 | struct _pdf_stream stream; 101 | struct _pdf_file file; 102 | } u; 103 | }; 104 | 105 | char* 106 | pdf_type_to_str(enum _pdf_type type); 107 | 108 | void 109 | pdf_free(struct _pdf_object *object); 110 | 111 | void 112 | pdf_digest(struct _pdf_object *object); 113 | 114 | void 115 | pdf_corrupt(struct _pdf_object *object); 116 | 117 | uint64_t 118 | pdf_genpdf( 119 | char *buf, 120 | uint64_t len, 121 | const struct _pdf_object *object); 122 | 123 | rstate_t 124 | pdf_parse_object( 125 | const uint8_t *object_str, 126 | uint64_t object_str_len, 127 | const uint8_t **out_object_str, 128 | struct _pdf_object **out_object); 129 | 130 | rstate_t 131 | loadpdf( 132 | const uint8_t *pdf, 133 | uint64_t pdf_len, 134 | struct _pdf_object **out_object); 135 | 136 | -------------------------------------------------------------------------------- /srcs/vm/svm.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | section .text 4 | 5 | struc vm 6 | .host_vmcb: resq 1 7 | .vmcb: resq 1 8 | 9 | .host_vmcb_pa: resq 1 10 | .vmcb_pa: resq 1 11 | 12 | .host_xsave: resq 1 13 | .xsave: resq 1 14 | endstruc 15 | 16 | struc gprs 17 | .rax: resq 1 18 | .rbx: resq 1 19 | .rcx: resq 1 20 | .rdx: resq 1 21 | .rdi: resq 1 22 | .rsi: resq 1 23 | .rbp: resq 1 24 | .rsp: resq 1 25 | .r8: resq 1 26 | .r9: resq 1 27 | .r10: resq 1 28 | .r11: resq 1 29 | .r12: resq 1 30 | .r13: resq 1 31 | .r14: resq 1 32 | .r15: resq 1 33 | .rip: resq 1 34 | .rfl: resq 1 35 | endstruc 36 | 37 | global svm_asm_step 38 | svm_asm_step: 39 | clgi 40 | 41 | ; Save all non-volatile registers 42 | push rbx 43 | push rbp 44 | push rsi 45 | push rdi 46 | push r12 47 | push r13 48 | push r14 49 | push r15 50 | 51 | ; Save the vm pointer and regs 52 | push rdi 53 | push rsi 54 | 55 | ; r15 - Pointer to struct _svm_vm 56 | ; r14 - Pointer to gprs 57 | mov r15, rdi 58 | mov r14, rsi 59 | 60 | ; Save host state 61 | mov edx, 0x40000000 62 | mov eax, 0x00000007 63 | xor ecx, ecx 64 | xsetbv 65 | mov rbx, [r15 + vm.host_xsave] 66 | xsave [rbx] 67 | mov rax, [r15 + vm.host_vmcb_pa] 68 | vmsave 69 | 70 | ; Load guest xsave 71 | mov edx, 0x40000000 72 | mov eax, 0x00000007 73 | mov rbx, [r15 + vm.xsave] 74 | xrstor [rbx] 75 | 76 | ; Load guest vmsave 77 | mov rax, [r15 + vm.vmcb_pa] 78 | vmload 79 | 80 | mov rbx, [r14 + gprs.rbx] 81 | mov rcx, [r14 + gprs.rcx] 82 | mov rdx, [r14 + gprs.rdx] 83 | mov rdi, [r14 + gprs.rdi] 84 | mov rsi, [r14 + gprs.rsi] 85 | mov rbp, [r14 + gprs.rbp] 86 | mov r8, [r14 + gprs.r8] 87 | mov r9, [r14 + gprs.r9] 88 | mov r10, [r14 + gprs.r10] 89 | mov r11, [r14 + gprs.r11] 90 | mov r12, [r14 + gprs.r12] 91 | mov r13, [r14 + gprs.r13] 92 | mov r15, [r14 + gprs.r15] 93 | mov r14, [r14 + gprs.r14] 94 | 95 | vmrun 96 | 97 | ; Restore gprs 98 | mov rax, [rsp] 99 | 100 | mov [rax + gprs.rbx], rbx 101 | mov [rax + gprs.rcx], rcx 102 | mov [rax + gprs.rdx], rdx 103 | mov [rax + gprs.rsi], rsi 104 | mov [rax + gprs.rdi], rdi 105 | mov [rax + gprs.rbp], rbp 106 | mov [rax + gprs.r8], r8 107 | mov [rax + gprs.r9], r9 108 | mov [rax + gprs.r10], r10 109 | mov [rax + gprs.r11], r11 110 | mov [rax + gprs.r12], r12 111 | mov [rax + gprs.r13], r13 112 | mov [rax + gprs.r14], r14 113 | mov [rax + gprs.r15], r15 114 | 115 | ; Get the gprs and vm pointer 116 | pop r14 117 | pop r15 118 | 119 | ; Save guest state 120 | mov edx, 0x40000000 121 | mov eax, 0x00000007 122 | xor ecx, ecx 123 | xsetbv 124 | mov rbx, [r15 + vm.xsave] 125 | xsave [rbx] 126 | mov rax, [r15 + vm.vmcb_pa] 127 | vmsave 128 | 129 | ; Load host xsave 130 | mov edx, 0x40000000 131 | mov eax, 0x00000007 132 | mov rbx, [r15 + vm.host_xsave] 133 | xrstor [rbx] 134 | 135 | ; Load host vmsave 136 | mov rax, [r15 + vm.host_vmcb_pa] 137 | vmload 138 | 139 | ; Restore all non-volatile registers 140 | pop r15 141 | pop r14 142 | pop r13 143 | pop r12 144 | pop rdi 145 | pop rsi 146 | pop rbp 147 | pop rbx 148 | stgi 149 | ret 150 | 151 | -------------------------------------------------------------------------------- /srcs/disk/ide.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define IO_ADDR_BASE 0x1f0 6 | 7 | #define IDE_DATA (IO_ADDR_BASE + 0) 8 | #define IDE_ERROR (IO_ADDR_BASE + 1) 9 | #define IDE_FEATURES (IO_ADDR_BASE + 1) 10 | #define IDE_SECCOUNT0 (IO_ADDR_BASE + 2) 11 | #define IDE_SECCOUNT1 (IO_ADDR_BASE + 2) 12 | #define IDE_LBA0 (IO_ADDR_BASE + 3) 13 | #define IDE_LBA3 (IO_ADDR_BASE + 3) 14 | #define IDE_LBA1 (IO_ADDR_BASE + 4) 15 | #define IDE_LBA4 (IO_ADDR_BASE + 4) 16 | #define IDE_LBA2 (IO_ADDR_BASE + 5) 17 | #define IDE_LBA5 (IO_ADDR_BASE + 5) 18 | #define IDE_HDDEVSEL (IO_ADDR_BASE + 6) 19 | #define IDE_COMMAND (IO_ADDR_BASE + 7) 20 | #define IDE_STATUS (IO_ADDR_BASE + 7) 21 | 22 | #define IDE_CONTROL 0x3f6 23 | 24 | #define IDE_OUT_WAIT(port, byte) {outb(port, byte); ide_wait_busy();} 25 | 26 | /* ide_wait_busy() 27 | * 28 | * Summary: 29 | * 30 | * This function waits until the busy bit is no longer set on the IDE drive. 31 | */ 32 | void 33 | ide_wait_busy(void) 34 | { 35 | while(inb(IDE_STATUS) & 0x80); 36 | return; 37 | } 38 | 39 | /* ide_pio_read_sectors() 40 | * 41 | * Summary: 42 | * 43 | * This function reads a single sector from the IDE drive starting at 44 | * an LBA. It does the read via PIO mode, thus this is extremely slow. 45 | * This code is NOT thread safe. 46 | * 47 | * Parameters: 48 | * 49 | * _In_ lba - LBA of the data to read 50 | * _Out_ buf - Pointer to caller allocated buffer to receive 1 sector (512 51 | * bytes). 52 | * _In_ buf_len - Length of the buffer provided (in bytes) 53 | * 54 | * Returns: 55 | * 56 | * RSTATE_SUCCESS on success, otherwise error. 57 | */ 58 | rstate_t 59 | ide_pio_read_sectors( 60 | _In_ uint64_t lba, 61 | _Out_writes_bytes_all_(512) uint8_t *buf, 62 | _In_ size_t buf_len) 63 | { 64 | int ii; 65 | 66 | static int reset = 0; 67 | 68 | RSTATE_LOCALS; 69 | 70 | RSCHECK(buf_len >= 512, 71 | "Buffer supplied not large enough for 512-byte sector"); 72 | 73 | /* If the device is busy or this is our first entry of the function, 74 | * reset the device. 75 | */ 76 | if(!reset || (inb(IDE_STATUS) & (1 << 7))){ 77 | /* Reset the device */ 78 | outb(IDE_CONTROL, (1 << 2)); 79 | outb(IDE_CONTROL, 0); 80 | ide_wait_busy(); 81 | 82 | reset = 1; 83 | } 84 | 85 | /* Disable interrupts */ 86 | IDE_OUT_WAIT(IDE_CONTROL, 2); 87 | 88 | /* Select master drive with LBA addressing mode */ 89 | IDE_OUT_WAIT(IDE_HDDEVSEL, 0xE0); 90 | 91 | /* Set up to read one sector with the LBA specified */ 92 | IDE_OUT_WAIT(IDE_SECCOUNT1, 0); 93 | IDE_OUT_WAIT(IDE_LBA5, (lba >> (8 * 5)) & 0xff); 94 | IDE_OUT_WAIT(IDE_LBA4, (lba >> (8 * 4)) & 0xff); 95 | IDE_OUT_WAIT(IDE_LBA3, (lba >> (8 * 3)) & 0xff); 96 | IDE_OUT_WAIT(IDE_SECCOUNT0, 1); 97 | IDE_OUT_WAIT(IDE_LBA2, (lba >> (8 * 2)) & 0xff); 98 | IDE_OUT_WAIT(IDE_LBA1, (lba >> (8 * 1)) & 0xff); 99 | IDE_OUT_WAIT(IDE_LBA0, (lba >> (8 * 0)) & 0xff); 100 | 101 | /* Send the 48-bit LBA PIO read request command */ 102 | outb(IDE_COMMAND, 0x24); 103 | 104 | /* Poll for busy to clear, check for errors as well. */ 105 | for( ; ; ){ 106 | uint8_t status = inb(IDE_STATUS); 107 | 108 | /* Check for an error */ 109 | RSCHECK(!(status & (1 << 0)), 110 | "Error bit was set in status during IDE read"); 111 | 112 | /* Check for a drive fault */ 113 | RSCHECK(!(status & (1 << 5)), 114 | "Drive fault bit was set in status during IDE read"); 115 | 116 | /* Check if we're still busy, if we're not, end the loop */ 117 | if(!(status & (1 << 7))){ 118 | break; 119 | } 120 | } 121 | 122 | /* Read in all 512 bytes of data */ 123 | for(ii = 0; ii < 512; ii++){ 124 | buf[ii] = inb(IDE_DATA); 125 | } 126 | 127 | rstate_ret = rstate = RSTATE_SUCCESS; 128 | cleanup: 129 | RSTATE_RETURN; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /srcs/time/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Rate that the rdtsc increments at, in MHz. 2300 would indicate a 2.3GHz 6 | * processor. Set by rdtsc_calibrate() early in the boot process. 7 | */ 8 | static uint64_t rdtsc_inc_freq = 0; 9 | 10 | /* rdtsc_calibrate() 11 | * 12 | * Summary: 13 | * 14 | * Using the PIT, determine the frequency of rdtsc. Round this frequency to 15 | * the nearest 100MHz and store it in the rdtsc_inc_freq global. This function 16 | * should only be used as part of the system init sequence. 17 | */ 18 | void 19 | rdtsc_calibrate(void) 20 | { 21 | uint64_t start, rounded_rate; 22 | double elapsed, computed_rate; 23 | 24 | /* Store off the current rdtsc value */ 25 | start = __rdtsc(); 26 | 27 | /* Program the PIT to use mode 0 (interrupt after countdown) to count 28 | * down from 65535. This causes an interrupt to occur after about 29 | * 54.92 milliseconds (65535 / 1193182). We mask interrupts from the 30 | * PIT, thus we poll by sending the read back command to check whether 31 | * the output pin is set to 1, indicating the countdown completed. 32 | */ 33 | outb(0x43, 0x30); 34 | outb(0x40, 0xff); 35 | outb(0x40, 0xff); 36 | 37 | for( ; ; ){ 38 | /* Send the read back command to latch status on channel 0 */ 39 | outb(0x43, 0xe2); 40 | 41 | /* If the output pin is high, then we know the countdown is done. 42 | * Break from the loop. 43 | */ 44 | if(inb(0x40) & 0x80){ 45 | break; 46 | } 47 | } 48 | 49 | /* Compute the time, in seconds, that the countdown was supposed to take */ 50 | elapsed = 65536.0 / 1193182.0; 51 | 52 | /* Compute MHz for the rdtsc */ 53 | computed_rate = (double)(__rdtsc() - start) / elapsed / 1000000.0; 54 | 55 | /* Round to the nearest 100MHz value */ 56 | rounded_rate = (((uint64_t)computed_rate + 50) / 100) * 100; 57 | 58 | printf("Calibrated rdtsc at %lu MHz, rounding to %lu MHz", 59 | (uint64_t)computed_rate, rounded_rate); 60 | 61 | /* Store the rounded rate in rdtsc_inc_freq */ 62 | rdtsc_inc_freq = rounded_rate; 63 | return; 64 | } 65 | 66 | /* rdtsc_freq() 67 | * 68 | * Summary: 69 | * 70 | * This function returns the frequency of rdtsc in MHz. Panics if 71 | * rdtsc_inc_freq is not set, this will happen if rdtsc_calibrate() is not 72 | * used first. 73 | */ 74 | uint64_t 75 | rdtsc_freq(void) 76 | { 77 | if(!rdtsc_inc_freq){ 78 | panic("rdtsc not calibrated, call rdtsc_calibrate() first"); 79 | } 80 | 81 | return rdtsc_inc_freq; 82 | } 83 | 84 | /* rdtsc_future() 85 | * 86 | * Summary: 87 | * 88 | * This function returns the value that rdtsc for the current cpu will be 89 | * microseconds in the future. This is fairly cheap as it only requires an 90 | * imul, versus needing to do a div in rdtsc_uptime(). 91 | * 92 | * Parameters: 93 | * 94 | * _In_ microseconds - Number of microseconds to add to the current rdtsc count 95 | * 96 | * Returns: 97 | * 98 | * Value of rdtsc microseconds in the future. 99 | */ 100 | uint64_t 101 | rdtsc_future(_In_ uint64_t microseconds) 102 | { 103 | return __rdtsc() + (microseconds * rdtsc_freq()); 104 | } 105 | 106 | /* rdtsc_uptime() 107 | * 108 | * Summary: 109 | * 110 | * This returns the current system uptime in microseconds. This function is 111 | * fairly expensive as it does a divide. If you are polling for a timeout 112 | * you should use rdtsc_future() once rather than polling this function. 113 | */ 114 | uint64_t 115 | rdtsc_uptime(void) 116 | { 117 | return __rdtsc() / rdtsc_freq(); 118 | } 119 | 120 | /* rdtsc_sleep() 121 | * 122 | * Summary: 123 | * 124 | * This function sleeps for the specified amount of microseconds. This is a 125 | * busy sleep. 126 | * 127 | * Parameters: 128 | * 129 | * _In_ microseconds - Number of microseconds to sleep for. 130 | */ 131 | void 132 | rdtsc_sleep(_In_ uint64_t microseconds) 133 | { 134 | uint64_t waitval; 135 | 136 | waitval = rdtsc_future(microseconds); 137 | while(__rdtsc() < waitval); 138 | 139 | return; 140 | } 141 | 142 | -------------------------------------------------------------------------------- /srcs/vm/vm_x86.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma pack(push, 1) 4 | struct _x86_regs { 5 | /* Do not move these GPR definitions, as we use hardcoded offsets in 6 | * assembly. 7 | */ 8 | union { 9 | struct { 10 | uint8_t al; 11 | uint8_t ah; 12 | } b; 13 | uint16_t ax; 14 | uint32_t eax; 15 | uint64_t rax; 16 | } rax; 17 | union { 18 | struct { 19 | uint8_t bl; 20 | uint8_t bh; 21 | } b; 22 | uint16_t bx; 23 | uint32_t ebx; 24 | uint64_t rbx; 25 | } rbx; 26 | union { 27 | struct { 28 | uint8_t cl; 29 | uint8_t ch; 30 | } b; 31 | uint16_t cx; 32 | uint32_t ecx; 33 | uint64_t rcx; 34 | } rcx; 35 | union { 36 | struct { 37 | uint8_t dl; 38 | uint8_t dh; 39 | } b; 40 | uint16_t dx; 41 | uint32_t edx; 42 | uint64_t rdx; 43 | } rdx; 44 | union { 45 | uint8_t dil; 46 | uint16_t di; 47 | uint32_t edi; 48 | uint64_t rdi; 49 | } rdi; 50 | union { 51 | uint8_t sil; 52 | uint16_t si; 53 | uint32_t esi; 54 | uint64_t rsi; 55 | } rsi; 56 | union { 57 | uint8_t bpl; 58 | uint16_t bp; 59 | uint32_t ebp; 60 | uint64_t rbp; 61 | } rbp; 62 | union { 63 | uint8_t spl; 64 | uint16_t sp; 65 | uint32_t esp; 66 | uint64_t rsp; 67 | } rsp; 68 | union { 69 | uint8_t r8b; 70 | uint16_t r8w; 71 | uint32_t r8d; 72 | uint64_t r8; 73 | } r8; 74 | union { 75 | uint8_t r9b; 76 | uint16_t r9w; 77 | uint32_t r9d; 78 | uint64_t r9; 79 | } r9; 80 | union { 81 | uint8_t r10b; 82 | uint16_t r10w; 83 | uint32_t r10d; 84 | uint64_t r10; 85 | } r10; 86 | union { 87 | uint8_t r11b; 88 | uint16_t r11w; 89 | uint32_t r11d; 90 | uint64_t r11; 91 | } r11; 92 | union { 93 | uint8_t r12b; 94 | uint16_t r12w; 95 | uint32_t r12d; 96 | uint64_t r12; 97 | } r12; 98 | union { 99 | uint8_t r13b; 100 | uint16_t r13w; 101 | uint32_t r13d; 102 | uint64_t r13; 103 | } r13; 104 | union { 105 | uint8_t r14b; 106 | uint16_t r14w; 107 | uint32_t r14d; 108 | uint64_t r14; 109 | } r14; 110 | union { 111 | uint8_t r15b; 112 | uint16_t r15w; 113 | uint32_t r15d; 114 | uint64_t r15; 115 | } r15; 116 | 117 | union { 118 | uint16_t ip; 119 | uint32_t eip; 120 | uint64_t rip; 121 | } rip; 122 | 123 | union { 124 | struct { 125 | uint64_t cf:1; 126 | uint64_t resvd1:1; 127 | uint64_t pf:1; 128 | uint64_t resvd2:1; 129 | uint64_t af:1; 130 | uint64_t resvd3:1; 131 | uint64_t zf:1; 132 | uint64_t sf:1; 133 | uint64_t tf:1; 134 | uint64_t intf:1; 135 | uint64_t df:1; 136 | uint64_t of:1; 137 | uint64_t iopl:2; 138 | uint64_t nt:1; 139 | uint64_t resvd4:1; 140 | uint64_t rf:1; 141 | uint64_t vm:1; 142 | uint64_t ac:1; 143 | uint64_t vif:1; 144 | uint64_t vip:1; 145 | uint64_t id:1; 146 | } u; 147 | 148 | uint64_t rfl; 149 | } rfl; 150 | 151 | uint16_t es_sel; 152 | uint16_t es_attrib; 153 | uint32_t es_limit; 154 | uint64_t es_base; 155 | 156 | uint16_t cs_sel; 157 | uint16_t cs_attrib; 158 | uint32_t cs_limit; 159 | uint64_t cs_base; 160 | 161 | uint16_t ss_sel; 162 | uint16_t ss_attrib; 163 | uint32_t ss_limit; 164 | uint64_t ss_base; 165 | 166 | uint16_t ds_sel; 167 | uint16_t ds_attrib; 168 | uint32_t ds_limit; 169 | uint64_t ds_base; 170 | 171 | uint16_t fs_sel; 172 | uint16_t fs_attrib; 173 | uint32_t fs_limit; 174 | uint64_t fs_base; 175 | 176 | uint16_t gs_sel; 177 | uint16_t gs_attrib; 178 | uint32_t gs_limit; 179 | uint64_t gs_base; 180 | 181 | uint16_t gdtr_sel; 182 | uint16_t gdtr_attrib; 183 | uint32_t gdtr_limit; 184 | uint64_t gdtr_base; 185 | 186 | uint16_t ldtr_sel; 187 | uint16_t ldtr_attrib; 188 | uint32_t ldtr_limit; 189 | uint64_t ldtr_base; 190 | 191 | uint16_t idtr_sel; 192 | uint16_t idtr_attrib; 193 | uint32_t idtr_limit; 194 | uint64_t idtr_base; 195 | 196 | uint16_t tr_sel; 197 | uint16_t tr_attrib; 198 | uint32_t tr_limit; 199 | uint64_t tr_base; 200 | }; 201 | #pragma pack(pop) 202 | 203 | rstate_t 204 | vm_x86_create(_Outptr_ struct _vm **out_vm, _In_ enum _vm_subtype type); 205 | 206 | void 207 | vm_x86_dump_state(struct _vm *vm); 208 | 209 | -------------------------------------------------------------------------------- /srcs/boot/boot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include