├── util.h ├── utsversion.h ├── .gitignore ├── loop.h ├── dump.h ├── panic.h ├── sys_exit.c ├── Mm.cpp ├── sys_readlink.c ├── Mm.hpp ├── sys_unimplemented.c ├── panic.c ├── syscall.h ├── README.md ├── load.h ├── Process.cpp ├── panicw.hpp ├── Process.hpp ├── Flag.hpp ├── Debug.hpp ├── sys_brk.c ├── sys_getuid.c ├── thread.h ├── Common.hpp ├── process.h ├── sys_write.c ├── panicw.cpp ├── Kernel.hpp ├── dump.c ├── main.c ├── sys_arch_prctl.c ├── sys_uname.c ├── range.h ├── Range.hpp ├── syscall.c ├── Vm.hpp ├── thread.c ├── LICENSE ├── process.c ├── Makefile ├── Kernel.cpp ├── Vm.cpp ├── Range.cpp ├── Vcpu.hpp ├── range.c ├── mm.h ├── vm.h ├── Vcpu.cpp ├── loop.c ├── load.c ├── mm.c ├── vm.c └── linux.h /util.h: -------------------------------------------------------------------------------- 1 | #define countof(a) (sizeof(a)/sizeof(a[0])) 2 | -------------------------------------------------------------------------------- /utsversion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern const char utsversion[]; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | *.exe 4 | *.stackdump 5 | *.out 6 | utsversion.c 7 | .vscode/ 8 | -------------------------------------------------------------------------------- /loop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "thread.h" 4 | 5 | void 6 | handle_vmexit(thread_t *thread); 7 | -------------------------------------------------------------------------------- /dump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mm.h" 4 | 5 | void 6 | dump_guest_stack(mm_t *mm, mm_gvirt_t rsp); 7 | -------------------------------------------------------------------------------- /panic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define OR ?(void)0: 4 | 5 | void 6 | _panic(const char *msg); 7 | 8 | #define panic(msg) _panic(__FILE__ ": " msg) 9 | -------------------------------------------------------------------------------- /sys_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | 4 | long 5 | sys_exit_group(thread_t *thread, uint64_t *args) 6 | { 7 | _exit(args[0]); 8 | } -------------------------------------------------------------------------------- /Mm.cpp: -------------------------------------------------------------------------------- 1 | #include "Mm.hpp" 2 | #include "Debug.hpp" 3 | 4 | Mm::Mm(Vm& vm) : m_vm(vm) 5 | { 6 | LOG("create\n"); 7 | } 8 | 9 | Mm::~Mm() 10 | { 11 | LOG("delete\n"); 12 | } -------------------------------------------------------------------------------- /sys_readlink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | #include "linux.h" 4 | 5 | long 6 | sys_readlink(thread_t *thread, uint64_t *args) 7 | { 8 | return -LINUX_EACCES; 9 | } -------------------------------------------------------------------------------- /Mm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Vm.hpp" 4 | 5 | class Mm 6 | { 7 | private: 8 | Vm& m_vm; 9 | 10 | public: 11 | // CREATORS 12 | Mm(Vm& vm); 13 | ~Mm(); 14 | }; -------------------------------------------------------------------------------- /sys_unimplemented.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "panic.h" 3 | 4 | long 5 | sys_unimplemented(thread_t *thread, uint64_t *args) 6 | { 7 | panic("unimplemented syscall"); 8 | } 9 | -------------------------------------------------------------------------------- /panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "panic.h" 4 | 5 | void 6 | _panic(const char *msg) 7 | { 8 | fprintf(stderr, "%s\n", msg); 9 | exit(EXIT_FAILURE); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /syscall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "process.h" 4 | #include "linux.h" 5 | 6 | long 7 | handle_syscall(thread_t *thread, uint64_t number, uint64_t *args); 8 | 9 | typedef long (*syscall_t)(thread_t *thread, uint64_t *args); 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Noahx: Noah for Windows 2 | (in the very early stage of development) 3 | 4 | It will run a Linux ELF binary on Windows by exploiting Cygwin and Windows Hypervisor Platform API without the support of the Windows kernel code like in WSL. 5 | -------------------------------------------------------------------------------- /load.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mm.h" 4 | 5 | typedef struct { 6 | mm_gvirt_t entry; 7 | mm_gvirt_t stack; 8 | mm_gvirt_t heap; 9 | } load_info_t; 10 | 11 | void 12 | ldr_load(mm_t *mm, int argc, char *argv[], load_info_t *info); 13 | -------------------------------------------------------------------------------- /Process.cpp: -------------------------------------------------------------------------------- 1 | #include "Process.hpp" 2 | #include "Debug.hpp" 3 | 4 | Process::Process() : m_mm(m_vm) 5 | { 6 | // m_mm = std::make_unique(m_vm); 7 | LOG("create\n"); 8 | } 9 | 10 | Process::~Process() 11 | { 12 | LOG("delete\n"); 13 | } -------------------------------------------------------------------------------- /panicw.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "panic.h" 4 | #include 5 | 6 | static const HRESULT SUCCESS = 0x80000000; 7 | #undef OR 8 | #define OR & SUCCESS ^ SUCCESS ?(void)0: 9 | 10 | void 11 | panicw(HRESULT result, const char *msg); 12 | -------------------------------------------------------------------------------- /Process.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Mm.hpp" 4 | #include "Vm.hpp" 5 | #include 6 | 7 | class Process 8 | { 9 | public: 10 | 11 | private: 12 | Vm m_vm; 13 | Mm m_mm; 14 | 15 | public: 16 | // CREATORS 17 | Process(); 18 | ~Process(); 19 | }; -------------------------------------------------------------------------------- /Flag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define ENUM_FLAG(T) \ 6 | constexpr T operator|(T l, T r) \ 7 | { \ 8 | using U = typename std::underlying_type::type; \ 9 | return static_cast(static_cast(l) | static_cast(r)); \ 10 | } 11 | -------------------------------------------------------------------------------- /Debug.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static const bool DEBUG = true; 6 | 7 | template 8 | void log(Args && ...args) 9 | { 10 | if (DEBUG) 11 | (std::cerr << ... << args); 12 | } 13 | 14 | #define LOG(...) log(__func__, ": ", __VA_ARGS__) 15 | -------------------------------------------------------------------------------- /sys_brk.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | 3 | int 4 | sys_brk(thread_t *thread, uint64_t *args) 5 | { 6 | mm_gvirt_t newbrk = args[0]; 7 | mm_t *mm = &thread->process->mm; 8 | if (newbrk < mm->heap_start) 9 | return mm->heap_end; 10 | newbrk = mm_expand_heap(mm, newbrk); 11 | return newbrk; 12 | } 13 | -------------------------------------------------------------------------------- /sys_getuid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | 4 | long sys_getuid(thread_t *thread, uint64_t *args) { return getuid(); } 5 | long sys_getgid(thread_t *thread, uint64_t *args) { return getgid(); } 6 | long sys_geteuid(thread_t *thread, uint64_t *args) { return geteuid(); } 7 | long sys_getegid(thread_t *thread, uint64_t *args) { return getegid(); } 8 | -------------------------------------------------------------------------------- /thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "vm.h" 4 | 5 | typedef struct process process_t; 6 | typedef struct { 7 | vcpu_t vcpu; 8 | process_t *process; 9 | } thread_t; 10 | 11 | void 12 | thread_create(thread_t *thread, process_t *process); 13 | 14 | void 15 | thread_init(thread_t *thread, vcpu_sysregs_t *sysregs, uint64_t rip, uint64_t rsp); 16 | 17 | void 18 | thread_run(thread_t *thread); 19 | -------------------------------------------------------------------------------- /Common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | constexpr uint64_t GiB = 1024*1024*1024; 4 | constexpr int PAGE_SIZE_4K = 1024*1024; 5 | 6 | constexpr uint64_t 7 | rounddown(uint64_t value, size_t size) 8 | { 9 | return (value & (~(size - 1))); 10 | } 11 | 12 | constexpr inline uint64_t 13 | roundup(uint64_t value, size_t size) 14 | { 15 | return rounddown(value + size - 1, size); 16 | } 17 | -------------------------------------------------------------------------------- /process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "thread.h" 4 | #include "mm.h" 5 | #include "vm.h" 6 | 7 | typedef struct process { 8 | int thread_count, thread_count_max; 9 | thread_t *thread; 10 | mm_t mm; 11 | vm_t vm; 12 | } process_t; 13 | 14 | void 15 | process_create(process_t *process); 16 | 17 | void 18 | process_load(process_t *process, int argc, char *argv[]); 19 | 20 | void 21 | process_run(process_t *process); 22 | -------------------------------------------------------------------------------- /sys_write.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | #include "panic.h" 4 | 5 | long 6 | sys_write(thread_t *thread, uint64_t *args) 7 | { 8 | int fd = args[0]; 9 | mm_gvirt_t gbuf = args[1]; 10 | size_t count = args[2]; 11 | 12 | void *buf = malloc(count); 13 | if (buf == NULL) 14 | panic("out of memory"); 15 | 16 | mm_t *mm = &thread->process->mm; 17 | mm_copy_from_user(mm, buf, gbuf, count) 18 | OR panic("copy error"); 19 | 20 | return write(fd, buf, count); 21 | } -------------------------------------------------------------------------------- /panicw.cpp: -------------------------------------------------------------------------------- 1 | #include "panicw.hpp" 2 | #include 3 | 4 | void 5 | panicw(HRESULT result, const char *msg) 6 | { 7 | std::cerr << "Vm: " << msg; 8 | LPVOID lpMsgBuf; 9 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 10 | FORMAT_MESSAGE_FROM_SYSTEM | 11 | FORMAT_MESSAGE_IGNORE_INSERTS, 12 | NULL, result, 13 | MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 14 | (LPTSTR) &lpMsgBuf, 0, NULL); 15 | std::cerr << lpMsgBuf; 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Kernel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Vm.hpp" 4 | #include "Common.hpp" 5 | 6 | class Kernel 7 | { 8 | private: 9 | Vm& m_vm; 10 | Vm::gpa_t m_start; 11 | size_t m_size; 12 | static const int PAGE_ENTRY_COUNT = 512; 13 | struct kernel { 14 | uint64_t pml4[PAGE_ENTRY_COUNT]; 15 | uint64_t pdpt[PAGE_ENTRY_COUNT]; 16 | char tss[PAGE_SIZE_4K]; 17 | uint64_t gdt[3]; 18 | } *m_data; 19 | 20 | public: 21 | Kernel(Vm& vm) : m_vm(vm) {}; 22 | ~Kernel(); 23 | 24 | void 25 | setup(); 26 | 27 | Vm::gpa_t 28 | hva_to_gpa(void *hva); 29 | }; 30 | -------------------------------------------------------------------------------- /dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dump.h" 3 | 4 | void 5 | dump_guest_stack(mm_t *mm, mm_gvirt_t rsp) 6 | { 7 | int skip = rsp % 16; 8 | rsp = rounddown(rsp, 16); 9 | int used_stack_size = mm->stack_top - rsp; 10 | char *p = (char *)mm_stack_gvirt_to_hvirt(mm, rsp); 11 | for (int i = 0; i < used_stack_size; i++) { 12 | if ((uint64_t)&p[i] % 16 == 0) 13 | fprintf(stderr, "\n%lx: ", rsp + i); 14 | if (skip == 0) 15 | fprintf(stderr, "%02x ", p[i] & 0xff); 16 | else { 17 | fprintf(stderr, " "); 18 | skip--; 19 | } 20 | 21 | } 22 | fprintf(stderr, "\n"); 23 | } 24 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "Vm.hpp" 2 | #include "Vcpu.hpp" 3 | #include "Process.hpp" 4 | #include 5 | #include 6 | #include 7 | #include "process.h" 8 | #include "load.h" 9 | #include "loop.h" 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | process_t process; 15 | 16 | { 17 | Process process; 18 | } 19 | 20 | if (argc < 2) { 21 | printf("Usage: %s [ELF file]\n", argv[0]); 22 | exit(1); 23 | } 24 | printf("Starting Noahx ...\n"); 25 | 26 | process_create(&process); 27 | process_load(&process, argc - 1, &argv[1]); 28 | process_run(&process); 29 | } 30 | -------------------------------------------------------------------------------- /sys_arch_prctl.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "panic.h" 3 | 4 | int 5 | sys_arch_prctl(thread_t *thread, uint64_t *args) 6 | { 7 | int code = args[0]; 8 | uint64_t arg2 = args[1]; 9 | 10 | enum 11 | { 12 | ARCH_SET_GS = 0x1001, 13 | ARCH_SET_FS = 0x1002, 14 | ARCH_GET_FS = 0x1003, 15 | ARCH_GET_GS = 0x1004, 16 | 17 | ARCH_GET_CPUID = 0x1011, 18 | ARCH_SET_CPUID = 0x1012, 19 | 20 | ARCH_MAP_VDSO_X32 = 0x2001, 21 | ARCH_MAP_VDSO_32 = 0x2002, 22 | ARCH_MAP_VDSO_64 = 0x2003 23 | }; 24 | 25 | switch (code) 26 | { 27 | case ARCH_SET_FS: 28 | vcpu_set_segbase(&thread->vcpu, VCPU_SEG_FS, arg2); 29 | return 0; 30 | 31 | default: 32 | panic("unimplemented arch_prctl\n"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sys_uname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | #include "utsversion.h" 4 | 5 | #define LEN 65 6 | 7 | static struct { 8 | char sysname[LEN]; 9 | char nodename[LEN]; 10 | char release[LEN]; 11 | char version[LEN]; 12 | char machine[LEN]; 13 | char domainname[LEN]; 14 | } utsname = { 15 | "Linux", 16 | "", 17 | "4.19.noahx.x86_64", 18 | "", 19 | "x86_64", 20 | "", 21 | }; 22 | 23 | int 24 | sys_uname(thread_t *thread, uint64_t *args) 25 | { 26 | mm_gvirt_t buf = args[0]; 27 | mm_t *mm = &thread->process->mm; 28 | gethostname(utsname.nodename, sizeof(utsname.nodename)); 29 | strcpy(utsname.version, utsversion); 30 | mm_copy_to_user(mm, buf, &utsname, sizeof(utsname)); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct range { 6 | struct range *left, *right; 7 | uint64_t start, end; 8 | } range_t; 9 | 10 | typedef range_t **range_root_t; 11 | 12 | #if 0 13 | static inline void 14 | range_init(range_t *range, uint64_t start, uint64_t end) 15 | { 16 | range->left = NULL; 17 | range->right = NULL; 18 | range->start = start; 19 | range->end = end; 20 | } 21 | #endif 22 | 23 | range_t * 24 | range_search(range_root_t root, uint64_t start, uint64_t end); 25 | 26 | static inline range_t * 27 | range_search_one(range_root_t root, uint64_t value) 28 | { 29 | return range_search(root, value, value); 30 | } 31 | 32 | range_t * 33 | range_insert(range_root_t root, range_t *range); 34 | 35 | void 36 | range_print(range_root_t root); 37 | -------------------------------------------------------------------------------- /Range.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class RangeTree; 6 | 7 | class RangeNode 8 | { 9 | RangeNode *left = nullptr, *right = nullptr; 10 | uint64_t start, end; 11 | public: 12 | friend RangeTree; 13 | RangeNode(uint64_t const start, uint64_t const end) : start(start), end(end) {}; 14 | }; 15 | 16 | class RangeTree 17 | { 18 | private: 19 | RangeNode *root = nullptr; 20 | 21 | int 22 | search_internal(uint64_t start, uint64_t end, RangeNode **result); 23 | 24 | void 25 | do_print(RangeNode *node, int depth); 26 | 27 | public: 28 | // CREATORS 29 | RangeTree() {} 30 | ~RangeTree() {} 31 | 32 | // ACCESSORS 33 | RangeNode* 34 | search(uint64_t const start, uint64_t const end); 35 | 36 | void 37 | print(); 38 | 39 | // MANIPULATORS 40 | RangeNode& 41 | insert(uint64_t start, uint64_t end); 42 | }; 43 | -------------------------------------------------------------------------------- /syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "syscall.h" 3 | #include "linux.h" 4 | #include "panic.h" 5 | 6 | #define SYSCALL(number, name) #name, 7 | static const char *syscall_name[] = { 8 | SYSCALLS 9 | }; 10 | #undef SYSCALL 11 | 12 | #define SYSCALL(number, name) extern long sys_##name(thread_t *thread, uint64_t *args); 13 | SYSCALLS 14 | #undef SYSCALL 15 | 16 | #define SYSCALL(number, name) (syscall_t) sys_##name, 17 | syscall_t syscalls[] = { 18 | SYSCALLS 19 | }; 20 | #undef SYSCALL 21 | 22 | long 23 | handle_syscall(thread_t *thread, uint64_t number, uint64_t *args) 24 | { 25 | printf("%s[%ld](%lx,%lx,%lx,%lx,%lx,%lx)\n", syscall_name[number], number, args[0], args[1], args[2], args[3], args[4], args[5]); 26 | 27 | if (number >= countof(syscalls)) 28 | sys_unimplemented(thread, args); 29 | syscall_t syscall = syscalls[number]; 30 | return syscall(thread, args); 31 | } 32 | -------------------------------------------------------------------------------- /Vm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Flag.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Vcpu; 10 | 11 | class Vm 12 | { 13 | public: 14 | typedef uint64_t gpa_t; 15 | enum prot_t : uint64_t { 16 | PROT_NONE = 0, 17 | PROT_READ = WHvMapGpaRangeFlagRead, 18 | PROT_WRITE = WHvMapGpaRangeFlagWrite, 19 | PROT_EXEC = WHvMapGpaRangeFlagExecute, 20 | }; 21 | 22 | private: 23 | static const int MAX_VCPU = 8; 24 | 25 | WHV_PARTITION_HANDLE m_handle; 26 | std::array, MAX_VCPU> m_vcpu; 27 | 28 | public: 29 | // CREATORS 30 | Vm(); 31 | ~Vm(); 32 | 33 | // MANIPULATORS 34 | void 35 | map(gpa_t gpa, void *hva, size_t size, prot_t prot); 36 | 37 | Vcpu& 38 | createVcpu(); 39 | 40 | void 41 | deleteVcpu(UINT32 id); 42 | 43 | // ACCESSORS 44 | const WHV_PARTITION_HANDLE 45 | getHandle() { return m_handle; } 46 | }; 47 | 48 | ENUM_FLAG(Vm::prot_t); 49 | -------------------------------------------------------------------------------- /thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "thread.h" 4 | #include "process.h" 5 | #include "vm.h" 6 | #include "mm.h" 7 | #include "loop.h" 8 | 9 | void 10 | thread_create(thread_t *thread, process_t *process) 11 | { 12 | thread->process = process; 13 | vm_create_vcpu(&process->vm, &thread->vcpu); 14 | } 15 | 16 | void 17 | thread_init(thread_t *thread, vcpu_sysregs_t *sysregs, mm_gvirt_t rip, mm_gvirt_t rsp) 18 | { 19 | vcpu_init_sysregs(&thread->vcpu, sysregs); 20 | 21 | vcpu_regs_t regs[] = { 22 | VCPU_REGS_ENTRY_SET(RIP, rip), 23 | VCPU_REGS_ENTRY_SET(RSP, rsp), 24 | VCPU_REGS_ENTRY_SET(RDX, 0), 25 | }; 26 | vcpu_set_regs(&thread->vcpu, regs, countof(regs)); 27 | } 28 | 29 | static void 30 | start_thread(thread_t *thread) 31 | { 32 | do { 33 | vcpu_run(&thread->vcpu); 34 | handle_vmexit(thread); 35 | } while (thread->vcpu.in_operation); 36 | } 37 | 38 | void 39 | thread_run(thread_t *thread) 40 | { 41 | std::thread t(start_thread, thread); 42 | 43 | for (int i = 0; i < 1000000000; i++) 44 | (void)0; 45 | vcpu_stop(&thread->vcpu); 46 | t.join(); 47 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Takahiro Shinagawa 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 | -------------------------------------------------------------------------------- /process.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "load.h" 3 | #include "thread.h" 4 | #include "loop.h" 5 | #include "dump.h" 6 | #include "panic.h" 7 | 8 | void 9 | process_create(process_t *process) 10 | { 11 | vm_create(&process->vm); 12 | mm_init(&process->mm, &process->vm); 13 | mm_setup_kernel(&process->mm); 14 | mm_setup_stack(&process->mm); 15 | 16 | process->thread_count = 1; 17 | process->thread_count_max = 2; 18 | process->thread = (thread_t *)calloc(process->thread_count_max, sizeof(thread_t)); 19 | if (process->thread == NULL) 20 | panic("out of memory"); 21 | thread_create(&process->thread[0], process); 22 | } 23 | 24 | void 25 | process_load(process_t *process, int argc, char *argv[]) 26 | { 27 | load_info_t info; 28 | ldr_load(&process->mm, argc, argv, &info); 29 | mm_setup_heap(&process->mm, info.heap); 30 | 31 | vcpu_sysregs_t sysregs; 32 | mm_get_sysregs(&process->mm, &sysregs); 33 | thread_init(process->thread, &sysregs, info.entry, info.stack); 34 | dump_guest_stack(&process->mm, info.stack); 35 | } 36 | 37 | void 38 | process_run(process_t *process) 39 | { 40 | // mm_dump_range_tree(&process->mm); 41 | thread_run(&process->thread[0]); 42 | } 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = noahx.exe 2 | CC = clang++ 3 | CFLAGS = -std=c++17 -I. -idirafter$(WINSDKINC) -Wno-parentheses -Wno-unknown-pragmas -D_POSIX_C_SOURCE=200809L -MMD -MP 4 | LDFLAGS = -L/cygdrive/c/Windows/System32 -lWinHvPlatform 5 | WINSDKDIR = /cygdrive/c/Program Files (x86)/Windows Kits/10/Include 6 | WINSDKINC = "$(shell find "$(WINSDKDIR)" -name WinHvPlatform.h -printf "%h\n" | tail -n 1)" 7 | SRCS = $(shell ls *.c) 8 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 9 | CPPSRCS = $(shell ls *.cpp) 10 | CPPOBJS = $(patsubst %.cpp,%.opp,$(CPPSRCS)) 11 | INCS = $(shell ls *.h) 12 | 13 | .SUFFIXES: .opp .exe 14 | 15 | .c.o: 16 | $(CC) $(CFLAGS) -c $< 17 | 18 | .cpp.opp: 19 | $(CC) $(CFLAGS) -c $< -o `basename $< .cpp`.opp 20 | 21 | .cpp.exe: 22 | $(CC) $(CFLAGS) -DTEST $< -o $@ 23 | 24 | .PHONY: all clean 25 | 26 | all: $(TARGET) 27 | 28 | $(TARGET): $(OBJS) $(CPPOBJS) 29 | echo "extern const char utsversion[] = \"#1 SMP `env LANG=en date`\";" > utsversion.c 30 | $(CC) -c utsversion.c -o utsversion.o 31 | $(CC) $(OBJS) $(CPPOBJS) -o $@ $(LDFLAGS) 32 | 33 | -include *.d 34 | 35 | clean: 36 | rm -f $(TARGET) *.o *.d 37 | 38 | Range.exe: Range.cpp 39 | 40 | test: Range.exe 41 | ./$< 42 | -------------------------------------------------------------------------------- /Kernel.cpp: -------------------------------------------------------------------------------- 1 | #include "Kernel.hpp" 2 | #include "Common.hpp" 3 | #include "panic.h" 4 | 5 | inline Vm::gpa_t 6 | Kernel::hva_to_gpa(void *hva) 7 | { 8 | uint64_t offset = reinterpret_cast(hva) - reinterpret_cast(m_data); 9 | return m_start + offset; 10 | } 11 | 12 | void 13 | Kernel::setup() 14 | { 15 | m_start = 255 * GiB; 16 | m_size = roundup(sizeof(*m_data), PAGE_SIZE_4K); 17 | m_data = static_cast(aligned_alloc(PAGE_SIZE_4K, m_size)); 18 | if (m_data) 19 | panic("out of memory"); 20 | memset(m_data, 0, m_size); 21 | m_vm.map(m_start, m_data, m_size, Vm::PROT_READ | Vm::PROT_WRITE); 22 | 23 | constexpr uint64_t PTE_P = 1ULL << 0; 24 | constexpr uint64_t PTE_RW = 1ULL << 1; 25 | constexpr uint64_t PTE_US = 1ULL << 2; 26 | constexpr uint64_t PTE_PS = 1ULL << 7; 27 | constexpr uint64_t PML4E_FLAG = PTE_P | PTE_RW | PTE_US; 28 | constexpr uint64_t PDPTE_FLAG = PTE_P | PTE_RW | PTE_US | PTE_PS; 29 | m_data->pml4[0] = hva_to_gpa(m_data->pdpt) | PML4E_FLAG; 30 | const uint64_t pdpte_count = m_start / (1 * GiB); 31 | for (uint64_t i = 0; i < pdpte_count; i++) 32 | m_data->pdpt[i] = (i * GiB) | PDPTE_FLAG; 33 | 34 | m_data->gdt[0] = 0; 35 | m_data->gdt[1] = 0x00a0fa000000ffff; // user code 36 | m_data->gdt[2] = 0x00c0f2000000ffff; // user data 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Vm.cpp: -------------------------------------------------------------------------------- 1 | #include "Vm.hpp" 2 | #include "Vcpu.hpp" 3 | #include "panicw.hpp" 4 | #include "Debug.hpp" 5 | #include 6 | #include 7 | 8 | static void 9 | init() 10 | { 11 | UINT32 size; 12 | WHV_CAPABILITY capability; 13 | 14 | WHvGetCapability( 15 | WHvCapabilityCodeHypervisorPresent, 16 | &capability, sizeof(capability), &size); 17 | if (!capability.HypervisorPresent) 18 | panic("Windows Hypervisor Platform is not enabled"); 19 | } 20 | 21 | Vm::Vm() 22 | { 23 | [[maybe_unused]] static bool initialized = []() { init(); return true; }(); 24 | 25 | WHvCreatePartition(&m_handle) 26 | OR panic("create partition error"); 27 | 28 | UINT32 cpu_count = MAX_VCPU; 29 | WHvSetPartitionProperty( 30 | m_handle, 31 | WHvPartitionPropertyCodeProcessorCount, 32 | &cpu_count, sizeof(cpu_count)) 33 | OR panic("set partition property error"); 34 | 35 | WHvSetupPartition(m_handle) 36 | OR panic("setup partition error"); 37 | 38 | LOG("create\n"); 39 | } 40 | 41 | Vm::~Vm() 42 | { 43 | for (auto&& e : m_vcpu) 44 | e = nullptr; 45 | WHvDeletePartition(m_handle) 46 | OR panic("delete partition error"); 47 | LOG("delete\n"); 48 | } 49 | 50 | void 51 | Vm::map(gpa_t gpa, void *hva, size_t size, prot_t prot) 52 | { 53 | HRESULT hr; 54 | 55 | WHV_MAP_GPA_RANGE_FLAGS wprot = static_cast(prot); 56 | hr = WHvMapGpaRange(m_handle, hva, gpa, size, wprot); 57 | if (FAILED(hr)) 58 | panicw(hr, "user mmap error"); 59 | LOG(std::hex, "map: gpa=", gpa, " hva", hva, " size=", size, " prot=", prot); 60 | } 61 | 62 | Vcpu& 63 | Vm::createVcpu() 64 | { 65 | for (size_t i = 0; i < m_vcpu.size(); i++) { 66 | if (!m_vcpu[i]) { 67 | m_vcpu[i] = std::make_unique(*this, i); 68 | return *m_vcpu[i]; 69 | } 70 | } 71 | panic("too many VCPU"); 72 | } 73 | 74 | void 75 | Vm::deleteVcpu(UINT32 id) 76 | { 77 | m_vcpu[id] = nullptr; 78 | } -------------------------------------------------------------------------------- /Range.cpp: -------------------------------------------------------------------------------- 1 | #include "Range.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | RangeTree::search_internal(uint64_t const start, uint64_t const end, RangeNode **result) 8 | { 9 | int n = 0; 10 | RangeNode *node = root; 11 | 12 | while (node) { 13 | *result = node; 14 | if (node->end <= start) 15 | n = 1, node = node->right; 16 | else if (end < node->start) 17 | n = -1, node = node->left; 18 | else 19 | return 0; 20 | } 21 | return n; 22 | } 23 | 24 | RangeNode& 25 | RangeTree::insert(uint64_t const start, uint64_t const end) 26 | { 27 | RangeNode *result = nullptr; 28 | RangeNode *node = new RangeNode(start, end); 29 | 30 | int n = search_internal(start, end, &result); 31 | if (result != nullptr) { 32 | if (n < 0) 33 | result->left = node; 34 | else if (n > 0) 35 | result->right = node; 36 | else 37 | { delete node; node = result; } 38 | } else 39 | root = node; 40 | return *node; 41 | } 42 | 43 | RangeNode* 44 | RangeTree::search(uint64_t const start, uint64_t const end) 45 | { 46 | RangeNode *result = nullptr; 47 | int n = search_internal(start, end, &result); 48 | return (n == 0 ? result : nullptr); 49 | } 50 | 51 | void 52 | RangeTree::do_print(RangeNode *node, int depth = 0) 53 | { 54 | assert(node != nullptr); 55 | if (node->left) { 56 | depth++; do_print(node->left, depth); depth--; 57 | } 58 | std::cout << std::setw(4*depth) << ' ' << std::setw(8); 59 | std::cout << std::hex << node->start << '-' << node->end << std::endl; 60 | if (node->right) { 61 | depth++; do_print(node->right, depth); depth--; 62 | } 63 | } 64 | 65 | void 66 | RangeTree::print() 67 | { 68 | do_print(root); 69 | } 70 | 71 | 72 | #ifdef TEST 73 | 74 | int main() 75 | { 76 | RangeTree tree; 77 | tree.insert(0xb000, 0xc000); 78 | tree.insert(0x4000, 0x4100); 79 | tree.insert(0x4100, 0x4400); 80 | tree.print(); 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /Vcpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Vm; 8 | 9 | class Vcpu 10 | { 11 | public: 12 | enum RegName { 13 | VCPU_REG_RAX = WHvX64RegisterRax, 14 | VCPU_REG_RCX = WHvX64RegisterRcx, 15 | VCPU_REG_RDX = WHvX64RegisterRdx, 16 | VCPU_REG_RBX = WHvX64RegisterRbx, 17 | VCPU_REG_RSP = WHvX64RegisterRsp, 18 | VCPU_REG_RBP = WHvX64RegisterRbp, 19 | VCPU_REG_RSI = WHvX64RegisterRsi, 20 | VCPU_REG_RDI = WHvX64RegisterRdi, 21 | VCPU_REG_R8 = WHvX64RegisterR8, 22 | VCPU_REG_R9 = WHvX64RegisterR9, 23 | VCPU_REG_R10 = WHvX64RegisterR10, 24 | VCPU_REG_R11 = WHvX64RegisterR11, 25 | VCPU_REG_R12 = WHvX64RegisterR12, 26 | VCPU_REG_R13 = WHvX64RegisterR13, 27 | VCPU_REG_R14 = WHvX64RegisterR14, 28 | VCPU_REG_R15 = WHvX64RegisterR15, 29 | VCPU_REG_RIP = WHvX64RegisterRip, 30 | VCPU_REG_RFLAGS = WHvX64RegisterRflags, 31 | 32 | VCPU_SEG_FS = WHvX64RegisterFs, 33 | VCPU_SEG_GS = WHvX64RegisterGs, 34 | }; 35 | 36 | struct Reg { 37 | RegName name; 38 | union { 39 | uint64_t value; 40 | uint64_t *ptr; 41 | }; 42 | }; 43 | 44 | #define VCPU_REGS_ENTRY_GET(reg, val) { VCPU_REG_##reg, { (vcpu_regvalue_t)val } } 45 | #define VCPU_REGS_ENTRY_SET(reg, val) { VCPU_REG_##reg, { val } } 46 | 47 | struct SysRegs { 48 | uint64_t cr3; 49 | uint64_t gdt_base; 50 | uint16_t gdt_limit; 51 | uint64_t idt_base; 52 | uint16_t idt_limit; 53 | uint64_t tss_base; 54 | uint16_t tss_limit; 55 | }; 56 | 57 | private: 58 | WHV_RUN_VP_EXIT_CONTEXT exit_context; 59 | Vm& m_vm; 60 | UINT32 m_id; 61 | bool m_running; 62 | 63 | public: 64 | Vcpu(Vm& vm, UINT32 id); 65 | ~Vcpu(); 66 | 67 | void 68 | get_regs(Reg *regs, int count); 69 | 70 | void 71 | set_regs(Reg *regs, int count); 72 | 73 | void 74 | init_sysregs(SysRegs *sysregs); 75 | 76 | void 77 | set_segbase(RegName seg, uint64_t base); 78 | 79 | void 80 | run(); 81 | 82 | void 83 | stop(); 84 | }; 85 | -------------------------------------------------------------------------------- /range.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "range.h" 4 | 5 | static inline int 6 | range_search_internal(range_root_t root, uint64_t start, uint64_t end, range_t **parent) 7 | { 8 | int n = 0; 9 | range_t *r = *root; 10 | 11 | while (r) { 12 | *parent = r; 13 | if (r->end <= start) 14 | n = 1, r = r->right; 15 | else if (end <= r->start) 16 | n = -1, r = r->left; 17 | else 18 | return 0; 19 | } 20 | return n; 21 | } 22 | 23 | range_t * 24 | range_search(range_root_t root, uint64_t start, uint64_t end) 25 | { 26 | range_t *parent = NULL; 27 | int n = range_search_internal(root, start, end, &parent); 28 | return (n == 0 ? parent : NULL); 29 | } 30 | 31 | range_t * 32 | range_insert(range_root_t root, range_t *range) 33 | { 34 | range_t *parent = NULL; 35 | int n = range_search_internal(root, range->start, range->end, &parent); 36 | if (parent != NULL) { 37 | if (n < 0) 38 | parent->left = range; 39 | else if (n > 0) 40 | parent->right = range; 41 | else 42 | return parent; 43 | } else 44 | *root = range; 45 | return NULL; 46 | } 47 | 48 | static int depth = 0; 49 | void 50 | do_range_print(range_t *range) 51 | { 52 | if (range->left) { 53 | depth++; do_range_print(range->left); depth--; 54 | } 55 | printf("%*c%08lx-%08lx\n", 4 * depth, ' ', range->start, range->end); 56 | if (range->right) { 57 | depth++; do_range_print(range->right); depth--; 58 | } 59 | } 60 | 61 | void 62 | range_print(range_root_t root) 63 | { 64 | depth = 0; 65 | do_range_print(*root); 66 | } 67 | 68 | 69 | #ifdef TEST 70 | 71 | #include 72 | #include "range.h" 73 | 74 | range_t *root = NULL; 75 | 76 | int main() 77 | { 78 | range_t stack = { .left = NULL, .right = NULL, .start = 0xb000, .end = 0xc000 }; 79 | range_t code = { .left = NULL, .right = NULL, .start = 0x4000, .end = 0x4100 }; 80 | range_t data = { .left = NULL, .right = NULL, .start = 0x4100, .end = 0x4400 }; 81 | 82 | range_insert(&root, &stack); 83 | range_insert(&root, &code); 84 | range_insert(&root, &data); 85 | range_print(root); 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /mm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "vm.h" 6 | #include "range.h" 7 | 8 | #define KiB *1L*1024 9 | #define MiB *1L*1024*1024 10 | #define GiB *1L*1024*1024*1024 11 | #define PAGE_SIZE_4K 4096 12 | 13 | typedef uint64_t mm_gvirt_t; 14 | 15 | typedef enum { 16 | MM_MMAP_TYPE_ALLOC, 17 | MM_MMAP_TYPE_MMAP, 18 | } mm_mmap_type_t; 19 | 20 | typedef int mm_mmap_prot_t; 21 | static const mm_mmap_prot_t MM_MMAP_PROT_NONE = 0; 22 | static const mm_mmap_prot_t MM_MMAP_PROT_READ = VM_MMAP_PROT_READ; 23 | static const mm_mmap_prot_t MM_MMAP_PROT_WRITE = VM_MMAP_PROT_WRITE; 24 | static const mm_mmap_prot_t MM_MMAP_PROT_EXEC = VM_MMAP_PROT_EXEC; 25 | 26 | static const mm_mmap_prot_t MM_MMAP_PROT_RE = MM_MMAP_PROT_READ | MM_MMAP_PROT_EXEC; 27 | static const mm_mmap_prot_t MM_MMAP_PROT_RW = MM_MMAP_PROT_READ | MM_MMAP_PROT_WRITE; 28 | static const mm_mmap_prot_t MM_MMAP_PROT_RWE = MM_MMAP_PROT_READ | MM_MMAP_PROT_WRITE | MM_MMAP_PROT_EXEC; 29 | 30 | 31 | typedef struct { 32 | range_t range; 33 | void *hvirt; 34 | uint64_t size; 35 | mm_mmap_type_t type; 36 | } mm_mmap_range_t; 37 | 38 | typedef struct { 39 | vm_t *vm; 40 | 41 | mm_mmap_range_t *mmap_range_root; 42 | 43 | mm_gvirt_t stack_top, stack_bottom; 44 | size_t stack_size; 45 | void *stack; 46 | 47 | mm_gvirt_t heap_start, heap_end; 48 | size_t heap_size; 49 | void *heap; 50 | 51 | mm_gvirt_t kernel_start; 52 | uint64_t kernel_size; 53 | #define PAGE_ENTRY_COUNT 512 54 | struct kernel { 55 | uint64_t pml4[PAGE_ENTRY_COUNT]; 56 | uint64_t pdpt[PAGE_ENTRY_COUNT]; 57 | char tss[PAGE_SIZE_4K]; 58 | char idt[PAGE_SIZE_4K]; 59 | uint64_t gdt[3]; 60 | } *kernel; 61 | } mm_t; 62 | 63 | 64 | void 65 | mm_init(mm_t *mm, vm_t *vm); 66 | 67 | void 68 | mm_setup_kernel(mm_t *mm); 69 | 70 | void 71 | mm_setup_stack(mm_t *mm); 72 | 73 | mm_gvirt_t 74 | mm_get_stack_top(mm_t *mm); 75 | 76 | void 77 | mm_setup_heap(mm_t *mm, mm_gvirt_t heap_start); 78 | 79 | int 80 | mm_expand_heap(mm_t *mm, mm_gvirt_t new_heap_end); 81 | 82 | void 83 | mm_get_sysregs(mm_t *mm, vcpu_sysregs_t *sysregs); 84 | 85 | void 86 | mm_push(mm_t *mm, const void *data, size_t n); 87 | 88 | void 89 | mm_mmap(mm_t *mm, mm_gvirt_t gvirt, void *hvirt, size_t size, mm_mmap_prot_t prot, mm_mmap_type_t type); 90 | 91 | void * 92 | mm_gvirt_to_hvirt(mm_t *mm, mm_gvirt_t gvirt); 93 | 94 | bool 95 | mm_copy_from_user(mm_t *mm, void *dst, mm_gvirt_t src, size_t size); 96 | 97 | bool 98 | mm_copy_to_user(mm_t *mm, mm_gvirt_t dst, void *src, size_t size); 99 | 100 | void 101 | mm_dump_range_tree(mm_t *mm); 102 | 103 | static inline void * 104 | mm_stack_gvirt_to_hvirt(mm_t *mm, mm_gvirt_t gvirt) 105 | { 106 | return (char *)mm->stack + (gvirt - mm->stack_bottom); 107 | } 108 | 109 | #if 0 110 | static inline mm_gphys_t 111 | mm_stack_hvirt_to_gphys(vm_t *vm, void *hvirt) 112 | { 113 | return (uint64_t)hvirt - (uint64_t)vm->stack + vm->stack_top_gphys - vm->stack_size; 114 | } 115 | #endif 116 | -------------------------------------------------------------------------------- /vm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "range.h" 6 | #include "util.h" 7 | 8 | typedef uint64_t vm_gphys_t; 9 | 10 | typedef struct { 11 | WHV_PARTITION_HANDLE handle; 12 | WHV_RUN_VP_EXIT_CONTEXT exit_context; 13 | } vm_t; 14 | void 15 | vm_create(vm_t *vm); 16 | 17 | typedef int vm_mmap_prot_t; 18 | static const vm_mmap_prot_t VM_MMAP_PROT_READ = WHvMapGpaRangeFlagRead; 19 | static const vm_mmap_prot_t VM_MMAP_PROT_WRITE = WHvMapGpaRangeFlagWrite; 20 | static const vm_mmap_prot_t VM_MMAP_PROT_EXEC = WHvMapGpaRangeFlagExecute; 21 | 22 | void 23 | vm_mmap(vm_t *vm, vm_gphys_t gphys, void *hvirt, size_t size, vm_mmap_prot_t prot); 24 | 25 | typedef struct { 26 | bool in_operation; 27 | vm_t *vm; 28 | UINT32 id; 29 | } vcpu_t; 30 | void 31 | vm_create_vcpu(vm_t *vm, vcpu_t *vcpu); 32 | 33 | typedef struct { 34 | uint64_t cr3; 35 | uint64_t gdt_base; 36 | uint16_t gdt_limit; 37 | uint64_t idt_base; 38 | uint16_t idt_limit; 39 | uint64_t tss_base; 40 | uint16_t tss_limit; 41 | 42 | } vcpu_sysregs_t; 43 | void 44 | vcpu_init_sysregs(vcpu_t *vcpu, vcpu_sysregs_t *sysregs); 45 | 46 | void 47 | vcpu_run(vcpu_t *vcpu); 48 | 49 | void 50 | vcpu_stop(vcpu_t *vcpu); 51 | 52 | typedef enum { 53 | VCPU_REG_RAX = WHvX64RegisterRax, 54 | VCPU_REG_RCX = WHvX64RegisterRcx, 55 | VCPU_REG_RDX = WHvX64RegisterRdx, 56 | VCPU_REG_RBX = WHvX64RegisterRbx, 57 | VCPU_REG_RSP = WHvX64RegisterRsp, 58 | VCPU_REG_RBP = WHvX64RegisterRbp, 59 | VCPU_REG_RSI = WHvX64RegisterRsi, 60 | VCPU_REG_RDI = WHvX64RegisterRdi, 61 | VCPU_REG_R8 = WHvX64RegisterR8, 62 | VCPU_REG_R9 = WHvX64RegisterR9, 63 | VCPU_REG_R10 = WHvX64RegisterR10, 64 | VCPU_REG_R11 = WHvX64RegisterR11, 65 | VCPU_REG_R12 = WHvX64RegisterR12, 66 | VCPU_REG_R13 = WHvX64RegisterR13, 67 | VCPU_REG_R14 = WHvX64RegisterR14, 68 | VCPU_REG_R15 = WHvX64RegisterR15, 69 | VCPU_REG_RIP = WHvX64RegisterRip, 70 | VCPU_REG_RFLAGS = WHvX64RegisterRflags, 71 | 72 | VCPU_SEG_FS = WHvX64RegisterFs, 73 | VCPU_SEG_GS = WHvX64RegisterGs, 74 | } vcpu_regname_t; 75 | typedef uint64_t vcpu_regvalue_t; 76 | typedef struct { 77 | vcpu_regname_t name; 78 | union { 79 | vcpu_regvalue_t value; 80 | vcpu_regvalue_t *ptr; 81 | }; 82 | } vcpu_regs_t; 83 | #define VCPU_REGS_ENTRY_GET(reg, val) { VCPU_REG_##reg, { (vcpu_regvalue_t)val } } 84 | #define VCPU_REGS_ENTRY_SET(reg, val) { VCPU_REG_##reg, { val } } 85 | 86 | void 87 | vcpu_get_regs(vcpu_t *vcpu, vcpu_regs_t *regs, int count); 88 | void 89 | vcpu_set_regs(vcpu_t *vcpu, vcpu_regs_t *regs, int count); 90 | void 91 | vcpu_set_segbase(vcpu_t *vcpu, vcpu_regname_t seg, uint64_t base); 92 | 93 | #if 0 94 | static inline void * 95 | stack_gphys_to_hvirt(vm_t *vm, vmm_gphys_t gphys) 96 | { 97 | vmm_gphys_t stack_bottom_gphys = vm->stack_top_gphys - vm->stack_size; 98 | return gphys - stack_bottom_gphys + vm->stack; 99 | } 100 | #endif 101 | 102 | static inline uint64_t 103 | rounddown(uint64_t value, size_t size) 104 | { 105 | return (value & (~(size - 1))); 106 | } 107 | 108 | static inline uint64_t 109 | roundup(uint64_t value, size_t size) 110 | { 111 | return rounddown(value + size - 1, size); 112 | } 113 | 114 | -------------------------------------------------------------------------------- /Vcpu.cpp: -------------------------------------------------------------------------------- 1 | #include "Vcpu.hpp" 2 | #include "Vm.hpp" 3 | #include "panicw.hpp" 4 | #include "Debug.hpp" 5 | #include 6 | 7 | Vcpu::Vcpu(Vm &vm, UINT32 id) : m_vm(vm), m_id(id) 8 | { 9 | m_running = false; 10 | 11 | WHvCreateVirtualProcessor(m_vm.getHandle(), m_id, 0) 12 | OR panic("create virtual processor error"); 13 | LOG("VCPU ", m_id, " created\n"); 14 | } 15 | 16 | Vcpu::~Vcpu() 17 | { 18 | WHvDeleteVirtualProcessor(m_vm.getHandle(), m_id) 19 | OR panic("delete virtual processor error"); 20 | LOG("VCPU ", m_id, " deleted\n"); 21 | } 22 | 23 | void 24 | Vcpu::init_sysregs(SysRegs *sysregs) 25 | { 26 | enum { 27 | Cr0, Cr3, Cr4, Efer, Gdtr, Idtr, Tr, 28 | Cs, Ss, Ds, Es, Fs, Gs, N 29 | }; 30 | const WHV_REGISTER_NAME regname[N] = { 31 | #define REGNAME(reg) [reg] = WHvX64Register##reg 32 | REGNAME(Cr0), 33 | REGNAME(Cr3), 34 | REGNAME(Cr4), 35 | REGNAME(Efer), 36 | REGNAME(Idtr), 37 | REGNAME(Gdtr), 38 | REGNAME(Tr), 39 | REGNAME(Cs), 40 | REGNAME(Ss), 41 | REGNAME(Ds), 42 | REGNAME(Es), 43 | REGNAME(Fs), 44 | REGNAME(Gs), 45 | }; 46 | WHV_REGISTER_VALUE regvalue[N]; 47 | WHvGetVirtualProcessorRegisters( 48 | m_vm.getHandle(), m_id, regname, N, regvalue) 49 | OR panic("get virtual processor registers error"); 50 | 51 | static const uint64_t CR0_PE = 1ULL << 0; 52 | static const uint64_t CR0_PG = 1ULL << 31; 53 | static const uint64_t CR4_PSE = 1ULL << 4; 54 | static const uint64_t CR4_PAE = 1ULL << 5; 55 | static const uint64_t CR4_PGE = 1ULL << 7; 56 | static const uint64_t CR4_OSFXSR = 1ULL << 9; 57 | static const uint64_t CR4_OSXMMEXCPT = 1ULL << 10; 58 | static const uint64_t EFER_LME = 1ULL << 8; 59 | static const uint64_t EFER_LMA = 1ULL << 10; 60 | 61 | regvalue[Cr0].Reg64 |= (CR0_PE | CR0_PG); 62 | regvalue[Cr3].Reg64 = sysregs->cr3; 63 | regvalue[Cr4].Reg64 |= (CR4_PSE | CR4_PAE | CR4_PGE | CR4_OSFXSR | CR4_OSXMMEXCPT); 64 | regvalue[Efer].Reg64 |= (EFER_LME | EFER_LMA); 65 | regvalue[Gdtr].Table.Base = sysregs->gdt_base; 66 | regvalue[Gdtr].Table.Limit = sysregs->gdt_limit; 67 | regvalue[Idtr].Table.Base = sysregs->idt_base; 68 | regvalue[Idtr].Table.Limit = sysregs->idt_limit; 69 | regvalue[Tr].Segment = { 70 | .Base = sysregs->tss_base, .Limit = sysregs->tss_limit, 71 | .Selector = 0x10, .Attributes = 0x808b, 72 | }; 73 | regvalue[Cs].Segment = { 74 | .Base = 0, .Limit = 0xfffff, 75 | .Selector = 0x08, .Attributes = 0xa0fb, 76 | }; 77 | regvalue[Ss].Segment = { 78 | .Base = 0, .Limit = 0xfffff, 79 | .Selector = 0x10, .Attributes = 0xc0f3, 80 | }; 81 | regvalue[Ds].Segment = {}; 82 | regvalue[Es].Segment = {}; 83 | regvalue[Fs].Segment = {}; 84 | regvalue[Gs].Segment = {}; 85 | WHvSetVirtualProcessorRegisters( 86 | m_vm.getHandle(), m_id, regname, N, regvalue) 87 | OR panic("set virtual processor registers error"); 88 | } 89 | 90 | void 91 | Vcpu::get_regs(Reg *regs, int count) 92 | { 93 | WHV_REGISTER_NAME regname[count]; 94 | WHV_REGISTER_VALUE regvalue[count]; 95 | 96 | for (int i = 0; i < count; i++) 97 | regname[i] = (WHV_REGISTER_NAME)regs[i].name; 98 | WHvGetVirtualProcessorRegisters( 99 | m_vm.getHandle(), m_id, regname, count, regvalue) 100 | OR panic("get virtual processor registers error"); 101 | for (int i = 0; i < count; i++) 102 | *regs[i].ptr = regvalue[i].Reg64; 103 | } 104 | 105 | void 106 | Vcpu::set_regs(Reg *regs, int count) 107 | { 108 | WHV_REGISTER_NAME regname[count]; 109 | WHV_REGISTER_VALUE regvalue[count]; 110 | 111 | for (int i = 0; i < count; i++) 112 | regname[i] = (WHV_REGISTER_NAME)regs[i].name; 113 | for (int i = 0; i < count; i++) 114 | regvalue[i].Reg64 = regs[i].value; 115 | WHvSetVirtualProcessorRegisters( 116 | m_vm.getHandle(), m_id, regname, count, regvalue) 117 | OR panic("set virtual processor registers error"); 118 | } 119 | 120 | void 121 | Vcpu::set_segbase(RegName seg, uint64_t base) 122 | { 123 | WHV_REGISTER_NAME regname[1]; 124 | WHV_REGISTER_VALUE regvalue[1]; 125 | 126 | memset(regvalue, 0, sizeof(regvalue)); 127 | regname[0] = (WHV_REGISTER_NAME)seg; 128 | regvalue[0].Segment.Base = base; 129 | WHvSetVirtualProcessorRegisters( 130 | m_vm.getHandle(), m_id, regname, 1, regvalue) 131 | OR panic("set virtual processor registers error"); 132 | } 133 | 134 | void 135 | Vcpu::run() 136 | { 137 | WHvRunVirtualProcessor( 138 | m_vm.getHandle(), m_id, 139 | &exit_context, sizeof(exit_context)) 140 | OR panic("run virtual processor error"); 141 | } 142 | 143 | void 144 | Vcpu::stop() 145 | { 146 | WHvCancelRunVirtualProcessor( 147 | m_vm.getHandle(), m_id, 0) 148 | OR panic("cannot stop virtual processor"); 149 | } 150 | -------------------------------------------------------------------------------- /loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "process.h" 3 | #include "mm.h" 4 | #include "syscall.h" 5 | #include "dump.h" 6 | 7 | static const char * 8 | get_exit_reason_str(int reason) 9 | { 10 | switch (reason) 11 | { 12 | case WHvRunVpExitReasonNone: 13 | return "none"; 14 | case WHvRunVpExitReasonMemoryAccess: 15 | return "memory"; 16 | case WHvRunVpExitReasonUnrecoverableException: 17 | return "exception"; 18 | case WHvRunVpExitReasonCanceled: 19 | return "canceled"; 20 | default: 21 | return "undefined"; 22 | } 23 | } 24 | 25 | static void 26 | print_instruction(mm_t *mm) 27 | { 28 | WHV_VP_EXIT_CONTEXT *context = &mm->vm->exit_context.VpContext; 29 | uint8_t len = context->InstructionLength; 30 | fprintf(stderr, "inst(%d): ", len); 31 | if (len == 0) 32 | len = 8; 33 | uint64_t rip = context->Rip; 34 | uint8_t *p = (uint8_t *)mm_gvirt_to_hvirt(mm, rip); 35 | for (int i = 0; i < len; i++) 36 | fprintf(stderr, "%02x ", p[i]); 37 | fprintf(stderr, "\n"); 38 | } 39 | 40 | void handle_vmexit(thread_t *thread) 41 | { 42 | vcpu_t *vcpu = &thread->vcpu; 43 | mm_t *mm = &thread->process->mm; 44 | vm_t *vm = vcpu->vm; 45 | 46 | int reason = vm->exit_context.ExitReason; 47 | if (reason == WHvRunVpExitReasonUnrecoverableException) 48 | { 49 | uint16_t *inst = (uint16_t *)mm_gvirt_to_hvirt(mm, vm->exit_context.VpContext.Rip); 50 | if (*inst == 0x050f) 51 | { // syscall 52 | uint64_t sysnum; 53 | uint64_t args[6]; 54 | vcpu_regs_t regs1[] = { 55 | VCPU_REGS_ENTRY_GET(RAX, &sysnum), 56 | VCPU_REGS_ENTRY_GET(RDI, &args[0]), 57 | VCPU_REGS_ENTRY_GET(RSI, &args[1]), 58 | VCPU_REGS_ENTRY_GET(RDX, &args[2]), 59 | VCPU_REGS_ENTRY_GET(R10, &args[3]), 60 | VCPU_REGS_ENTRY_GET(R8, &args[4]), 61 | VCPU_REGS_ENTRY_GET(R9, &args[5]), 62 | }; 63 | vcpu_get_regs(vcpu, regs1, countof(regs1)); 64 | 65 | vcpu_regvalue_t rax = handle_syscall(thread, sysnum, args); 66 | 67 | vcpu_regvalue_t rip = vm->exit_context.VpContext.Rip + 2; 68 | vcpu_regs_t regs2[] = { 69 | VCPU_REGS_ENTRY_SET(RIP, rip), 70 | VCPU_REGS_ENTRY_SET(RAX, rax), 71 | }; 72 | vcpu_set_regs(vcpu, regs2, countof(regs2)); 73 | vcpu->in_operation = true; 74 | return; 75 | } 76 | } 77 | 78 | vcpu->in_operation = false; 79 | printf("exit reason: %s (%x)\n", get_exit_reason_str(reason), reason); 80 | printf("state: %x\n", vm->exit_context.VpContext.ExecutionState.AsUINT16); 81 | printf("cs:rip : %x:%llx\n", vm->exit_context.VpContext.Cs.Selector, vm->exit_context.VpContext.Rip); 82 | 83 | switch (vm->exit_context.ExitReason) 84 | { 85 | case WHvRunVpExitReasonMemoryAccess: 86 | print_instruction(mm); 87 | printf("access info: %x\n", vm->exit_context.MemoryAccess.AccessInfo.AsUINT32); 88 | printf("gpa: %llx\n", vm->exit_context.MemoryAccess.Gpa); 89 | printf("gva: %llx\n", vm->exit_context.MemoryAccess.Gva); 90 | #if 0 91 | vcpu_regvalue_t rsp; 92 | vcpu_regs_t regs[] = { 93 | VCPU_REGS_ENTRY_GET(RSP, &rsp), 94 | }; 95 | vcpu_get_regs(vcpu, regs, countof(regs)); 96 | dump_guest_stack(mm, rsp); 97 | #endif 98 | break; 99 | 100 | case WHvRunVpExitReasonUnrecoverableException: { 101 | printf("info: %x\n", vm->exit_context.VpException.ExceptionInfo.AsUINT32); 102 | printf("type: %d\n", vm->exit_context.VpException.ExceptionType); 103 | printf("error code: %d\n", vm->exit_context.VpException.ErrorCode); 104 | printf("inst count: %d\n", vm->exit_context.VpException.InstructionByteCount); 105 | printf("parameter: %llx\n", vm->exit_context.VpException.ExceptionParameter); 106 | print_instruction(mm); 107 | break; 108 | } 109 | 110 | default: 111 | break; 112 | } 113 | 114 | vcpu_regvalue_t rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, rflags; 115 | vcpu_regs_t regs[] = { 116 | VCPU_REGS_ENTRY_GET(RAX, &rax), 117 | VCPU_REGS_ENTRY_GET(RCX, &rcx), 118 | VCPU_REGS_ENTRY_GET(RDX, &rdx), 119 | VCPU_REGS_ENTRY_GET(RBX, &rbx), 120 | VCPU_REGS_ENTRY_GET(RSP, &rsp), 121 | VCPU_REGS_ENTRY_GET(RBP, &rbp), 122 | VCPU_REGS_ENTRY_GET(RSI, &rsi), 123 | VCPU_REGS_ENTRY_GET(RDI, &rdi), 124 | VCPU_REGS_ENTRY_GET(R8, &r8), 125 | VCPU_REGS_ENTRY_GET(R9, &r9), 126 | VCPU_REGS_ENTRY_GET(R10, &r10), 127 | VCPU_REGS_ENTRY_GET(R11, &r11), 128 | VCPU_REGS_ENTRY_GET(R12, &r12), 129 | VCPU_REGS_ENTRY_GET(R13, &r13), 130 | VCPU_REGS_ENTRY_GET(R14, &r14), 131 | VCPU_REGS_ENTRY_GET(R15, &r15), 132 | VCPU_REGS_ENTRY_GET(RFLAGS, &rflags), 133 | }; 134 | vcpu_get_regs(vcpu, regs, countof(regs)); 135 | fprintf(stderr, "rax=%016lx, rbx=%016lx, rcx=%016lx, rdx=%016lx\n", rax, rbx, rcx, rdx); 136 | fprintf(stderr, "rsi=%016lx, rdi=%016lx, rbp=%016lx, rsp=%016lx\n", rsi, rdi, rbp, rsp); 137 | fprintf(stderr, " r8=%016lx, r9=%016lx, r10=%016lx, r11=%016lx\n", r8, r9, r10, r11); 138 | fprintf(stderr, "r12=%016lx, r13=%016lx, r14=%016lx, r15=%016lx\n", r12, r13, r14, r15); 139 | dump_guest_stack(mm, rsp); 140 | 141 | return; 142 | } 143 | -------------------------------------------------------------------------------- /load.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "load.h" 10 | #include "panic.h" 11 | 12 | typedef struct { 13 | uint64_t entry; 14 | uint64_t phdr; 15 | uint64_t phent; 16 | uint64_t phnum; 17 | } elf_t; 18 | 19 | static uint64_t 20 | max(uint64_t a, uint64_t b) 21 | { 22 | return a > b ? a : b; 23 | } 24 | 25 | static void 26 | push(mm_t *mm, uint64_t *rsp, const void *data, size_t n) 27 | { 28 | uint64_t remainder = roundup(n, 8) - n; 29 | *rsp -= (n + remainder); 30 | char *sp = (char *)mm_stack_gvirt_to_hvirt(mm, *rsp); 31 | memcpy(sp, data, n); 32 | memset(sp + n, 0, remainder); 33 | } 34 | 35 | static void 36 | push_strings(mm_t *mm, uint64_t *rsp, int count, char **vector, mm_gvirt_t *gvbuf) 37 | { 38 | int size = 0; 39 | int offset[count + 1]; 40 | 41 | offset[0] = 0; 42 | for (int i = 0; i < count; i++) { 43 | size += strlen(vector[i]) + 1; 44 | offset[i + 1] = size; 45 | } 46 | 47 | char buf[size]; 48 | for (int i = 0; i < count; i++) 49 | strcpy(&buf[offset[i]], vector[i]); 50 | 51 | push(mm, rsp, buf, size); 52 | for (int i = 0; i < count; i++) 53 | gvbuf[i] = *rsp + offset[i]; 54 | gvbuf[count] = 0; 55 | } 56 | 57 | static void 58 | setup_stack(elf_t *elf, mm_t *mm, load_info_t *info) 59 | { 60 | mm_gvirt_t *rsp = &info->stack; 61 | int argc = 1; 62 | char arg[] = "/bin/ls"; 63 | char *argv[] = { arg, NULL, }; 64 | char env[] = "USER=shina"; 65 | char *envp[] = { env, NULL, }; 66 | 67 | char random[16]; 68 | push(mm, rsp, random, sizeof(random)); 69 | mm_gvirt_t rand_gvirt = *rsp; 70 | 71 | int envc = 0; 72 | for (char **v = envp; *v != NULL; v++) 73 | envc++; 74 | mm_gvirt_t guest_envp[envc + 1]; 75 | push_strings(mm, rsp, envc, envp, guest_envp); 76 | 77 | mm_gvirt_t guest_argv[argc + 1]; 78 | push_strings(mm, rsp, argc, argv, guest_argv); 79 | 80 | Elf64_auxv_t auxv[] = { 81 | // { AT_BASE, {0} }, 82 | { AT_ENTRY, { elf->entry } }, 83 | { AT_PHDR, { elf->phdr } }, 84 | { AT_PHENT, { elf->phent } }, 85 | { AT_PHNUM, { elf->phnum } }, 86 | { AT_PAGESZ, {PAGE_SIZE_4K} }, 87 | { AT_RANDOM, {rand_gvirt} }, 88 | { AT_NULL, {0} }, 89 | }; 90 | push(mm, rsp, auxv, sizeof(auxv)); 91 | push(mm, rsp, guest_envp, sizeof(guest_envp)); 92 | push(mm, rsp, guest_argv, sizeof(guest_argv)); 93 | push(mm, rsp, &argc, sizeof(argc)); 94 | } 95 | 96 | static mm_mmap_prot_t 97 | conv_prot(Elf64_Word flags) 98 | { 99 | mm_mmap_prot_t prot = MM_MMAP_PROT_NONE; 100 | if (flags & PF_X) prot |= MM_MMAP_PROT_EXEC; 101 | if (flags & PF_W) prot |= MM_MMAP_PROT_WRITE; 102 | if (flags & PF_R) prot |= MM_MMAP_PROT_READ; 103 | return prot; 104 | } 105 | 106 | static void 107 | load_elf(elf_t *elf, mm_t *mm, char *filename, load_info_t *info, size_t load_offset) 108 | { 109 | int fd = open(filename, O_RDONLY, 0); 110 | if (fd < 0) 111 | panic("can't open file"); 112 | 113 | struct stat statbuf; 114 | fstat(fd, &statbuf) == 0 115 | OR panic("can't stat"); 116 | 117 | uint8_t *data = (uint8_t *)mmap((void *)0x700000000, statbuf.st_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0); 118 | if (data == MAP_FAILED) 119 | perror("mmap"), panic("mmap failed"); 120 | fprintf(stderr, "mmap: %p--%p\n", data, data + statbuf.st_size); 121 | data[0x1b2f] = 0x48; 122 | data[0x1b30] = 0x8b; 123 | data[0x1b31] = 0x83; 124 | data[0x1b32] = 0xff; 125 | data[0x1b33] = 0x5f; 126 | data[0x1b34] = 0x22; 127 | data[0x1b35] = 0x00; 128 | #if 0 129 | for (int i = 0x1b2f; i < 0x1b36; i++) 130 | data[i] = 0x90; 131 | for (int i = 0x24e18; i < 0x24e18 + 8; i++) 132 | fprintf(stderr, "%02x ", data[i]); 133 | fprintf(stderr, "\n"); 134 | #endif 135 | 136 | 137 | Elf64_Ehdr *ehdr = (Elf64_Ehdr *)data; 138 | uint8_t valid_ident[] = {0x7f, 'E', 'L', 'F', 0x02, 0x01, 0x01}; 139 | if (memcmp(ehdr->e_ident, valid_ident, sizeof(valid_ident)) != 0) 140 | panic("ELF header is invalid"); 141 | if (!(ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)) 142 | panic("ELF is not a supported type"); 143 | if (ehdr->e_machine != EM_X86_64) 144 | panic("ELF is not an x64 executable"); 145 | 146 | info->entry = elf->entry = ehdr->e_entry + load_offset; 147 | int n = ehdr->e_phnum; 148 | Elf64_Phdr *phdr = (Elf64_Phdr *)(data + ehdr->e_phoff); 149 | 150 | mm_gvirt_t heap = 0; 151 | uint64_t load_base = 0; 152 | for (int i = 0; i < n; i++) { 153 | switch (phdr[i].p_type) { 154 | case PT_LOAD: { 155 | off_t offset = rounddown(phdr[i].p_offset, PAGE_SIZE_4K); 156 | mm_gvirt_t gvirt = rounddown(phdr[i].p_vaddr, PAGE_SIZE_4K) + load_offset; 157 | uint8_t *hvirt = data + offset; 158 | uint64_t size = roundup(gvirt + phdr[i].p_memsz, PAGE_SIZE_4K) - gvirt; 159 | mm_mmap_prot_t prot = conv_prot(phdr[i].p_flags); 160 | mm_mmap(mm, gvirt, hvirt, size, prot, MM_MMAP_TYPE_MMAP); 161 | 162 | uint8_t *file_end = data + phdr[i].p_offset + phdr[i].p_filesz; 163 | size_t remainder = hvirt + size - file_end; 164 | assert(phdr[i].p_filesz != 0); 165 | memset(file_end, 0, remainder); 166 | 167 | if (load_base == 0) 168 | load_base = phdr[i].p_vaddr - phdr[i].p_offset + load_offset; 169 | heap = roundup(max(heap, gvirt + size), PAGE_SIZE_4K); 170 | break; 171 | } 172 | 173 | case PT_INTERP: 174 | printf("interp\n"); 175 | break; 176 | } 177 | } 178 | 179 | info->heap = heap; 180 | elf->phdr = load_base + ehdr->e_phoff; 181 | elf->phent = ehdr->e_phentsize; 182 | elf->phnum = ehdr->e_phnum; 183 | close(fd); 184 | 185 | } 186 | 187 | void 188 | ldr_load(mm_t *mm, int argc, char *argv[], load_info_t *info) 189 | { 190 | elf_t elf; 191 | info->stack = mm_get_stack_top(mm); 192 | load_elf(&elf, mm, argv[0], info, 0); 193 | setup_stack(&elf, mm, info); 194 | } 195 | -------------------------------------------------------------------------------- /mm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "panic.h" 5 | #include "mm.h" 6 | #include "thread.h" 7 | #include "range.h" 8 | 9 | static inline uint64_t 10 | poffset(void *p1, void *p2) 11 | { 12 | return (uint64_t)p2 - (uint64_t)p1; 13 | } 14 | 15 | static inline vm_gphys_t 16 | gvirt_to_gphys(mm_gvirt_t gvirt) 17 | { 18 | return (vm_gphys_t)gvirt; 19 | } 20 | 21 | static inline vm_gphys_t 22 | kernel_hvirt_to_gphys(mm_t *mm, void *hvirt) 23 | { 24 | return gvirt_to_gphys(mm->kernel_start) + poffset(mm->kernel, hvirt); 25 | } 26 | 27 | static mm_mmap_range_t * 28 | alloc_mmap_range(mm_gvirt_t start, void *hvirt, size_t size, mm_mmap_type_t type) 29 | { 30 | mm_mmap_range_t *mmap_range = (mm_mmap_range_t *)malloc(sizeof(mm_mmap_range_t)); 31 | if (mmap_range == NULL) 32 | panic("out of memory"); 33 | range_init(&mmap_range->range, start, start + size); 34 | mmap_range->hvirt = hvirt; 35 | mmap_range->size = size; 36 | mmap_range->type = type; 37 | return mmap_range; 38 | } 39 | 40 | static inline range_root_t 41 | get_mmap_range_root(mm_t *mm) 42 | { 43 | return (range_root_t)&mm->mmap_range_root; 44 | } 45 | 46 | void 47 | mm_mmap(mm_t *mm, mm_gvirt_t gvirt, void *hvirt, size_t size, mm_mmap_prot_t prot, mm_mmap_type_t type) 48 | { 49 | assert(gvirt < mm->kernel_start); 50 | 51 | vm_mmap(mm->vm, gvirt_to_gphys(gvirt), hvirt, size, (vm_mmap_prot_t)prot); 52 | 53 | mm_mmap_range_t *mmap_range = alloc_mmap_range(gvirt, hvirt, size, type); 54 | range_insert(get_mmap_range_root(mm), &mmap_range->range); 55 | } 56 | 57 | 58 | static void * 59 | range_to_hvirt(range_t *r, mm_gvirt_t gvirt) 60 | { 61 | mm_mmap_range_t *mmap_range = (mm_mmap_range_t *)r; 62 | return (char *)mmap_range->hvirt + (gvirt - mmap_range->range.start); 63 | } 64 | 65 | void * 66 | mm_gvirt_to_hvirt(mm_t *mm, mm_gvirt_t gvirt) 67 | { 68 | range_t *r = range_search_one(get_mmap_range_root(mm), gvirt); 69 | if (r == NULL) 70 | return NULL; 71 | return range_to_hvirt(r, gvirt); 72 | } 73 | 74 | bool 75 | mm_copy_from_user(mm_t *mm, void *dst, mm_gvirt_t src, size_t size) 76 | { 77 | range_t *r = range_search_one(get_mmap_range_root(mm), src); 78 | if (r == NULL) 79 | return false; 80 | if (r->end < src + size) 81 | panic("cross the page boundary"); 82 | void *src_hvirt = range_to_hvirt(r, src); 83 | memcpy(dst, src_hvirt, size); 84 | return true; 85 | } 86 | 87 | bool 88 | mm_copy_to_user(mm_t *mm, mm_gvirt_t dst, void *src, size_t size) 89 | { 90 | range_t *r = range_search_one(get_mmap_range_root(mm), dst); 91 | if (r == NULL) 92 | return false; 93 | if (r->end < dst + size) 94 | panic("cross the page boundary"); 95 | void *dst_hvirt = range_to_hvirt(r, dst); 96 | memcpy(dst_hvirt, src, size); 97 | return true; 98 | } 99 | 100 | void 101 | mm_dump_range_tree(mm_t *mm) 102 | { 103 | range_print(get_mmap_range_root(mm)); 104 | } 105 | 106 | void 107 | mm_get_sysregs(mm_t *mm, vcpu_sysregs_t *sysregs) 108 | { 109 | sysregs->cr3 = kernel_hvirt_to_gphys(mm, mm->kernel->pml4); 110 | sysregs->gdt_base = kernel_hvirt_to_gphys(mm, mm->kernel->gdt); 111 | sysregs->gdt_limit = 0x17; 112 | sysregs->idt_base = kernel_hvirt_to_gphys(mm, mm->kernel->idt); 113 | sysregs->idt_limit = PAGE_SIZE_4K - 1; 114 | sysregs->tss_base = kernel_hvirt_to_gphys(mm, mm->kernel->tss); 115 | sysregs->tss_limit = PAGE_SIZE_4K - 1; // 0xffff ? 116 | } 117 | 118 | mm_gvirt_t 119 | mm_get_stack_top(mm_t *mm) 120 | { 121 | return mm->stack_top; 122 | } 123 | 124 | int 125 | mm_expand_heap(mm_t *mm, mm_gvirt_t new_heap_end) 126 | { 127 | new_heap_end = roundup(new_heap_end, PAGE_SIZE_4K); 128 | assert(new_heap_end > mm->heap_end); 129 | size_t size_diff = new_heap_end - mm->heap_end; 130 | void *heap = mmap(NULL, size_diff, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 131 | if (!heap) 132 | panic("out of memory"); 133 | mm_mmap(mm, mm->heap_end, heap, size_diff, 134 | MM_MMAP_PROT_READ | MM_MMAP_PROT_WRITE, 135 | MM_MMAP_TYPE_ALLOC); 136 | mm->heap_size += size_diff; 137 | mm->heap_end = new_heap_end; 138 | return new_heap_end; 139 | } 140 | 141 | void 142 | mm_setup_heap(mm_t *mm, mm_gvirt_t heap_start) 143 | { 144 | mm->heap_size = PAGE_SIZE_4K; 145 | mm->heap_start = heap_start; 146 | mm->heap_end = heap_start + mm->heap_size; 147 | mm->heap = mmap(NULL, mm->heap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 148 | if (!mm->heap) 149 | panic("out of memory"); 150 | mm_mmap(mm, mm->heap_start, mm->heap, mm->heap_size, 151 | MM_MMAP_PROT_READ | MM_MMAP_PROT_WRITE, 152 | MM_MMAP_TYPE_ALLOC); 153 | } 154 | 155 | void 156 | mm_setup_stack(mm_t *mm) 157 | { 158 | mm->stack_size = 64 KiB; 159 | mm->stack_top = mm->kernel_start; 160 | mm->stack_bottom = mm->stack_top - mm->stack_size; 161 | mm->stack = mmap(NULL, mm->stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 162 | if (!mm->stack) 163 | panic("out of memory"); 164 | mm_mmap(mm, mm->stack_bottom, mm->stack, mm->stack_size, 165 | MM_MMAP_PROT_READ | MM_MMAP_PROT_WRITE, 166 | MM_MMAP_TYPE_ALLOC); 167 | } 168 | 169 | void 170 | mm_setup_kernel(mm_t *mm) 171 | { 172 | mm->kernel_start = 255 GiB; 173 | mm->kernel_size = roundup(sizeof(*mm->kernel), PAGE_SIZE_4K); 174 | mm->kernel = (__typeof(mm->kernel))aligned_alloc(PAGE_SIZE_4K, mm->kernel_size); 175 | if (!mm->kernel) 176 | panic("out of memory"); 177 | memset(mm->kernel, 0, mm->kernel_size); 178 | vm_mmap(mm->vm, gvirt_to_gphys(mm->kernel_start), 179 | mm->kernel, mm->kernel_size, 180 | VM_MMAP_PROT_READ | VM_MMAP_PROT_WRITE); 181 | 182 | const uint64_t PTE_P = 1ULL << 0; 183 | const uint64_t PTE_RW = 1ULL << 1; 184 | const uint64_t PTE_US = 1ULL << 2; 185 | const uint64_t PTE_PS = 1ULL << 7; 186 | const uint64_t PML4E_FLAG = PTE_P | PTE_RW | PTE_US; 187 | const uint64_t PDPTE_FLAG = PTE_P | PTE_RW | PTE_US | PTE_PS; 188 | mm->kernel->pml4[0] = kernel_hvirt_to_gphys(mm, mm->kernel->pdpt) | PML4E_FLAG; 189 | const uint64_t pdpte_count = mm->kernel_start / (1 GiB); 190 | for (uint64_t i = 0; i < pdpte_count; i++) 191 | mm->kernel->pdpt[i] = i GiB | PDPTE_FLAG; 192 | 193 | mm->kernel->gdt[0] = 0; 194 | mm->kernel->gdt[1] = 0x00a0fa000000ffff; // user code 195 | mm->kernel->gdt[2] = 0x00c0f2000000ffff; // user data 196 | } 197 | 198 | 199 | void 200 | mm_init(mm_t *mm, vm_t *vm) 201 | { 202 | mm->vm = vm; 203 | mm->mmap_range_root = NULL; 204 | } 205 | -------------------------------------------------------------------------------- /vm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "vm.h" 7 | #include "panicw.hpp" 8 | 9 | #define SUCCESS 0x80000000 10 | #undef OR 11 | #define OR & SUCCESS ^ SUCCESS ?(void)0: 12 | 13 | static bool initialized = false; 14 | 15 | #if 0 16 | _Noreturn void 17 | panicw(HRESULT result, const char *msg) 18 | { 19 | fprintf(stderr, "vm: %s\n", msg); 20 | LPVOID lpMsgBuf; 21 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 22 | FORMAT_MESSAGE_FROM_SYSTEM | 23 | FORMAT_MESSAGE_IGNORE_INSERTS, 24 | NULL, result, 25 | MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 26 | (LPTSTR) &lpMsgBuf, 0, NULL); 27 | fputs((const char *)lpMsgBuf, stderr); 28 | exit(EXIT_FAILURE); 29 | } 30 | #endif 31 | 32 | static void 33 | vmm_init(void) 34 | { 35 | UINT32 size; 36 | WHV_CAPABILITY capability; 37 | 38 | WHvGetCapability( 39 | WHvCapabilityCodeHypervisorPresent, 40 | &capability, sizeof(capability), &size); 41 | if (!capability.HypervisorPresent) 42 | panic("Windows Hypervisor Platform is not enabled"); 43 | } 44 | 45 | void 46 | vm_create(vm_t *vm) 47 | { 48 | if (!initialized) { 49 | vmm_init(); 50 | initialized = true; 51 | } 52 | 53 | assert(vm != NULL); 54 | WHvCreatePartition(&vm->handle) 55 | OR panic("create partition error"); 56 | 57 | UINT32 cpu_count = 1; 58 | WHvSetPartitionProperty( 59 | vm->handle, 60 | WHvPartitionPropertyCodeProcessorCount, 61 | &cpu_count, sizeof(cpu_count)) 62 | OR panic("set partition property error"); 63 | 64 | WHvSetupPartition(vm->handle) 65 | OR panic("setup partition error"); 66 | } 67 | 68 | void 69 | vm_mmap(vm_t *vm, vm_gphys_t gphys, void *hvirt, size_t size, vm_mmap_prot_t prot) 70 | { 71 | HRESULT hr; 72 | 73 | assert(vm != NULL); 74 | printf("mmap: hvirt=%p, gphys=%lx, size=%lx, prot=%x\n", 75 | hvirt, gphys, size, prot); 76 | WHV_MAP_GPA_RANGE_FLAGS wprot = (WHV_MAP_GPA_RANGE_FLAGS)prot; 77 | hr = WHvMapGpaRange(vm->handle, hvirt, gphys, size, wprot); 78 | if (FAILED(hr)) 79 | panicw(hr, "user mmap error"); 80 | } 81 | 82 | void 83 | vm_create_vcpu(vm_t *vm, vcpu_t *vcpu) 84 | { 85 | static UINT16 vcpu_id = 0; 86 | 87 | vcpu->vm = vm; 88 | vcpu->id = vcpu_id++; 89 | WHvCreateVirtualProcessor(vm->handle, vcpu->id, 0) 90 | OR panic("create virtual processor error"); 91 | } 92 | 93 | void 94 | vcpu_init_sysregs(vcpu_t *vcpu, vcpu_sysregs_t *sysregs) 95 | { 96 | vm_t *vm = vcpu->vm; 97 | 98 | enum { 99 | Cr0, Cr3, Cr4, Efer, Gdtr, Idtr, Tr, 100 | Cs, Ss, Ds, Es, Fs, Gs, 101 | }; 102 | WHV_REGISTER_NAME regname[] = { 103 | #define REGNAME_ENTRY(reg) WHvX64Register##reg 104 | REGNAME_ENTRY(Cr0), 105 | REGNAME_ENTRY(Cr3), 106 | REGNAME_ENTRY(Cr4), 107 | REGNAME_ENTRY(Efer), 108 | REGNAME_ENTRY(Idtr), 109 | REGNAME_ENTRY(Gdtr), 110 | REGNAME_ENTRY(Tr), 111 | REGNAME_ENTRY(Cs), 112 | REGNAME_ENTRY(Ss), 113 | REGNAME_ENTRY(Ds), 114 | REGNAME_ENTRY(Es), 115 | REGNAME_ENTRY(Fs), 116 | REGNAME_ENTRY(Gs), 117 | }; 118 | WHV_REGISTER_VALUE regvalue[countof(regname)]; 119 | WHvGetVirtualProcessorRegisters( 120 | vm->handle, vcpu->id, regname, countof(regname), regvalue) 121 | OR panic("get virtual processor registers error"); 122 | 123 | static const uint64_t CR0_PE = 1ULL << 0; 124 | static const uint64_t CR0_PG = 1ULL << 31; 125 | static const uint64_t CR4_PSE = 1ULL << 4; 126 | static const uint64_t CR4_PAE = 1ULL << 5; 127 | static const uint64_t CR4_PGE = 1ULL << 7; 128 | static const uint64_t CR4_OSFXSR = 1ULL << 9; 129 | static const uint64_t CR4_OSXMMEXCPT = 1ULL << 10; 130 | static const uint64_t EFER_LME = 1ULL << 8; 131 | static const uint64_t EFER_LMA = 1ULL << 10; 132 | 133 | regvalue[Cr0].Reg64 |= (CR0_PE | CR0_PG); 134 | regvalue[Cr3].Reg64 = sysregs->cr3; 135 | regvalue[Cr4].Reg64 |= (CR4_PSE | CR4_PAE | CR4_PGE | CR4_OSFXSR | CR4_OSXMMEXCPT); 136 | regvalue[Efer].Reg64 |= (EFER_LME | EFER_LMA); 137 | regvalue[Gdtr].Table.Base = sysregs->gdt_base; 138 | regvalue[Gdtr].Table.Limit = sysregs->gdt_limit; 139 | regvalue[Idtr].Table.Base = sysregs->idt_base; 140 | regvalue[Idtr].Table.Limit = sysregs->idt_limit; 141 | regvalue[Idtr].Table.Base = 0; 142 | regvalue[Idtr].Table.Limit = 0; 143 | regvalue[Tr].Segment.Base = sysregs->tss_base; 144 | regvalue[Tr].Segment.Limit = sysregs->tss_limit; 145 | regvalue[Tr].Segment.Selector = 0x10; 146 | regvalue[Tr].Segment.Attributes = 0x808b; 147 | WHV_X64_SEGMENT_REGISTER CodeSegment; 148 | CodeSegment.Base = 0; 149 | CodeSegment.Limit = 0xfffff; 150 | CodeSegment.Selector = 0x08; 151 | CodeSegment.Attributes = 0xa0fb; 152 | regvalue[Cs].Segment = CodeSegment; 153 | WHV_X64_SEGMENT_REGISTER DataSegment; 154 | DataSegment.Base = 0; 155 | DataSegment.Limit = 0xfffff; 156 | DataSegment.Selector = 0x10; 157 | DataSegment.Attributes = 0xc0f3; 158 | regvalue[Ss].Segment = DataSegment; 159 | regvalue[Ds].Segment = {}; 160 | regvalue[Es].Segment = {}; 161 | regvalue[Fs].Segment = {}; 162 | regvalue[Gs].Segment = {}; 163 | WHvSetVirtualProcessorRegisters( 164 | vm->handle, vcpu->id, regname, countof(regname), regvalue) 165 | OR panic("set virtual processor registers error"); 166 | } 167 | 168 | void 169 | vcpu_get_regs(vcpu_t *vcpu, vcpu_regs_t *regs, int count) 170 | { 171 | WHV_REGISTER_NAME regname[sizeof(WHV_REGISTER_NAME) * count]; 172 | WHV_REGISTER_VALUE regvalue[sizeof(WHV_REGISTER_VALUE) * count]; 173 | 174 | for (int i = 0; i < count; i++) 175 | regname[i] = (WHV_REGISTER_NAME)regs[i].name; 176 | WHvGetVirtualProcessorRegisters( 177 | vcpu->vm->handle, vcpu->id, regname, count, regvalue) 178 | OR panic("get virtual processor registers error"); 179 | for (int i = 0; i < count; i++) 180 | *regs[i].ptr = regvalue[i].Reg64; 181 | } 182 | 183 | void 184 | vcpu_set_regs(vcpu_t *vcpu, vcpu_regs_t *regs, int count) 185 | { 186 | WHV_REGISTER_NAME regname[sizeof(WHV_REGISTER_NAME) * count]; 187 | WHV_REGISTER_VALUE regvalue[sizeof(WHV_REGISTER_VALUE) * count]; 188 | 189 | for (int i = 0; i < count; i++) 190 | regname[i] = (WHV_REGISTER_NAME)regs[i].name; 191 | for (int i = 0; i < count; i++) 192 | regvalue[i].Reg64 = regs[i].value; 193 | WHvSetVirtualProcessorRegisters( 194 | vcpu->vm->handle, vcpu->id, regname, count, regvalue) 195 | OR panic("set virtual processor registers error"); 196 | } 197 | 198 | void 199 | vcpu_set_segbase(vcpu_t *vcpu, vcpu_regname_t seg, uint64_t base) 200 | { 201 | WHV_REGISTER_NAME regname[1]; 202 | WHV_REGISTER_VALUE regvalue[1]; 203 | 204 | memset(regvalue, 0, sizeof(regvalue)); 205 | regname[0] = (WHV_REGISTER_NAME)seg; 206 | regvalue[0].Segment.Base = base; 207 | WHvSetVirtualProcessorRegisters( 208 | vcpu->vm->handle, vcpu->id, regname, 1, regvalue) 209 | OR panic("set virtual processor registers error"); 210 | } 211 | 212 | void 213 | vcpu_run(vcpu_t *vcpu) 214 | { 215 | vm_t *vm = vcpu->vm; 216 | WHvRunVirtualProcessor( 217 | vm->handle, vcpu->id, 218 | &vm->exit_context, sizeof(vm->exit_context)) 219 | OR panic("run virtual processor error"); 220 | } 221 | 222 | void 223 | vcpu_stop(vcpu_t *vcpu) 224 | { 225 | vm_t *vm = vcpu->vm; 226 | WHvCancelRunVirtualProcessor( 227 | vm->handle, vcpu->id, 0) 228 | OR panic("cannot stop virtual processor"); 229 | } -------------------------------------------------------------------------------- /linux.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PATH_MAX 4096 4 | 5 | #define SYSCALLS \ 6 | SYSCALL(0, unimplemented) \ 7 | SYSCALL(1, write) \ 8 | SYSCALL(2, unimplemented) \ 9 | SYSCALL(3, unimplemented) \ 10 | SYSCALL(4, unimplemented) \ 11 | SYSCALL(5, unimplemented) \ 12 | SYSCALL(6, unimplemented) \ 13 | SYSCALL(7, unimplemented) \ 14 | SYSCALL(8, unimplemented) \ 15 | SYSCALL(9, unimplemented) \ 16 | SYSCALL(10, unimplemented) \ 17 | SYSCALL(11, unimplemented) \ 18 | SYSCALL(12, brk) \ 19 | SYSCALL(13, unimplemented) \ 20 | SYSCALL(14, unimplemented) \ 21 | SYSCALL(15, unimplemented) \ 22 | SYSCALL(16, unimplemented) \ 23 | SYSCALL(17, unimplemented) \ 24 | SYSCALL(18, unimplemented) \ 25 | SYSCALL(19, unimplemented) \ 26 | SYSCALL(20, unimplemented) \ 27 | SYSCALL(21, unimplemented) \ 28 | SYSCALL(22, unimplemented) \ 29 | SYSCALL(23, unimplemented) \ 30 | SYSCALL(24, unimplemented) \ 31 | SYSCALL(25, unimplemented) \ 32 | SYSCALL(26, unimplemented) \ 33 | SYSCALL(27, unimplemented) \ 34 | SYSCALL(28, unimplemented) \ 35 | SYSCALL(29, unimplemented) \ 36 | SYSCALL(30, unimplemented) \ 37 | SYSCALL(31, unimplemented) \ 38 | SYSCALL(32, unimplemented) \ 39 | SYSCALL(33, unimplemented) \ 40 | SYSCALL(34, unimplemented) \ 41 | SYSCALL(35, unimplemented) \ 42 | SYSCALL(36, unimplemented) \ 43 | SYSCALL(37, unimplemented) \ 44 | SYSCALL(38, unimplemented) \ 45 | SYSCALL(39, unimplemented) \ 46 | SYSCALL(40, unimplemented) \ 47 | SYSCALL(41, unimplemented) \ 48 | SYSCALL(42, unimplemented) \ 49 | SYSCALL(43, unimplemented) \ 50 | SYSCALL(44, unimplemented) \ 51 | SYSCALL(45, unimplemented) \ 52 | SYSCALL(46, unimplemented) \ 53 | SYSCALL(47, unimplemented) \ 54 | SYSCALL(48, unimplemented) \ 55 | SYSCALL(49, unimplemented) \ 56 | SYSCALL(50, unimplemented) \ 57 | SYSCALL(51, unimplemented) \ 58 | SYSCALL(52, unimplemented) \ 59 | SYSCALL(53, unimplemented) \ 60 | SYSCALL(54, unimplemented) \ 61 | SYSCALL(55, unimplemented) \ 62 | SYSCALL(56, unimplemented) \ 63 | SYSCALL(57, unimplemented) \ 64 | SYSCALL(58, unimplemented) \ 65 | SYSCALL(59, unimplemented) \ 66 | SYSCALL(60, unimplemented) \ 67 | SYSCALL(61, unimplemented) \ 68 | SYSCALL(62, unimplemented) \ 69 | SYSCALL(63, uname) \ 70 | SYSCALL(64, unimplemented) \ 71 | SYSCALL(65, unimplemented) \ 72 | SYSCALL(66, unimplemented) \ 73 | SYSCALL(67, unimplemented) \ 74 | SYSCALL(68, unimplemented) \ 75 | SYSCALL(69, unimplemented) \ 76 | SYSCALL(70, unimplemented) \ 77 | SYSCALL(71, unimplemented) \ 78 | SYSCALL(72, unimplemented) \ 79 | SYSCALL(73, unimplemented) \ 80 | SYSCALL(74, unimplemented) \ 81 | SYSCALL(75, unimplemented) \ 82 | SYSCALL(76, unimplemented) \ 83 | SYSCALL(77, unimplemented) \ 84 | SYSCALL(78, unimplemented) \ 85 | SYSCALL(79, unimplemented) \ 86 | SYSCALL(80, unimplemented) \ 87 | SYSCALL(81, unimplemented) \ 88 | SYSCALL(82, unimplemented) \ 89 | SYSCALL(83, unimplemented) \ 90 | SYSCALL(84, unimplemented) \ 91 | SYSCALL(85, unimplemented) \ 92 | SYSCALL(86, unimplemented) \ 93 | SYSCALL(87, unimplemented) \ 94 | SYSCALL(88, unimplemented) \ 95 | SYSCALL(89, readlink) \ 96 | SYSCALL(90, unimplemented) \ 97 | SYSCALL(91, unimplemented) \ 98 | SYSCALL(92, unimplemented) \ 99 | SYSCALL(93, unimplemented) \ 100 | SYSCALL(94, unimplemented) \ 101 | SYSCALL(95, unimplemented) \ 102 | SYSCALL(96, unimplemented) \ 103 | SYSCALL(97, unimplemented) \ 104 | SYSCALL(98, unimplemented) \ 105 | SYSCALL(99, unimplemented) \ 106 | SYSCALL(100, unimplemented) \ 107 | SYSCALL(101, unimplemented) \ 108 | SYSCALL(102, getuid) \ 109 | SYSCALL(103, unimplemented) \ 110 | SYSCALL(104, getgid) \ 111 | SYSCALL(105, unimplemented) \ 112 | SYSCALL(106, unimplemented) \ 113 | SYSCALL(107, geteuid) \ 114 | SYSCALL(108, getegid) \ 115 | SYSCALL(109, unimplemented) \ 116 | SYSCALL(110, unimplemented) \ 117 | SYSCALL(111, unimplemented) \ 118 | SYSCALL(112, unimplemented) \ 119 | SYSCALL(113, unimplemented) \ 120 | SYSCALL(114, unimplemented) \ 121 | SYSCALL(115, unimplemented) \ 122 | SYSCALL(116, unimplemented) \ 123 | SYSCALL(117, unimplemented) \ 124 | SYSCALL(118, unimplemented) \ 125 | SYSCALL(119, unimplemented) \ 126 | SYSCALL(120, unimplemented) \ 127 | SYSCALL(121, unimplemented) \ 128 | SYSCALL(122, unimplemented) \ 129 | SYSCALL(123, unimplemented) \ 130 | SYSCALL(124, unimplemented) \ 131 | SYSCALL(125, unimplemented) \ 132 | SYSCALL(126, unimplemented) \ 133 | SYSCALL(127, unimplemented) \ 134 | SYSCALL(128, unimplemented) \ 135 | SYSCALL(129, unimplemented) \ 136 | SYSCALL(130, unimplemented) \ 137 | SYSCALL(131, unimplemented) \ 138 | SYSCALL(132, unimplemented) \ 139 | SYSCALL(133, unimplemented) \ 140 | SYSCALL(134, unimplemented) \ 141 | SYSCALL(135, unimplemented) \ 142 | SYSCALL(136, unimplemented) \ 143 | SYSCALL(137, unimplemented) \ 144 | SYSCALL(138, unimplemented) \ 145 | SYSCALL(139, unimplemented) \ 146 | SYSCALL(140, unimplemented) \ 147 | SYSCALL(141, unimplemented) \ 148 | SYSCALL(142, unimplemented) \ 149 | SYSCALL(143, unimplemented) \ 150 | SYSCALL(144, unimplemented) \ 151 | SYSCALL(145, unimplemented) \ 152 | SYSCALL(146, unimplemented) \ 153 | SYSCALL(147, unimplemented) \ 154 | SYSCALL(148, unimplemented) \ 155 | SYSCALL(149, unimplemented) \ 156 | SYSCALL(150, unimplemented) \ 157 | SYSCALL(151, unimplemented) \ 158 | SYSCALL(152, unimplemented) \ 159 | SYSCALL(153, unimplemented) \ 160 | SYSCALL(154, unimplemented) \ 161 | SYSCALL(155, unimplemented) \ 162 | SYSCALL(156, unimplemented) \ 163 | SYSCALL(157, unimplemented) \ 164 | SYSCALL(158, arch_prctl) \ 165 | SYSCALL(159, unimplemented) \ 166 | SYSCALL(160, unimplemented) \ 167 | SYSCALL(161, unimplemented) \ 168 | SYSCALL(162, unimplemented) \ 169 | SYSCALL(163, unimplemented) \ 170 | SYSCALL(164, unimplemented) \ 171 | SYSCALL(165, unimplemented) \ 172 | SYSCALL(166, unimplemented) \ 173 | SYSCALL(167, unimplemented) \ 174 | SYSCALL(168, unimplemented) \ 175 | SYSCALL(169, unimplemented) \ 176 | SYSCALL(170, unimplemented) \ 177 | SYSCALL(171, unimplemented) \ 178 | SYSCALL(172, unimplemented) \ 179 | SYSCALL(173, unimplemented) \ 180 | SYSCALL(174, unimplemented) \ 181 | SYSCALL(175, unimplemented) \ 182 | SYSCALL(176, unimplemented) \ 183 | SYSCALL(177, unimplemented) \ 184 | SYSCALL(178, unimplemented) \ 185 | SYSCALL(179, unimplemented) \ 186 | SYSCALL(180, unimplemented) \ 187 | SYSCALL(181, unimplemented) \ 188 | SYSCALL(182, unimplemented) \ 189 | SYSCALL(183, unimplemented) \ 190 | SYSCALL(184, unimplemented) \ 191 | SYSCALL(185, unimplemented) \ 192 | SYSCALL(186, unimplemented) \ 193 | SYSCALL(187, unimplemented) \ 194 | SYSCALL(188, unimplemented) \ 195 | SYSCALL(189, unimplemented) \ 196 | SYSCALL(190, unimplemented) \ 197 | SYSCALL(191, unimplemented) \ 198 | SYSCALL(192, unimplemented) \ 199 | SYSCALL(193, unimplemented) \ 200 | SYSCALL(194, unimplemented) \ 201 | SYSCALL(195, unimplemented) \ 202 | SYSCALL(196, unimplemented) \ 203 | SYSCALL(197, unimplemented) \ 204 | SYSCALL(198, unimplemented) \ 205 | SYSCALL(199, unimplemented) \ 206 | SYSCALL(200, unimplemented) \ 207 | SYSCALL(201, unimplemented) \ 208 | SYSCALL(202, unimplemented) \ 209 | SYSCALL(203, unimplemented) \ 210 | SYSCALL(204, unimplemented) \ 211 | SYSCALL(205, unimplemented) \ 212 | SYSCALL(206, unimplemented) \ 213 | SYSCALL(207, unimplemented) \ 214 | SYSCALL(208, unimplemented) \ 215 | SYSCALL(209, unimplemented) \ 216 | SYSCALL(210, unimplemented) \ 217 | SYSCALL(211, unimplemented) \ 218 | SYSCALL(212, unimplemented) \ 219 | SYSCALL(213, unimplemented) \ 220 | SYSCALL(214, unimplemented) \ 221 | SYSCALL(215, unimplemented) \ 222 | SYSCALL(216, unimplemented) \ 223 | SYSCALL(217, unimplemented) \ 224 | SYSCALL(218, unimplemented) \ 225 | SYSCALL(219, unimplemented) \ 226 | SYSCALL(220, unimplemented) \ 227 | SYSCALL(221, unimplemented) \ 228 | SYSCALL(222, unimplemented) \ 229 | SYSCALL(223, unimplemented) \ 230 | SYSCALL(224, unimplemented) \ 231 | SYSCALL(225, unimplemented) \ 232 | SYSCALL(226, unimplemented) \ 233 | SYSCALL(227, unimplemented) \ 234 | SYSCALL(228, unimplemented) \ 235 | SYSCALL(229, unimplemented) \ 236 | SYSCALL(230, unimplemented) \ 237 | SYSCALL(231, exit_group) \ 238 | 239 | enum { 240 | LINUX_EACCES = 13, 241 | }; 242 | --------------------------------------------------------------------------------