├── .clang-format ├── .clang-tidy ├── .envrc ├── .gitlab-ci.yml ├── .gitlab └── issue_templates │ ├── bug_report.md │ └── feature_request.md ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── default.nix ├── docs ├── images │ └── memlayout.png ├── implementation.md ├── index.md ├── proposals.md └── user-documentation │ ├── data-structures.md │ ├── index.md │ ├── syscall-binary-interface.md │ └── syscall-reference.md ├── include ├── acpi.hpp ├── acpi_facs.hpp ├── acpi_fadt.hpp ├── acpi_gas.hpp ├── acpi_madt.hpp ├── acpi_mcfg.hpp ├── acpi_rsdp.hpp ├── acpi_rsdt.hpp ├── acpi_table.hpp ├── algorithm.hpp ├── alloc_result.hpp ├── api.hpp ├── arch.hpp ├── assert.hpp ├── atomic.hpp ├── avl.hpp ├── barrier.hpp ├── bitmap.hpp ├── bootstrap.hpp ├── buddy.hpp ├── capability.hpp ├── cmdline.hpp ├── compiler.hpp ├── config.hpp ├── console.hpp ├── console_serial.hpp ├── console_vga.hpp ├── counter.hpp ├── cpu.hpp ├── cpuinfo.hpp ├── cpulocal.hpp ├── cpuset.hpp ├── crd.hpp ├── delegate_result.hpp ├── descriptor.hpp ├── ec.hpp ├── elf.hpp ├── ept.hpp ├── extern.hpp ├── fpu.hpp ├── gdt.hpp ├── generic_mtrr.hpp ├── generic_page_table.hpp ├── hazards.hpp ├── hip.hpp ├── hpt.hpp ├── idt.hpp ├── idt_handlers.hpp ├── initprio.hpp ├── io.hpp ├── kobject.hpp ├── kp.hpp ├── lapic.hpp ├── list.hpp ├── lock_guard.hpp ├── math.hpp ├── mca.hpp ├── mdb.hpp ├── memory.hpp ├── monostate.hpp ├── msr.hpp ├── mtd.hpp ├── mtrr.hpp ├── multiboot.hpp ├── multiboot2.hpp ├── nodestruct.hpp ├── optional.hpp ├── page_alloc_policy.hpp ├── page_table_policies.hpp ├── panic.hpp ├── pci.hpp ├── pd.hpp ├── pt.hpp ├── qpd.hpp ├── queue.hpp ├── rcu.hpp ├── rcu_list.hpp ├── refptr.hpp ├── regs.hpp ├── result.hpp ├── rq.hpp ├── sc.hpp ├── scope_guard.hpp ├── selectors.hpp ├── slab.hpp ├── sm.hpp ├── space.hpp ├── space_mem.hpp ├── space_obj.hpp ├── space_pio.hpp ├── spinlock.hpp ├── static_vector.hpp ├── stdio.hpp ├── string.hpp ├── string_impl.hpp ├── suspend.hpp ├── syscall.hpp ├── time.hpp ├── tlb_cleanup.hpp ├── tss.hpp ├── types.hpp ├── unique_ptr.hpp ├── utcb.hpp ├── util.hpp ├── vcpu.hpp ├── vlapic.hpp ├── vmx.hpp ├── vmx_msr_bitmap.hpp ├── vmx_preemption_timer.hpp ├── vmx_types.hpp ├── vpid.hpp └── x86.hpp ├── mkdocs.yml ├── nix ├── build.nix ├── clang-tidy.nix ├── cmake-modules.nix ├── coverage.nix ├── cyberus-overlay.nix ├── docs.nix ├── integration-test.nix ├── overlay.nix ├── qemu-boot.nix ├── release.nix ├── sources.json ├── sources.nix └── stylecheck.nix ├── renovate.json ├── shell.nix ├── src ├── CMakeLists.txt ├── acpi.cpp ├── acpi_fadt.cpp ├── acpi_madt.cpp ├── acpi_mcfg.cpp ├── acpi_rsdp.cpp ├── acpi_rsdt.cpp ├── acpi_table.cpp ├── avl.cpp ├── bootstrap.cpp ├── buddy.cpp ├── cmdline.cpp ├── console.cpp ├── console_serial.cpp ├── console_vga.cpp ├── cpu.cpp ├── cpulocal.cpp ├── ec.cpp ├── ec_exc.cpp ├── ec_vmx.cpp ├── entry.S ├── ept.cpp ├── fpu.cpp ├── gdt.cpp ├── hip.cpp ├── hpt.cpp ├── hypervisor.ld ├── idt.cpp ├── init.cpp ├── kp.cpp ├── lapic.cpp ├── mca.cpp ├── mdb.cpp ├── memory.cpp ├── msr.cpp ├── mtrr.cpp ├── panic.cpp ├── pd.cpp ├── pt.cpp ├── rcu.cpp ├── regs.cpp ├── sc.cpp ├── slab.cpp ├── sm.cpp ├── space.cpp ├── space_mem.cpp ├── space_obj.cpp ├── space_pio.cpp ├── start.S ├── stdio.cpp ├── string.cpp ├── suspend.cpp ├── syscall.cpp ├── tss.cpp ├── utcb.cpp ├── vcpu.cpp ├── vlapic.cpp └── vmx.cpp ├── test ├── integration │ └── qemu-boot └── unit │ ├── CMakeLists.txt │ ├── acpi_fadt.cpp │ ├── acpi_fadt_test_helpers.hpp │ ├── algorithm.cpp │ ├── atomic.cpp │ ├── bitmap.cpp │ ├── construct_counter.hpp │ ├── list.cpp │ ├── main.cpp │ ├── math.cpp │ ├── mtrr.cpp │ ├── optional.cpp │ ├── page_table.cpp │ ├── result.cpp │ ├── scope_guard.cpp │ ├── spinlock.cpp │ ├── static_vector.cpp │ ├── string.cpp │ ├── time.cpp │ ├── unique_ptr.cpp │ ├── vmx_msr_bitmap.cpp │ └── vmx_preemption_timer.cpp └── tools ├── check-elf-segments ├── gen_usb.sh └── grub.cfg.tmpl /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AllowShortEnumsOnASingleLine: false 4 | ColumnLimit: 110 5 | EmptyLineAfterAccessModifier: Never 6 | EmptyLineBeforeAccessModifier: LogicalBlock 7 | IndentWidth: 4 8 | PointerAlignment: Left 9 | ReferenceAlignment: Left 10 | SortIncludes: true 11 | SpacesInSquareBrackets: false 12 | Standard: Cpp11 13 | UseTab: Never 14 | BreakBeforeBraces: Custom 15 | BraceWrapping: 16 | AfterClass: true 17 | AfterEnum: true 18 | AfterFunction: true 19 | AfterNamespace: true 20 | AfterStruct: false 21 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: -*, 3 | clang-analyzer-*, 4 | cppcoreguidelines-pro-type-cstyle-cast, 5 | google-global-names-in-headers, 6 | misc-unused-alias-decls, 7 | misc-unused-parameters, 8 | misc-unused-using-decls, 9 | modernize-use-nullptr 10 | WarningsAsErrors: '*' 11 | HeaderFilterRegex: '.*' 12 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /.gitlab/issue_templates/bug_report.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | (Summarize the bug encountered concisely.) 4 | 5 | ## Steps to reproduce 6 | 7 | (How one can reproduce the issue - this is very important. Include 8 | **exact** versions of all involved components. Provide details about 9 | which machine/CPU this happens on, if it is specific to a machine.) 10 | 11 | ## What is the current bug behavior? 12 | 13 | (What actually happens) 14 | 15 | ## What is the expected correct behavior? 16 | 17 | (What you should see instead) 18 | 19 | ## Relevant logs and/or screenshots 20 | 21 | (Paste any relevant logs. Booting the hypervisor with the `serial` 22 | command line option and collecting the serial output is extremely 23 | valuable, especially for crashes.) 24 | 25 | (please use code blocks (```) to format 26 | console output, logs, and code, as it's very hard to read otherwise.) 27 | 28 | ## Possible fixes 29 | 30 | (If you can, link to the line of code that might be responsible for 31 | the problem) 32 | 33 | ## Contacts 34 | 35 | (Please link any downstream issues here and tag relevant people.) 36 | 37 | /label ~bug 38 | /assign @jstecklina 39 | -------------------------------------------------------------------------------- /.gitlab/issue_templates/feature_request.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | (A concise 1-2 paragraph summary of your feature request including 4 | what high-level problem is being solved by it.) 5 | 6 | ## API Changes 7 | 8 | (Give a short description whether the hypercall API or HIP/UTCB layout 9 | need to change.) 10 | 11 | ## Relevant Projects 12 | 13 | (What downstream projects need to be kept in the loop when designing 14 | this feature. Who is affected by this change?) 15 | 16 | (Please link any downstream issues here and tag relevant people.) 17 | 18 | /label ~feature 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(HEDRON CXX ASM) 4 | 5 | include(CTest) 6 | 7 | set(CMAKE_CXX_STANDARD 20) 8 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 9 | 10 | set(default_build_type "Debug") 11 | 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 13 | message(STATUS "Setting build type to '${default_build_type}' as none was specified.") 14 | set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE 15 | STRING "Choose the type of build." FORCE) 16 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 17 | "Debug" "Release") 18 | endif() 19 | 20 | option(ENABLE_CLANG_TIDY "Enable clang-tidy analysis." OFF) 21 | 22 | # Globally enable additional goodies, if we are compiling with clang. 23 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND ENABLE_CLANG_TIDY) 24 | 25 | # Optionally enable clang-tidy for the whole project. 26 | find_program(CLANG_TIDY_EXE NAMES "clang-tidy" DOC "Path to clang-tidy executable") 27 | 28 | if(CLANG_TIDY_EXE) 29 | set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") 30 | else() 31 | message(FATAL_ERROR "clang-tidy not found. Please install for automatic static analysis.") 32 | endif() 33 | 34 | endif() 35 | 36 | include_directories(include) 37 | 38 | add_subdirectory(src) 39 | 40 | if(BUILD_TESTING) 41 | enable_testing() 42 | add_subdirectory(test/unit) 43 | endif() 44 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import ./nix/release.nix {}).hedron.builds.default-release 2 | -------------------------------------------------------------------------------- /docs/images/memlayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberus-technology/hedron/8ab6bd0bd6468be4602f65280a58ced1b1999156/docs/images/memlayout.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Hedron Hypervisor 2 | 3 | This is the documentation of the Hedron Hypervisor. Use the pane on 4 | the left to navigate to individual documents. 5 | -------------------------------------------------------------------------------- /docs/user-documentation/index.md: -------------------------------------------------------------------------------- 1 | # System Call Interface 2 | 3 | **This documentation is currently work-in-progress. Information in this 4 | documentation should be correct, but the documentation itself is incomplete.** 5 | 6 | These documents describe the system call interface for the Hedron hypervisor. 7 | -------------------------------------------------------------------------------- /include/acpi_facs.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "acpi_gas.hpp" 21 | #include "acpi_table.hpp" 22 | 23 | #pragma pack(1) 24 | 25 | /* 26 | * Firmware ACPI Control Structure (5.2.10) 27 | */ 28 | class Acpi_table_facs : public Acpi_header 29 | { 30 | public: 31 | uint32 hardware_signature; // 8 32 | uint32 firmware_waking_vector; // 12 33 | uint32 global_lock; // 16 34 | uint32 flags; // 20 35 | uint64 x_firmware_waking_vector; // 24 36 | uint8 version; // 32 37 | uint8 reserved[3]; // 33 38 | uint32 ospm_flags; // 36 39 | uint8 reserved_2[24]; // 40 40 | 41 | enum Flags 42 | { 43 | S4BIOS_F = 1u << 0, 44 | WAKE_64BIT_SUPPORTED_F = 1u << 1, 45 | }; 46 | 47 | enum Ospm_flags 48 | { 49 | WAKE_64BIT_F = 1u << 0, 50 | }; 51 | }; 52 | 53 | static_assert(sizeof(Acpi_table_facs) == 64); 54 | 55 | #pragma pack() 56 | -------------------------------------------------------------------------------- /include/acpi_gas.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | #include "types.hpp" 25 | 26 | #pragma pack(1) 27 | 28 | /* 29 | * Generic Address Structure (5.2.3.1) 30 | */ 31 | class Acpi_gas 32 | { 33 | public: 34 | uint8 asid; // ASID 35 | uint8 bits; // Register Size (bits) 36 | uint8 offset; // Register Offset 37 | uint8 access; // Access Size 38 | uint64 addr; // Register Address 39 | 40 | enum Asid 41 | { 42 | MEMORY = 0x0, 43 | IO = 0x1, 44 | PCI_CONFIG = 0x2, 45 | EC = 0x3, 46 | SMBUS = 0x4, 47 | FIXED = 0x7f 48 | }; 49 | 50 | void init(Asid reg_asid, unsigned reg_bytes, uint64 reg_addr) 51 | { 52 | asid = reg_asid; 53 | bits = static_cast(reg_bytes * 8); 54 | addr = reg_addr; 55 | } 56 | 57 | void init(uint8 reg_asid, unsigned reg_bytes, uint64 reg_addr) 58 | { 59 | init(static_cast(reg_asid), reg_bytes, reg_addr); 60 | } 61 | 62 | void init(const Acpi_gas& gas) { init(gas.asid, gas.bits / 8, gas.addr); } 63 | 64 | bool valid() const { return addr != 0; } 65 | }; 66 | 67 | #pragma pack() 68 | -------------------------------------------------------------------------------- /include/acpi_madt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "acpi_table.hpp" 25 | 26 | #pragma pack(1) 27 | 28 | /* 29 | * APIC Structure (5.2.11.4) 30 | */ 31 | class Acpi_apic 32 | { 33 | public: 34 | uint8 type; 35 | uint8 length; 36 | 37 | enum Type 38 | { 39 | LAPIC = 0, 40 | IOAPIC = 1, 41 | INTR = 2, 42 | }; 43 | }; 44 | 45 | /* 46 | * Processor Local APIC (5.2.11.5) 47 | */ 48 | class Acpi_lapic : public Acpi_apic 49 | { 50 | public: 51 | uint8 acpi_id; 52 | uint8 apic_id; 53 | uint32 flags; 54 | }; 55 | 56 | /* 57 | * Multiple APIC Description Table 58 | */ 59 | class Acpi_table_madt : public Acpi_table 60 | { 61 | private: 62 | static void parse_lapic(Acpi_apic const*); 63 | 64 | void parse_entry(Acpi_apic::Type, void (*)(Acpi_apic const*)) const; 65 | 66 | public: 67 | uint32 apic_addr; 68 | uint32 flags; 69 | Acpi_apic apic[]; 70 | 71 | void parse() const; 72 | }; 73 | 74 | #pragma pack() 75 | -------------------------------------------------------------------------------- /include/acpi_mcfg.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "acpi_table.hpp" 22 | 23 | #pragma pack(1) 24 | 25 | class Acpi_mcfg 26 | { 27 | public: 28 | uint64 addr; 29 | uint16 seg; 30 | uint8 bus_s; 31 | uint8 bus_e; 32 | uint32 reserved; 33 | }; 34 | 35 | class Acpi_table_mcfg : public Acpi_table 36 | { 37 | public: 38 | uint64 reserved; 39 | Acpi_mcfg mcfg[]; 40 | 41 | void parse() const; 42 | }; 43 | 44 | #pragma pack() 45 | -------------------------------------------------------------------------------- /include/acpi_rsdp.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | /* 25 | * Root System Description Pointer (5.2.5) 26 | */ 27 | class Acpi_rsdp 28 | { 29 | private: 30 | uint32 signature[2]; 31 | uint8 checksum; 32 | char oem_id[6]; 33 | uint8 revision; 34 | uint32 rsdt_addr; 35 | uint32 length; 36 | uint64 xsdt_addr; 37 | uint8 extended_checksum; 38 | 39 | bool good_signature() const; 40 | bool good_checksum(size_t len = 20) const; 41 | 42 | static Acpi_rsdp* find(mword, unsigned); 43 | 44 | public: 45 | static void parse(mword = 0); 46 | }; 47 | -------------------------------------------------------------------------------- /include/acpi_rsdt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "acpi_table.hpp" 22 | 23 | #pragma pack(1) 24 | 25 | /* 26 | * Root System Description Table (5.2.7 and 5.2.8) 27 | */ 28 | class Acpi_table_rsdt : public Acpi_table 29 | { 30 | private: 31 | static struct table_map { 32 | uint32 const sig; 33 | Paddr* const ptr; 34 | } const map[]; 35 | 36 | unsigned long entries(size_t size) const { return (length - sizeof(Acpi_table)) / size; } 37 | 38 | union { 39 | uint32 rsdt_; 40 | uint64 xsdt_; 41 | }; 42 | 43 | public: 44 | uint32 rsdt(unsigned i) const { return *(&rsdt_ + i); } 45 | uint64 xsdt(unsigned i) const { return *(&xsdt_ + i); } 46 | 47 | void parse(Paddr, size_t) const; 48 | }; 49 | 50 | #pragma pack() 51 | -------------------------------------------------------------------------------- /include/acpi_table.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | // Converts an ASCII ACPI table signature into its numeric representation. 25 | constexpr uint32 SIG(char const (&s)[5]) 26 | { 27 | return static_cast(s[0]) + (static_cast(s[1]) << 8) + (static_cast(s[2]) << 16) + 28 | (static_cast(s[3]) << 24); 29 | } 30 | 31 | class Acpi_header 32 | { 33 | public: 34 | uint32 signature; // 0 35 | uint32 length; // 4 36 | }; 37 | 38 | class Acpi_table : public Acpi_header 39 | { 40 | public: 41 | uint8 revision; // 8 42 | uint8 checksum; // 9 43 | char oem_id[6]; // 10 44 | char oem_table_id[8]; // 16 45 | uint32 oem_revision; // 24 46 | char creator_id[4]; // 28 47 | uint32 creator_revision; // 32 48 | 49 | // Compute the ACPI byte-by-byte checksum of an arbitrary piece of memory. 50 | static uint8 do_checksum(const void* table, size_t len); 51 | 52 | // Compute the ACPI byte-by-byte checksum of this table. 53 | uint8 do_checksum() const { return do_checksum(this, length); } 54 | 55 | bool good_checksum(Paddr addr) const; 56 | }; 57 | -------------------------------------------------------------------------------- /include/algorithm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Algorithms 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "util.hpp" 21 | 22 | template size_t array_size(T (&)[N]) { return N; }; 23 | 24 | template T* array_begin(T (&array)[SIZE]) { return &array[0]; } 25 | template T* array_end(T (&array)[SIZE]) { return &array[SIZE]; } 26 | 27 | template T accumulate(IT begin, IT_END end, T init) 28 | { 29 | for (; begin != end; ++begin) { 30 | init += *begin; 31 | } 32 | 33 | return init; 34 | } 35 | 36 | template VAL accumulate(T const& container, VAL&& init) 37 | { 38 | return accumulate(container.begin(), container.end(), forward(init)); 39 | } 40 | 41 | template IT find_if(IT begin, IT_END end, PRED predicate) 42 | { 43 | for (; begin != end and not predicate(*begin); ++begin) { 44 | } 45 | 46 | return begin; 47 | } 48 | 49 | template auto find_if(T const& container, PRED&& predicate) 50 | { 51 | return find_if(container.begin(), container.end(), forward(predicate)); 52 | } 53 | 54 | template void for_each(IT begin, IT_END end, FN&& fn) 55 | { 56 | for (; begin != end; ++begin) { 57 | fn(*begin); 58 | } 59 | } 60 | 61 | template void for_each(T const& container, FN&& fn) 62 | { 63 | for_each(container.begin(), container.end(), forward(fn)); 64 | } 65 | -------------------------------------------------------------------------------- /include/alloc_result.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory allocation result type. 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "result.hpp" 21 | 22 | // An allocation failed because the allocator ran out of space. 23 | struct Out_of_memory_error { 24 | }; 25 | 26 | template using Alloc_result = Result; 27 | using Alloc_result_void = Result_void; 28 | -------------------------------------------------------------------------------- /include/api.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Hedron Public API 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * Copyright (C) 2022 Sebastian Eydam, Cyberus Technology GmbH. 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | /// Hypercalls IDs 22 | /// 23 | /// See chapter "Hypercall Numbers" in the Kernel Interface documentation. 24 | enum class hypercall_id 25 | { 26 | HC_CALL = 0, 27 | HC_REPLY = 1, 28 | HC_CREATE_PD = 2, 29 | HC_CREATE_EC = 3, 30 | HC_CREATE_SC = 4, 31 | HC_CREATE_PT = 5, 32 | HC_CREATE_SM = 6, 33 | HC_REVOKE = 7, 34 | HC_PD_CTRL = 8, 35 | HC_EC_CTRL = 9, 36 | HC_SC_CTRL = 10, 37 | HC_PT_CTRL = 11, 38 | HC_SM_CTRL = 12, 39 | HC_MACHINE_CTRL = 15, 40 | HC_CREATE_KP = 16, 41 | HC_KP_CTRL = 17, 42 | HC_CREATE_VCPU = 19, 43 | HC_VCPU_CTRL = 20, 44 | }; 45 | -------------------------------------------------------------------------------- /include/assert.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Assertions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #if __STDC_HOSTED__ 25 | 26 | // In hosted builds (unit tests), all assertions map to the libc assert macro. 27 | 28 | #include 29 | #define assert_slow assert 30 | 31 | #else 32 | 33 | // In non-hosted builds, we always compile assertions unless they are marked as 34 | // slow. These assertions will not be included in release builds for performance 35 | // reasons. 36 | 37 | #include "panic.hpp" 38 | 39 | #define assert(X) \ 40 | do { \ 41 | if (EXPECT_FALSE(!(X))) { \ 42 | panic("Assertion \"%s\" failed at %s:%d:%s", #X, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ 43 | } \ 44 | } while (0) 45 | 46 | #ifdef NDEBUG 47 | #define assert_slow(X) \ 48 | do { \ 49 | } while (0) 50 | #else 51 | #define assert_slow(X) assert(X) 52 | #endif 53 | 54 | #endif // __STDC_HOSTED__ 55 | -------------------------------------------------------------------------------- /include/atomic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Atomic Operations 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | 23 | class Atomic 24 | { 25 | public: 26 | enum Memory_order 27 | { 28 | SEQ_CST = __ATOMIC_SEQ_CST, 29 | ACQUIRE = __ATOMIC_ACQUIRE, 30 | RELEASE = __ATOMIC_RELEASE, 31 | RELAXED = __ATOMIC_RELAXED, 32 | }; 33 | 34 | template static inline bool cmp_swap(T& ptr, T o, T n) 35 | { 36 | return __atomic_compare_exchange_n(&ptr, &o, n, false, O, O); 37 | } 38 | 39 | template static inline T exchange(T& ptr, T n) 40 | { 41 | return __atomic_exchange_n(&ptr, n, O); 42 | } 43 | 44 | template static inline T load(T& ptr) 45 | { 46 | return __atomic_load_n(&ptr, O); 47 | } 48 | 49 | template static inline void store(T& ptr, T n) 50 | { 51 | __atomic_store_n(&ptr, n, O); 52 | } 53 | 54 | template static inline T add(T& ptr, T v) 55 | { 56 | return __atomic_add_fetch(&ptr, v, O); 57 | } 58 | 59 | template static inline T fetch_add(T& ptr, T v) 60 | { 61 | return __atomic_fetch_add(&ptr, v, O); 62 | } 63 | 64 | template static inline T sub(T& ptr, T v) 65 | { 66 | return __atomic_sub_fetch(&ptr, v, O); 67 | } 68 | 69 | template static inline void set_mask(T& ptr, T v) 70 | { 71 | __atomic_fetch_or(&ptr, v, O); 72 | } 73 | 74 | template static inline void clr_mask(T& ptr, T v) 75 | { 76 | __atomic_fetch_and(&ptr, ~v, O); 77 | } 78 | 79 | template static inline bool test_set_bit(T& val, unsigned long bit) 80 | { 81 | auto const bitmask{static_cast(1) << bit}; 82 | return __atomic_fetch_or(&val, bitmask, O) & bitmask; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /include/avl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AVL Tree 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | class Avl 22 | { 23 | protected: 24 | Avl* lnk[2]; 25 | 26 | explicit Avl() : bal(2) { lnk[0] = lnk[1] = nullptr; } 27 | 28 | private: 29 | unsigned bal; 30 | 31 | bool balanced() const { return bal == 2; } 32 | 33 | static Avl* rotate(Avl*&, bool); 34 | static Avl* rotate(Avl*&, bool, unsigned); 35 | 36 | public: 37 | template static bool insert(Avl**, Avl*); 38 | template static bool remove(Avl**, Avl*); 39 | }; 40 | -------------------------------------------------------------------------------- /include/barrier.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Barriers 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | 23 | inline void barrier() { asm volatile("" : : : "memory"); } 24 | -------------------------------------------------------------------------------- /include/bootstrap.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Early Bootstrap Code 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "atomic.hpp" 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | /// Initialization for the kernel after initial boot or a suspend/resume cycle. 25 | /// 26 | /// See docs/implementation.md for a general overview of the boot flow. 27 | class Bootstrap 28 | { 29 | /// A spinlock that serializes CPU initialization. 30 | static inline mword boot_lock asm("boot_lock"); 31 | 32 | static void release_next_cpu() { Atomic::store(boot_lock, static_cast(1)); } 33 | 34 | /// A counter to implement the CPU boot barrier. Counts how many CPUs have reached the barrier. 35 | static inline mword barrier asm("boot_barrier"); 36 | 37 | /// Spin until all processors have reached this code. 38 | static void wait_for_all_cpus(); 39 | 40 | /// Create the idle EC. 41 | static void create_idle_ec(); 42 | 43 | /// Create the initial PD and EC for the rootask. 44 | static void create_roottask(); 45 | 46 | public: 47 | [[noreturn]] static void bootstrap() asm("bootstrap"); 48 | }; 49 | -------------------------------------------------------------------------------- /include/capability.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Capability 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "kobject.hpp" 24 | 25 | class Capability 26 | { 27 | private: 28 | mword val; 29 | 30 | static mword const perm = 0x1f; 31 | 32 | public: 33 | Capability() : val(0) {} 34 | 35 | Capability(Kobject* o, mword a) : val(a ? reinterpret_cast(o) | (a & perm) : 0) {} 36 | 37 | inline Kobject* obj() const { return reinterpret_cast(val & ~perm); } 38 | 39 | inline unsigned prm() const { return val & perm; } 40 | }; 41 | 42 | // Cast a capability to a specific Kobject type with dynamic type checking. 43 | // 44 | // The cast can perform additional permission bit checking if 45 | // required_permissions is given. Returns nullptr in case the cast is invalid 46 | // (just like dynamic_cast). 47 | template T* capability_cast(Capability const& cap, unsigned required_permissions = 0) 48 | { 49 | Kobject* obj{cap.obj()}; 50 | 51 | if (EXPECT_TRUE(obj and obj->type() == T::kobject_type and 52 | (cap.prm() & required_permissions) == required_permissions)) { 53 | return static_cast(cap.obj()); 54 | } else { 55 | return nullptr; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /include/cmdline.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Command Line Parser 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * Copyright (C) 2017-2018 Thomas Prescher, Cyberus Technology GmbH. 11 | * 12 | * This file is part of the Hedron hypervisor. 13 | * 14 | * Hedron is free software: you can redistribute it and/or modify it 15 | * under the terms of the GNU General Public License version 2 as 16 | * published by the Free Software Foundation. 17 | * 18 | * Hedron is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License version 2 for more details. 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "compiler.hpp" 27 | #include "types.hpp" 28 | 29 | class Cmdline 30 | { 31 | private: 32 | static struct param_map { 33 | char const* arg; 34 | bool* const ptr; 35 | } const map[]; 36 | 37 | static char const* get_arg(char const**, unsigned&); 38 | 39 | public: 40 | static inline bool serial; 41 | static inline bool nodl; 42 | static inline bool nopcid; 43 | static inline bool novga; 44 | static inline bool novpid; 45 | 46 | static void init(char const*); 47 | }; 48 | -------------------------------------------------------------------------------- /include/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Configuration 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * Copyright (C) 2017-2018 Markus Partheymüller, Cyberus Technology GmbH. 11 | * Copyright (C) 2022 Sebastian Eydam, Cyberus Technology GmbH. 12 | * 13 | * This file is part of the Hedron hypervisor. 14 | * 15 | * Hedron is free software: you can redistribute it and/or modify it 16 | * under the terms of the GNU General Public License version 2 as 17 | * published by the Free Software Foundation. 18 | * 19 | * Hedron is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | * GNU General Public License version 2 for more details. 23 | */ 24 | 25 | #pragma once 26 | 27 | /// Hedron API Version 28 | /// 29 | /// This value needs to be increased for every incompatible API version by 1000 30 | /// (major version bump). Backward compatible changes need to increase this 31 | /// value by 1 (minor version bump). 32 | /// 33 | /// For example, a change to the HIP or UTCB layouts or a change in hypercall 34 | /// numbers is backwards incompatible and requires a major version bump. The 35 | /// addition of a new hypercall without changing any of the existing hypercalls 36 | /// is backwards compatible and requires a minor version bump. 37 | /// 38 | /// Do not forget to update the CHANGELOG.md in the repository. 39 | #define CFG_VER 13002 40 | 41 | #define NUM_CPU 128 42 | #define NUM_EXC 32 43 | #define NUM_VMI 256 44 | 45 | // The number of possible interrupt vectors 46 | #define NUM_INT_VECTORS 256 47 | 48 | #define NUM_PRIORITIES 128 49 | 50 | // We have one stack per CPU. Each stack will have this size. 51 | // 52 | // One page of this will be sacrificed as a stack guard. 53 | #define STACK_SIZE 0x3000 54 | -------------------------------------------------------------------------------- /include/console.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic Console 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | #include "types.hpp" 25 | #include 26 | 27 | class Spinlock; 28 | 29 | class Console 30 | { 31 | private: 32 | enum 33 | { 34 | MODE_FLAGS = 0, 35 | MODE_WIDTH = 1, 36 | MODE_PRECS = 2, 37 | FLAG_SIGNED = 1UL << 0, 38 | FLAG_ALT_FORM = 1UL << 1, 39 | FLAG_ZERO_PAD = 1UL << 2, 40 | }; 41 | 42 | Console* next; 43 | 44 | static Console* list; 45 | static Spinlock lock; 46 | 47 | virtual void putc(int) = 0; 48 | void print_num(uint64, unsigned, unsigned, unsigned); 49 | void print_str(char const*, unsigned, unsigned); 50 | 51 | FORMAT(2, 0) 52 | void vprintf(char const*, va_list); 53 | 54 | protected: 55 | NOINLINE 56 | void enable() 57 | { 58 | Console** ptr; 59 | 60 | for (ptr = &list; *ptr; ptr = &(*ptr)->next) { 61 | } 62 | 63 | *ptr = this; 64 | } 65 | 66 | public: 67 | // Print to any configured console. 68 | // 69 | // Usually, this function is not called directly. Log messages should be printed via trace(). 70 | FORMAT(1, 2) 71 | static void print(char const* format, ...); 72 | 73 | // Same as print, just for argument lists. 74 | FORMAT(1, 0) 75 | static void vprint(const char* format, va_list ap); 76 | }; 77 | -------------------------------------------------------------------------------- /include/console_serial.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Console 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "console.hpp" 24 | #include "io.hpp" 25 | 26 | class Console_serial : public Console 27 | { 28 | private: 29 | enum Register 30 | { 31 | THR = 0, // Transmit Holding Register 32 | IER = 1, // Interrupt Enable Register 33 | FCR = 2, // FIFO Control Register 34 | LCR = 3, // Line Control Register 35 | MCR = 4, // Modem Control Register 36 | LSR = 5, // Line Status Register 37 | DLL = 0, // Divisor Latch (LSB) 38 | DLM = 1, // Divisor Latch (MSB) 39 | }; 40 | 41 | static unsigned const freq = 115200; 42 | 43 | unsigned base; 44 | 45 | inline unsigned in(Register r) { return Io::in(base + r); } 46 | 47 | inline void out(Register r, unsigned v) { Io::out(base + r, static_cast(v)); } 48 | 49 | void putc(int c); 50 | 51 | public: 52 | Console_serial(); 53 | 54 | static Console_serial con; 55 | }; 56 | -------------------------------------------------------------------------------- /include/counter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Event Counters 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "atomic.hpp" 24 | #include "console_vga.hpp" 25 | #include "cpu.hpp" 26 | 27 | class Counter 28 | { 29 | public: 30 | CPULOCAL_ACCESSOR(counter, tlb_shootdown); 31 | 32 | static inline uint16 remote_tlb_shootdown(unsigned cpu) 33 | { 34 | return Atomic::load(Cpulocal::get_remote(cpu).counter_tlb_shootdown); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /include/cpuinfo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CPU information 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * Hedron is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. 9 | * 10 | * Hedron is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License version 2 for more details. 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "types.hpp" 19 | 20 | enum class Cpu_vendor : unsigned 21 | { 22 | UNKNOWN, 23 | INTEL, 24 | }; 25 | 26 | struct Cpu_info { 27 | unsigned package; 28 | unsigned core; 29 | unsigned thread; 30 | 31 | Cpu_vendor vendor; 32 | unsigned platform; 33 | unsigned family; 34 | unsigned model; 35 | unsigned stepping; 36 | unsigned brand; 37 | unsigned patch; 38 | 39 | uint32 name[12]; 40 | }; 41 | -------------------------------------------------------------------------------- /include/cpuset.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CPU Set 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "bitmap.hpp" 24 | #include "types.hpp" 25 | 26 | class Cpuset 27 | { 28 | private: 29 | Bitmap bits{false}; 30 | 31 | public: 32 | bool chk(unsigned cpu) const { return bits.atomic_fetch(cpu); } 33 | 34 | bool set(unsigned cpu) { return bits[cpu].atomic_fetch_set(); } 35 | 36 | void clr(unsigned cpu) { bits[cpu].atomic_clear(); } 37 | 38 | /// Merge another Cpuset into this one. This effectively calculates the 39 | /// union of both sets. 40 | /// 41 | /// See the note at Bitmap::atomic_union for the properties of this 42 | /// function with respect to concurrency. 43 | void merge(Cpuset const& s) { bits.atomic_union(s.bits); } 44 | }; 45 | -------------------------------------------------------------------------------- /include/crd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Capability Range Descriptor (CRD) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | #include "types.hpp" 25 | 26 | class Crd 27 | { 28 | private: 29 | mword val; 30 | 31 | public: 32 | enum Type 33 | { 34 | MEM = 1, 35 | PIO = 2, 36 | OBJ = 3, 37 | }; 38 | 39 | inline explicit Crd() : val(0) {} 40 | 41 | inline explicit Crd(mword v) : val(v) {} 42 | 43 | inline explicit Crd(Type t, mword b = 0, mword o = 0x1f, mword a = 0x1f) 44 | : val(b << 12 | o << 7 | a << 2 | t) 45 | { 46 | } 47 | 48 | inline Type type() const { return static_cast(val & 0x3); } 49 | 50 | inline unsigned attr() const { return val >> 2 & 0x1f; } 51 | 52 | inline unsigned order() const { return val >> 7 & 0x1f; } 53 | 54 | inline mword base() const { return val >> 12; } 55 | 56 | inline mword value() const { return val; } 57 | }; 58 | 59 | // A typed IPC item used to transfer capabilities. 60 | // 61 | // See `enum Kind` for possible variants of capability transfers. 62 | class Xfer 63 | { 64 | private: 65 | Crd xfer_crd; 66 | mword xfer_meta; 67 | 68 | public: 69 | inline explicit Xfer(Crd c, mword v) : xfer_crd(c), xfer_meta(v) {} 70 | 71 | inline mword flags() const { return xfer_meta & 0xfff; } 72 | 73 | inline mword hotspot() const { return xfer_meta >> 12; } 74 | 75 | inline mword metadata() const { return xfer_meta; } 76 | 77 | inline Crd crd() const { return xfer_crd; } 78 | 79 | enum class Kind 80 | { 81 | TRANSLATE = 0, 82 | DELEGATE = 1, 83 | TRANS_DELEGATE = 2, 84 | INVALID = 3, 85 | }; 86 | 87 | inline Kind kind() const { return Kind(xfer_meta & 0x3); } 88 | 89 | // Which subspaces are the target of this mapping. 90 | // 91 | // The lowest bit is the HOST subspace and it is currently inverted for 92 | // backward compatibility. 93 | inline mword subspaces() const { return ((xfer_meta >> 8) & 0x7) ^ 1; } 94 | 95 | // If true, the source should be the kernel PD. 96 | // 97 | // See "hypervisor" flag in Delegate Flags in the specification. 98 | inline bool from_kern() const { return flags() & 0x800; } 99 | }; 100 | -------------------------------------------------------------------------------- /include/delegate_result.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Delegation result and error type. 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "alloc_result.hpp" 21 | #include "result.hpp" 22 | 23 | // A delegation failed. This can happen for different reasons. See the different constructors below. 24 | struct Delegate_error { 25 | enum class type 26 | { 27 | OUT_OF_MEMORY, 28 | INVALID_MAPPING, 29 | }; 30 | 31 | type error_type; 32 | 33 | Delegate_error() = delete; 34 | 35 | // These constructors should never be called manually. Functions that fail to allocate memory return 36 | // Out_of_memory_error and these constructors will automatically convert this to Delegate_error as needed. 37 | Delegate_error(Out_of_memory_error const&) : error_type(type::OUT_OF_MEMORY) {} 38 | Delegate_error(Out_of_memory_error&&) : error_type(type::OUT_OF_MEMORY) {} 39 | 40 | Delegate_error(type error_type_) : error_type(error_type_) {} 41 | 42 | // A delegation failed because the source or destination addresses are invalid. 43 | static Delegate_error invalid_mapping() { return type::INVALID_MAPPING; } 44 | }; 45 | 46 | template using Delegate_result = Result; 47 | using Delegate_result_void = Result_void; 48 | -------------------------------------------------------------------------------- /include/descriptor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Descriptor 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | class Descriptor 25 | { 26 | protected: 27 | enum Granularity 28 | { 29 | BYTES = 0u << 23, 30 | PAGES = 1u << 23, 31 | }; 32 | 33 | enum Size 34 | { 35 | BIT_16 = 0u << 22, 36 | BIT_32 = 1u << 22 37 | }; 38 | 39 | enum Type 40 | { 41 | SYS_LDT = 2u << 8, 42 | SYS_TASK_GATE = 5u << 8, 43 | SYS_TSS = 9u << 8, 44 | SYS_CALL_GATE = 12u << 8, 45 | SYS_INTR_GATE = 14u << 8, 46 | SYS_TRAP_GATE = 15u << 8, 47 | 48 | DATA_R = 16u << 8, 49 | DATA_RA = 17u << 8, 50 | DATA_RW = 18u << 8, 51 | DATA_RWA = 19u << 8, 52 | DATA_DOWN_R = 20u << 8, 53 | DATA_DOWN_RA = 21u << 8, 54 | DATA_DOWN_RW = 22u << 8, 55 | DATA_DOWN_RWA = 23u << 8, 56 | 57 | CODE_X = 24u << 8, 58 | CODE_XA = 25u << 8, 59 | CODE_XR = 26u << 8, 60 | CODE_XRA = 27u << 8, 61 | CODE_CONF_X = 28u << 8, 62 | CODE_CONF_XA = 29u << 8, 63 | CODE_CONF_XR = 30u << 8, 64 | CODE_CONF_XRA = 31u << 8 65 | }; 66 | }; 67 | 68 | #pragma pack(1) 69 | struct Pseudo_descriptor { 70 | uint16 limit; 71 | mword base; 72 | 73 | inline Pseudo_descriptor(mword l, mword b) : limit(static_cast(l)), base(b) {} 74 | }; 75 | #pragma pack() 76 | -------------------------------------------------------------------------------- /include/elf.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Executable and Linkable Format (ELF) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | 25 | class Eh 26 | { 27 | public: 28 | uint32 ei_magic; 29 | uint8 ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, ei_pad[7]; 30 | uint16 type, machine; 31 | uint32 version; 32 | mword entry, ph_offset, sh_offset; 33 | uint32 flags; 34 | uint16 eh_size, ph_size, ph_count, sh_size, sh_count, strtab; 35 | }; 36 | 37 | class Ph32 38 | { 39 | public: 40 | uint32 type, f_offs, v_addr, p_addr, f_size, m_size, flags, align; 41 | }; 42 | 43 | class Ph64 44 | { 45 | public: 46 | uint32 type, flags; 47 | uint64 f_offs, v_addr, p_addr, f_size, m_size, align; 48 | }; 49 | -------------------------------------------------------------------------------- /include/extern.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * External Symbols 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "memory.hpp" 24 | #include "types.hpp" 25 | 26 | extern char GIT_VER; 27 | 28 | extern char PAGE_0[PAGE_SIZE]; 29 | extern char PAGE_1[PAGE_SIZE]; 30 | extern char PAGE_H[PAGE_SIZE]; 31 | 32 | extern char PDBRV; 33 | extern char PDBR; 34 | 35 | extern char LOAD_END; 36 | 37 | extern mword FIXUP_S; 38 | extern mword FIXUP_E; 39 | 40 | extern void (*CTORS_G)(); 41 | extern void (*CTORS_E)(); 42 | 43 | extern int32 const PHYS_RELOCATION; 44 | 45 | extern char entry_sysenter; 46 | extern char entry_vmx; 47 | extern mword handlers[]; 48 | extern mword hwdev_addr; 49 | 50 | extern "C" char __start_all[]; 51 | extern "C" char __resume_bsp[]; 52 | 53 | extern "C" char __start_cpu[]; 54 | extern "C" char __start_cpu_end[]; 55 | 56 | extern "C" uint32 const __start_cpu_patch_jmp_dst; 57 | extern "C" uint32 const __start_cpu_patch_rel[]; 58 | extern "C" uint32 const __start_cpu_patch_rel_end[]; 59 | 60 | // There is a label before the "iretq" in Ec::ret_user_iret. Check Ec::maybe_handle_deferred_nmi_work to see 61 | // why we need it. 62 | extern "C" uint8 iret_to_user; 63 | -------------------------------------------------------------------------------- /include/fpu.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Floating Point Unit (FPU) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "memory.hpp" 25 | #include "refptr.hpp" 26 | #include "types.hpp" 27 | 28 | class Kp; 29 | 30 | class Fpu 31 | { 32 | private: 33 | static constexpr size_t FXSAVE_HEADER_SIZE{32ul}; // Intel SDM Vol. 1 Chap. 10.5.1 34 | 35 | struct FxsaveHdr { 36 | uint16 fcw; 37 | uint16 fsw; 38 | uint8 ftw; 39 | uint8 res_; 40 | uint16 fop; 41 | uint64 fip; 42 | uint64 fdp; 43 | uint32 mxcsr; 44 | uint32 mxcsr_mask; 45 | }; 46 | static_assert(sizeof(FxsaveHdr) == FXSAVE_HEADER_SIZE); 47 | static constexpr size_t FXSAVE_AREA_SIZE{512ul}; // Intel SDM Vol. 1 Chap. 10.5.1 48 | 49 | struct FxsaveData { 50 | uint8 fpu_data[FXSAVE_AREA_SIZE - FXSAVE_HEADER_SIZE]; 51 | }; 52 | 53 | struct FpuCtx { 54 | FxsaveHdr legacy_hdr; 55 | FxsaveData legacy_data; 56 | }; 57 | static_assert(sizeof(FpuCtx) <= PAGE_SIZE, "FpuCtx has to fit into a kernel page."); 58 | 59 | Refptr data_; 60 | FpuCtx* data(); 61 | 62 | enum class Mode : uint8 63 | { 64 | XSAVEOPT, 65 | XSAVE, 66 | }; 67 | 68 | struct FpuConfig { 69 | uint64 xsave_scb; // State-Component Bitmap 70 | size_t context_size; 71 | Mode mode; 72 | }; 73 | 74 | static FpuConfig config; 75 | 76 | public: 77 | static void probe(); 78 | static void init(); 79 | 80 | void save(); 81 | void load(); 82 | 83 | // Loads the FPU state with support for handling invalid XSAVE areas. Returns true if loading the state 84 | // succeeded, returns false if it resulted in a #GP. 85 | // 86 | // This function has to be used in situation where the user space has access to the FPU state and thus may 87 | // provide a faulty state. 88 | bool load_from_user(); 89 | 90 | static bool load_xcr0(uint64 xcr0); 91 | static void restore_xcr0(); 92 | 93 | explicit Fpu(Kp* data_kp); 94 | ~Fpu() = default; 95 | }; 96 | -------------------------------------------------------------------------------- /include/hazards.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Hazards 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | inline constexpr unsigned HZD_SCHED{1u << 0}; 22 | inline constexpr unsigned HZD_RCU{1u << 1}; 23 | inline constexpr unsigned HZD_TLB{1u << 2}; // The TLB has to be flushed. 24 | inline constexpr unsigned HZD_PRK{1u << 3}; // The CPU should be parked (call Lapic::park_function). 25 | inline constexpr unsigned HZD_IDL{1u << 4}; // RCU acceleration. 26 | inline constexpr unsigned HZD_RRQ{1u << 5}; // There are SCs in the ready queue and Sc::ready_enqueue has 27 | // to be called. 28 | -------------------------------------------------------------------------------- /include/idt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Interrupt Descriptor Table (IDT) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * Copyright (C) 2018 Thomas Prescher, Cyberus Technology GmbH. 10 | * 11 | * This file is part of the Hedron hypervisor. 12 | * 13 | * Hedron is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU General Public License version 2 as 15 | * published by the Free Software Foundation. 16 | * 17 | * Hedron is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License version 2 for more details. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "config.hpp" 26 | #include "descriptor.hpp" 27 | 28 | class Idt : public Descriptor 29 | { 30 | private: 31 | uint32 val[4]; 32 | 33 | void set(Type type, unsigned dpl, unsigned selector, mword offset, unsigned ist); 34 | 35 | public: 36 | static Idt idt[NUM_INT_VECTORS]; 37 | 38 | // Construct the IDT. 39 | static void build(); 40 | 41 | // Load the IDTR to point to the IDT. Must be called after build(). 42 | static void load(); 43 | }; 44 | -------------------------------------------------------------------------------- /include/idt_handlers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * IDT Handler Modes 3 | * 4 | * Copyright (C) 2023 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | // These definitions are used in entry.S to define the handlers[] array. 21 | 22 | #define IDT_MODE_MASK 0x3 23 | 24 | // An IDT entry that userspace cannot invoke directly. 25 | #define IDT_MODE_DPL0 0 26 | 27 | // An IDT entry that is available to userspace via `int`, `int3`, or `into` instructions. 28 | #define IDT_MODE_DPL3 1 29 | 30 | // Same as IDT_MODE_DPL0, but the handler will execute on an alternate stack. 31 | #define IDT_MODE_DPL0_ALTSTACK 2 32 | -------------------------------------------------------------------------------- /include/initprio.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Static Initialization Priorities 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #define AFTER(X) (X + 1) 24 | 25 | #define PRIO_GLOBAL 100 26 | #define PRIO_BUDDY AFTER(PRIO_GLOBAL) 27 | #define PRIO_SLAB AFTER(PRIO_BUDDY) 28 | -------------------------------------------------------------------------------- /include/io.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * I/O Ports 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | 23 | class Io 24 | { 25 | public: 26 | template static inline unsigned in(unsigned port) 27 | { 28 | T val; 29 | asm volatile("in %w1, %0" : "=a"(val) : "Nd"(port)); 30 | return val; 31 | } 32 | 33 | template static inline void out(unsigned port, T val) 34 | { 35 | asm volatile("out %0, %w1" : : "a"(val), "Nd"(port)); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /include/kobject.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Kernel Object 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * Copyright (C) 2018 Stefan Hertrampf, Cyberus Technology GmbH. 10 | * Copyright (C) 2022 Sebastian Eydam, Cyberus Technology GmbH. 11 | * 12 | * This file is part of the Hedron hypervisor. 13 | * 14 | * Hedron is free software: you can redistribute it and/or modify it 15 | * under the terms of the GNU General Public License version 2 as 16 | * published by the Free Software Foundation. 17 | * 18 | * Hedron is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License version 2 for more details. 22 | */ 23 | 24 | #pragma once 25 | 26 | #include "mdb.hpp" 27 | #include "refptr.hpp" 28 | 29 | class Kobject : public Mdb 30 | { 31 | public: 32 | enum class Type : uint8 33 | { 34 | PD, 35 | EC, 36 | SC, 37 | PT, 38 | SM, 39 | KP, 40 | VCPU, 41 | }; 42 | 43 | inline Type type() const { return objtype; } 44 | 45 | private: 46 | Type const objtype; 47 | 48 | protected: 49 | Spinlock lock; 50 | 51 | explicit Kobject(Type t, Space* s, mword b, mword a, void (*f)(Rcu_elem*), void (*pref)(Rcu_elem*)) 52 | : Mdb(s, reinterpret_cast(this), b, a, f, pref), objtype(t) 53 | { 54 | } 55 | }; 56 | 57 | template class Typed_kobject : public Kobject 58 | { 59 | public: 60 | // This member makes capability_cast work. 61 | static constexpr Type kobject_type{static_type}; 62 | 63 | Typed_kobject( 64 | Space* s, mword b = 0, mword a = 0, void (*f)(Rcu_elem*) = [](Rcu_elem*) {}, 65 | void (*pref)(Rcu_elem*) = nullptr) 66 | : Kobject(static_type, s, b, a, f, pref) 67 | { 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /include/list.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * List Element 3 | * 4 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "compiler.hpp" 21 | #include "types.hpp" 22 | 23 | #if __STDC_HOSTED__ 24 | #include 25 | #endif 26 | 27 | template class Forward_list_iterator 28 | { 29 | T* ptr; 30 | 31 | public: 32 | using difference_type = ptrdiff_t; 33 | using value_type = T; 34 | using pointer = T*; 35 | using reference = T&; 36 | 37 | #if __STDC_HOSTED__ 38 | using iterator_category = std::forward_iterator_tag; 39 | #endif 40 | 41 | Forward_list_iterator(T* ptr_) : ptr{ptr_} {} 42 | 43 | T& operator*() const { return *ptr; } 44 | T* operator->() const { return ptr; } 45 | 46 | Forward_list_iterator& operator++() 47 | { 48 | ptr = ptr->next; 49 | return *this; 50 | } 51 | 52 | bool operator==(Forward_list_iterator const& rhs) const { return ptr == rhs.ptr; } 53 | bool operator!=(Forward_list_iterator const& rhs) const { return not(*this == rhs); } 54 | }; 55 | 56 | template class Forward_list_range 57 | { 58 | T* ptr; 59 | 60 | public: 61 | Forward_list_range(T* ptr_) : ptr{ptr_} {} 62 | 63 | Forward_list_iterator begin() const { return {ptr}; } 64 | Forward_list_iterator end() const { return {nullptr}; } 65 | }; 66 | 67 | template class Forward_list 68 | { 69 | private: 70 | friend class Forward_list_iterator; 71 | 72 | T* next; 73 | 74 | public: 75 | explicit inline Forward_list(T*& list) : next(nullptr) 76 | { 77 | T** ptr; 78 | 79 | for (ptr = &list; *ptr; ptr = &(*ptr)->next) { 80 | } 81 | 82 | *ptr = static_cast(this); 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /include/lock_guard.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic Lock Guard 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2015 Alexander Boettcher, Genode Labs GmbH 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | #include "cpu.hpp" 25 | 26 | template class Lock_guard 27 | { 28 | private: 29 | T& _lock; 30 | 31 | public: 32 | inline Lock_guard(T& l) : _lock(l) 33 | { 34 | // Attempting to grab a lock while preemptible. This is a bug. 35 | assert(!Cpu::preemptible()); 36 | 37 | _lock.lock(); 38 | } 39 | 40 | inline ~Lock_guard() { _lock.unlock(); } 41 | }; 42 | -------------------------------------------------------------------------------- /include/math.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Math Helper Functions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | #include "memory.hpp" 25 | #include "types.hpp" 26 | 27 | template constexpr T min(T v1, T v2) { return v1 < v2 ? v1 : v2; } 28 | 29 | template constexpr T max(T v1, T v2) { return v1 > v2 ? v1 : v2; } 30 | 31 | constexpr inline long int bit_scan_reverse(mword val) 32 | { 33 | if (EXPECT_FALSE(!val)) 34 | return -1; 35 | 36 | static_assert(sizeof(mword) == sizeof(long long), "builtin call has wrong size"); 37 | #ifdef __clang__ 38 | return sizeof(long long) * 8 - __builtin_clzll(val) - 1; 39 | #else 40 | return __builtin_ia32_bsrdi(val); 41 | #endif 42 | } 43 | 44 | constexpr inline long int bit_scan_forward(mword val) 45 | { 46 | if (EXPECT_FALSE(!val)) 47 | return -1; 48 | 49 | static_assert(sizeof(mword) == sizeof(long), "builtin call has wrong size"); 50 | return __builtin_ctzl(val); 51 | } 52 | 53 | constexpr inline long int max_order(mword base, size_t size) 54 | { 55 | long int o = bit_scan_reverse(size); 56 | 57 | if (base) 58 | o = min(bit_scan_forward(base), o); 59 | 60 | return o; 61 | } 62 | 63 | constexpr inline mword align_dn(mword val, mword align) 64 | { 65 | val &= ~(align - 1); // Expect power-of-2 66 | return val; 67 | } 68 | 69 | constexpr inline mword align_up(mword val, mword align) 70 | { 71 | val += (align - 1); // Expect power-of-2 72 | return align_dn(val, align); 73 | } 74 | 75 | template constexpr inline bool is_aligned_by_order(T val, long int order) 76 | { 77 | return (val & ((static_cast(1) << order) - 1)) == 0; 78 | } 79 | 80 | template constexpr inline bool is_page_aligned(T val) 81 | { 82 | return is_aligned_by_order(val, PAGE_BITS); 83 | } 84 | -------------------------------------------------------------------------------- /include/mca.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Machine-Check Architecture (MCA) 3 | * 4 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "cpulocal.hpp" 21 | 22 | struct Cpu_info; 23 | 24 | class Mca 25 | { 26 | private: 27 | CPULOCAL_CONST_ACCESSOR(mca, banks); 28 | 29 | public: 30 | static void init(Cpu_info const& info); 31 | static void vector(); 32 | }; 33 | -------------------------------------------------------------------------------- /include/monostate.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * STL-like monostate implementation 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | // A STL-like monostate implementation. 21 | // 22 | // This type exists as an alternative to void in template instantiations. 23 | struct monostate { 24 | }; 25 | -------------------------------------------------------------------------------- /include/mtd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Message Transfer Descriptor (MTD) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2017-2018 Markus Partheymüller, Cyberus Technology GmbH. 8 | * Copyright (C) 2017-2018 Thomas Prescher, Cyberus Technology GmbH. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "compiler.hpp" 25 | #include "types.hpp" 26 | 27 | class Mtd 28 | { 29 | public: 30 | mword val; 31 | 32 | enum Item 33 | { 34 | // IPC 35 | GPR_ACDB = 1UL << 0, 36 | GPR_BSD = 1UL << 1, 37 | RSP = 1UL << 2, 38 | RIP_LEN = 1UL << 3, 39 | RFLAGS = 1UL << 4, 40 | DS_ES = 1UL << 5, 41 | FS_GS = 1UL << 6, 42 | CS_SS = 1UL << 7, 43 | TR = 1UL << 8, 44 | LDTR = 1UL << 9, 45 | GDTR = 1UL << 10, 46 | IDTR = 1UL << 11, 47 | CR = 1UL << 12, 48 | DR = 1UL << 13, 49 | SYSENTER = 1UL << 14, 50 | QUAL = 1UL << 15, 51 | CTRL = 1UL << 16, 52 | INJ = 1UL << 17, 53 | STA = 1UL << 18, 54 | TSC = 1UL << 19, 55 | EFER_PAT = 1UL << 20, 56 | PDPTE = 1UL << 21, 57 | GPR_R8_R15 = 1UL << 22, 58 | SYSCALL_SWAPGS = 1UL << 23, 59 | TSC_TIMEOUT = 1UL << 24, 60 | 61 | VINTR = 1UL << 26, 62 | EOI = 1UL << 27, 63 | TPR = 1UL << 28, 64 | 65 | TLB = 1UL << 30, 66 | FPU = 1UL << 31, 67 | }; 68 | 69 | inline explicit Mtd(mword v) : val(v) {} 70 | }; 71 | -------------------------------------------------------------------------------- /include/mtrr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory Type Range Registers (MTRR) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "generic_mtrr.hpp" 25 | #include "msr.hpp" 26 | 27 | class Mtrr_state : public Generic_mtrr_state 28 | { 29 | public: 30 | // Return a singleton instance. 31 | static Mtrr_state& get(); 32 | }; 33 | -------------------------------------------------------------------------------- /include/multiboot.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Multiboot Support 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2017 Alexander Boettcher, Genode Labs GmbH 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "compiler.hpp" 24 | 25 | /* 26 | * Multiboot Memory Map 27 | */ 28 | #pragma pack(1) 29 | class Multiboot_mmap 30 | { 31 | public: 32 | uint32 size; 33 | uint64 addr; 34 | uint64 len; 35 | uint32 type; 36 | }; 37 | #pragma pack() 38 | 39 | /* 40 | * Multiboot Information Structure 41 | */ 42 | class Multiboot 43 | { 44 | public: 45 | enum 46 | { 47 | MAGIC = 0x2badb002, 48 | MEMORY = 1ul << 0, 49 | BOOT_DEVICE = 1ul << 1, 50 | CMDLINE = 1ul << 2, 51 | MODULES = 1ul << 3, 52 | SYMBOLS = 1ul << 4 | 1ul << 5, 53 | MEMORY_MAP = 1ul << 6, 54 | DRIVES = 1ul << 7, 55 | CONFIG_TABLE = 1ul << 8, 56 | LOADER_NAME = 1ul << 9, 57 | APM_TABLE = 1ul << 10, 58 | VBE_INFO = 1ul << 11 59 | }; 60 | 61 | uint32 flags; // 0 62 | uint32 mem_lower; // 4 63 | uint32 mem_upper; // 8 64 | uint32 boot_device; // 12 65 | uint32 cmdline; // 16 66 | uint32 mods_count; // 20 67 | uint32 mods_addr; // 24 68 | uint32 syms[4]; // 28,32,36,40 69 | uint32 mmap_len; // 44 70 | uint32 mmap_addr; // 48 71 | uint32 drives_length; // 52 72 | uint32 drives_addr; // 56 73 | uint32 config_table; // 60 74 | uint32 loader_name; // 64 75 | 76 | template void for_each_mem(char const* mmap_virt, size_t len, FUNC const& fn) const 77 | { 78 | for (char const* ptr = mmap_virt; ptr < mmap_virt + len;) { 79 | Multiboot_mmap const* map = reinterpret_cast(ptr); 80 | fn(map); 81 | ptr += map->size + 4; 82 | } 83 | } 84 | }; 85 | 86 | /* 87 | * Multiboot Module 88 | */ 89 | class Multiboot_module 90 | { 91 | public: 92 | uint32 s_addr; 93 | uint32 e_addr; 94 | uint32 cmdline; 95 | uint32 reserved; 96 | }; 97 | -------------------------------------------------------------------------------- /include/nodestruct.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Help class to avoid destruction of static variables 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "util.hpp" 21 | 22 | template class No_destruct 23 | { 24 | alignas(T) char backing[sizeof(T)]; 25 | 26 | // Prevent dynamic allocation 27 | void* operator new(size_t) noexcept { __builtin_trap(); } 28 | 29 | public: 30 | template No_destruct(ARGS&&... args) { new (backing) T(forward(args)...); } 31 | 32 | T* operator->() { return reinterpret_cast(backing); } 33 | T const* operator->() const { return reinterpret_cast(backing); } 34 | 35 | T& operator*() { return *reinterpret_cast(backing); } 36 | T const& operator*() const { return *reinterpret_cast(backing); } 37 | 38 | T* operator&() { return reinterpret_cast(backing); } 39 | T* operator&() const { return reinterpret_cast(backing); } 40 | }; 41 | -------------------------------------------------------------------------------- /include/page_alloc_policy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Policy implementations for page table code 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * Copyright (C) 2020 Markus Partheymüller, Cyberus Technology GmbH. 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "alloc_result.hpp" 22 | #include "buddy.hpp" 23 | #include "types.hpp" 24 | 25 | template class Page_alloc_policy 26 | { 27 | public: 28 | using entry = T; 29 | using pointer = T*; 30 | 31 | static pointer phys_to_pointer(entry e) { return static_cast(Buddy::phys_to_ptr(e)); } 32 | static entry pointer_to_phys(pointer p) { return Buddy::ptr_to_phys(p); } 33 | 34 | static Alloc_result alloc_zeroed_page() 35 | { 36 | return Buddy::allocator.try_alloc(0, Buddy::FILL_0).map([](void* p) -> pointer { 37 | return static_cast(p); 38 | }); 39 | } 40 | static void free_page(pointer ptr) { Buddy::allocator.free(reinterpret_cast(ptr)); } 41 | }; 42 | -------------------------------------------------------------------------------- /include/page_table_policies.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Policy implementations for page table code 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "atomic.hpp" 21 | #include "buddy.hpp" 22 | #include "types.hpp" 23 | #include "x86.hpp" 24 | 25 | template class Atomic_access_policy 26 | { 27 | public: 28 | using entry = T; 29 | using pointer = T*; 30 | 31 | static entry read(pointer ptr) { return Atomic::load(*ptr); } 32 | static void write(pointer ptr, entry e) { Atomic::store(*ptr, e); } 33 | 34 | static bool cmp_swap(pointer ptr, entry old, entry desired) 35 | { 36 | return Atomic::cmp_swap(*ptr, old, desired); 37 | } 38 | static entry exchange(pointer ptr, entry desired) { return Atomic::exchange(*ptr, desired); } 39 | }; 40 | -------------------------------------------------------------------------------- /include/panic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Panic handling 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "compiler.hpp" 21 | 22 | #if __STDC_HOSTED__ 23 | 24 | // For hosted builds, we have a header-only implementation that makes our testing easier, because we don't 25 | // need to pull in panic.cpp. 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | [[noreturn]] FORMAT(1, 2) inline void panic(char const* format, ...) 32 | { 33 | va_list ap; 34 | va_start(ap, format); 35 | 36 | vfprintf(stderr, format, ap); 37 | abort(); 38 | 39 | va_end(ap); 40 | } 41 | 42 | #else 43 | 44 | // An unrecoverable error has occurred and Hedron execution cannot continue. 45 | [[noreturn]] COLD FORMAT(1, 2) void panic(char const* format, ...); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/pci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PCI Configuration Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * 9 | * Copyright (C) 2017-2018 Markus Partheymüller, Cyberus Technology GmbH. 10 | * 11 | * This file is part of the Hedron hypervisor. 12 | * 13 | * Hedron is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU General Public License version 2 as 15 | * published by the Free Software Foundation. 16 | * 17 | * Hedron is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License version 2 for more details. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "memory.hpp" 26 | #include "types.hpp" 27 | 28 | struct Pci { 29 | static inline Paddr cfg_base; 30 | static inline size_t cfg_size; 31 | }; 32 | -------------------------------------------------------------------------------- /include/pt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Portal 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "kobject.hpp" 24 | #include "mtd.hpp" 25 | 26 | class Ec; 27 | 28 | class Pt : public Typed_kobject 29 | { 30 | private: 31 | static Slab_cache cache; 32 | 33 | static void free(Rcu_elem* a) { delete static_cast(a); } 34 | 35 | public: 36 | // Capability permission bitmask. 37 | enum 38 | { 39 | PERM_CTRL = 1U << 0, 40 | PERM_CALL = 1U << 1, 41 | }; 42 | 43 | Refptr const ec; 44 | Mtd const mtd; 45 | mword const ip; 46 | mword id; 47 | 48 | Pt(Pd*, mword, Ec*, Mtd, mword); 49 | 50 | inline void set_id(mword i) { id = i; } 51 | 52 | static inline void* operator new(size_t) { return cache.alloc(); } 53 | 54 | static inline void operator delete(void* ptr) { cache.free(ptr); } 55 | }; 56 | -------------------------------------------------------------------------------- /include/qpd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Quantum Priority Descriptor (QPD) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | class Qpd 25 | { 26 | private: 27 | mword val; 28 | 29 | public: 30 | inline explicit Qpd(mword v) : val(v) {} 31 | 32 | inline unsigned quantum() const { return static_cast(val >> 12); } 33 | 34 | inline unsigned prio() const { return static_cast(val & 0xff); } 35 | }; 36 | -------------------------------------------------------------------------------- /include/queue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Queue 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "compiler.hpp" 25 | 26 | template class Queue 27 | { 28 | private: 29 | T* headptr; 30 | 31 | public: 32 | inline Queue() : headptr(nullptr) {} 33 | 34 | inline T* head() const { return headptr; } 35 | 36 | inline void enqueue(T* t) 37 | { 38 | if (!headptr) 39 | headptr = t->prev = t->next = t; 40 | else { 41 | t->next = headptr; 42 | t->prev = headptr->prev; 43 | t->next->prev = t->prev->next = t; 44 | } 45 | } 46 | 47 | inline bool dequeue(T* t) 48 | { 49 | if (!t || !t->next || !t->prev) 50 | return false; 51 | 52 | if (t == t->next) 53 | headptr = nullptr; 54 | 55 | else { 56 | t->next->prev = t->prev; 57 | t->prev->next = t->next; 58 | if (t == headptr) 59 | headptr = t->next; 60 | } 61 | 62 | t->next = t->prev = nullptr; 63 | 64 | return true; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /include/rcu.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Read-Copy Update (RCU) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "cpulocal.hpp" 22 | #include "rcu_list.hpp" 23 | 24 | /// The central Read-Copy-Update implementation. 25 | /// 26 | /// See docs/implementation.md for a longer description of how RCU works in 27 | /// Hedron. 28 | class Rcu 29 | { 30 | private: 31 | static mword count; 32 | static mword state; 33 | 34 | CPULOCAL_ACCESSOR(rcu, l_batch); 35 | CPULOCAL_ACCESSOR(rcu, c_batch); 36 | 37 | CPULOCAL_ACCESSOR(rcu, next); 38 | CPULOCAL_ACCESSOR(rcu, curr); 39 | CPULOCAL_ACCESSOR(rcu, done); 40 | 41 | enum State 42 | { 43 | RCU_CMP = 1UL << 0, 44 | RCU_PND = 1UL << 1, 45 | }; 46 | 47 | static inline mword batch() { return state >> 2; } 48 | 49 | static inline bool complete(mword b) 50 | { 51 | return static_cast((state & ~RCU_PND) - (b << 2)) > 0; 52 | } 53 | 54 | static void start_batch(State); 55 | static void invoke_batch(); 56 | 57 | public: 58 | /// Declare the passed object ready for reclamation. 59 | /// 60 | /// This will immediately call its pre_func callback. Once the 61 | /// hypervisor has gone through quiescent states on all CPUs, the free 62 | /// callback of the object is called. 63 | static inline bool call(Rcu_elem* e) 64 | { 65 | if (e->pre_func) 66 | e->pre_func(e); 67 | 68 | return next().enqueue(e); 69 | } 70 | 71 | static void quiet(); 72 | static void update(); 73 | }; 74 | -------------------------------------------------------------------------------- /include/rcu_list.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Read-Copy Update (RCU) lists 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "atomic.hpp" 22 | #include "compiler.hpp" 23 | #include "types.hpp" 24 | 25 | class Rcu_elem 26 | { 27 | public: 28 | Rcu_elem* next; 29 | 30 | /// This callback is called when the object has no known references 31 | /// anymore and must reclaim the object. 32 | void (*func)(Rcu_elem*); 33 | 34 | /// This callback is called when the object is handed to Rcu::call(). 35 | void (*pre_func)(Rcu_elem*); 36 | 37 | explicit Rcu_elem(void (*f)(Rcu_elem*), void (*pf)(Rcu_elem*) = nullptr) 38 | : next(nullptr), func(f), pre_func(pf) 39 | { 40 | } 41 | }; 42 | 43 | class Rcu_list 44 | { 45 | public: 46 | Rcu_elem* head; 47 | Rcu_elem** tail; 48 | mword count; 49 | 50 | explicit Rcu_list() { clear(); } 51 | 52 | inline void clear() 53 | { 54 | head = nullptr; 55 | tail = &head; 56 | count = 0; 57 | } 58 | 59 | inline bool empty() { return &head == tail || head == nullptr; } 60 | 61 | inline void append(Rcu_list* l) 62 | { 63 | *tail = l->head; 64 | tail = l->tail; 65 | *tail = head; 66 | 67 | count += l->count; 68 | l->clear(); 69 | } 70 | 71 | inline bool enqueue(Rcu_elem* e) 72 | { 73 | Rcu_elem* const unused = nullptr; 74 | Rcu_elem* const in_use = reinterpret_cast(1); 75 | 76 | if ((e->next && e->next != in_use)) 77 | /* double insertion in some queue */ 78 | return false; 79 | 80 | if (e->next == in_use && tail != &e->next) 81 | /* element already in other than current queue */ 82 | return false; 83 | 84 | if (!e->next) 85 | /* new element - mark as in use */ 86 | if (!Atomic::cmp_swap(e->next, unused, in_use)) 87 | /* element got used by another queue */ 88 | return false; 89 | 90 | if (!Atomic::cmp_swap(*tail, *tail, e)) 91 | /* element got enqueued by another queue */ 92 | return false; 93 | 94 | count++; 95 | 96 | tail = &e->next; 97 | 98 | return true; 99 | } 100 | }; 101 | -------------------------------------------------------------------------------- /include/rq.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Run Queue 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * Copyright (C) 2013-2014 Alexander Boettcher, Genode Labs GmbH 10 | * 11 | * This file is part of the Hedron hypervisor. 12 | * 13 | * Hedron is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU General Public License version 2 as 15 | * published by the Free Software Foundation. 16 | * 17 | * Hedron is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License version 2 for more details. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "spinlock.hpp" 26 | 27 | class Sc; 28 | 29 | struct Rq { 30 | Spinlock lock; 31 | Sc* queue; 32 | }; 33 | -------------------------------------------------------------------------------- /include/sc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Scheduling Context 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "compiler.hpp" 25 | #include "cpulocal.hpp" 26 | #include "kobject.hpp" 27 | #include "queue.hpp" 28 | 29 | class Ec; 30 | 31 | class Sc : public Typed_kobject, public Refcount 32 | { 33 | friend class Queue; 34 | 35 | public: 36 | Refptr const ec; 37 | unsigned const cpu; 38 | unsigned const prio; 39 | uint64 time; 40 | 41 | private: 42 | Sc *prev, *next; 43 | uint64 tsc; 44 | 45 | static Slab_cache cache; 46 | 47 | CPULOCAL_REMOTE_ACCESSOR(sc, rq); 48 | CPULOCAL_ACCESSOR(sc, list); 49 | CPULOCAL_ACCESSOR(sc, prio_top); 50 | 51 | void ready_enqueue(uint64, bool); 52 | 53 | void ready_dequeue(uint64); 54 | 55 | static void free(Rcu_elem* a) 56 | { 57 | Sc* s = static_cast(a); 58 | 59 | if (s->del_ref()) { 60 | assert(Sc::current() != s); 61 | delete s; 62 | } 63 | } 64 | 65 | public: 66 | // Capability permission bitmask. 67 | enum 68 | { 69 | PERM_SC_CTRL = 1U << 0, 70 | 71 | PERM_ALL = PERM_SC_CTRL, 72 | }; 73 | 74 | CPULOCAL_ACCESSOR(sc, current); 75 | CPULOCAL_ACCESSOR(sc, ctr_link); 76 | CPULOCAL_ACCESSOR(sc, ctr_loop); 77 | 78 | static unsigned const default_prio = 1; 79 | 80 | Sc(Pd*, mword, Ec*); 81 | Sc(Pd*, mword, Ec*, unsigned, unsigned); 82 | 83 | // Access the runqueue on a remote core. 84 | // 85 | // The returned pointer is valid forever as it points to statically 86 | // allocated memory. 87 | static Rq* remote(unsigned cpu) { return &remote_ref_rq(cpu); } 88 | 89 | void remote_enqueue(bool = true); 90 | 91 | static void rrq_handler(); 92 | 93 | [[noreturn]] static void schedule(bool suspend = false); 94 | 95 | static inline void* operator new(size_t) { return cache.alloc(); } 96 | 97 | static inline void operator delete(void* ptr) { cache.free(ptr); } 98 | }; 99 | -------------------------------------------------------------------------------- /include/scope_guard.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A per-scope cleanup helper. 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include 19 | 20 | // Execute cleanup code before exiting from a scope. 21 | // 22 | // The cleanup function that is given on construction will be executed by the destructor of Scope_guard 23 | // regardless how the scope is exited. 24 | // 25 | // Typical usage is: 26 | // 27 | // { 28 | // Scope_guard g([] { ... do some cleanup ... })}; 29 | // 30 | // if (something) { 31 | // // Cleanup happens here. 32 | // return; 33 | // } 34 | // 35 | // // Cleanup happens here. 36 | // } 37 | // 38 | // BEWARE: Scope_guard vs [[noreturn]] 39 | // 40 | // It is usually an error to use a Scope_guard in a function that calls [[noreturn]] functions. In this case, 41 | // the destructor of Scope_guard is not called and will NOT call the cleanup function. A workaround is to 42 | // introduce a new scope in which to use Scope_guard that does not contain calls to [[noreturn]] functions. 43 | // 44 | // Especially in the system call layer, Hedron uses a lot of [[noreturn]] functions and Scope_guard should be 45 | // used with extra caution. 46 | // 47 | // BEWARE: Modifying state from Scope_guard cleanup functions. 48 | // 49 | // Consider the following example: 50 | // 51 | // int pitfall() 52 | // { 53 | // int i {0}; 54 | // Scope_guard g{[&i] { i = 1; }}; 55 | // 56 | // return i; 57 | // } 58 | // 59 | // This function will return 0, not 1. This may be unexpected by developers. Conceptually, the return value is 60 | // computed and _then_ the destructors run. 61 | // 62 | // Code that relies on this behavior should be avoided to keep code easy to understand and read. 63 | // 64 | // Please note that the cleanup function must be a function that returns void. 65 | template class Scope_guard 66 | { 67 | F scope_cleanup_fn; 68 | 69 | static_assert(is_void::value, 70 | "Tried to instantiate a scope guard with a function that doesn't return void."); 71 | 72 | public: 73 | Scope_guard() = delete; 74 | Scope_guard(Scope_guard&) = delete; 75 | Scope_guard& operator=(Scope_guard&) = delete; 76 | 77 | Scope_guard(F&& f) : scope_cleanup_fn(move(f)) {} 78 | Scope_guard(F const& f) : scope_cleanup_fn(f) {} 79 | 80 | ~Scope_guard() { scope_cleanup_fn(); } 81 | }; 82 | -------------------------------------------------------------------------------- /include/space.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "spinlock.hpp" 24 | 25 | class Avl; 26 | class Mdb; 27 | 28 | class Space 29 | { 30 | private: 31 | Spinlock lock; 32 | Avl* tree{nullptr}; 33 | 34 | public: 35 | enum Subspace : mword 36 | { 37 | SUBSPACE_HOST = 1U << 0, 38 | SUBSPACE_GUEST = 1U << 2, 39 | }; 40 | 41 | Mdb* tree_lookup(mword idx, bool next = false); 42 | 43 | static bool tree_insert(Mdb* node); 44 | static bool tree_remove(Mdb* node); 45 | 46 | void addreg(mword addr, size_t size, mword attr, mword type = 0); 47 | }; 48 | -------------------------------------------------------------------------------- /include/space_obj.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Object Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "capability.hpp" 24 | #include "space.hpp" 25 | #include "tlb_cleanup.hpp" 26 | 27 | class Space_mem; 28 | 29 | class Space_obj : public Space 30 | { 31 | private: 32 | static inline mword idx_to_virt(unsigned long idx) 33 | { 34 | return SPC_LOCAL_OBJ + (idx % caps) * sizeof(Capability); 35 | } 36 | 37 | inline Space_mem* space_mem(); 38 | 39 | Tlb_cleanup update(mword, Capability); 40 | 41 | public: 42 | static unsigned const caps = (END_SPACE_LIM - SPC_LOCAL_OBJ) / sizeof(Capability); 43 | 44 | static inline Capability lookup(unsigned long idx) 45 | { 46 | return *reinterpret_cast(idx_to_virt(idx)); 47 | } 48 | 49 | size_t lookup(mword, Capability&); 50 | 51 | Paddr walk(mword, bool&); 52 | 53 | Tlb_cleanup update(Mdb*, mword = 0); 54 | 55 | static void page_fault(mword, mword); 56 | 57 | static bool insert_root(Kobject*); 58 | }; 59 | -------------------------------------------------------------------------------- /include/space_pio.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Port I/O Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "space.hpp" 24 | #include "tlb_cleanup.hpp" 25 | 26 | class Space_mem; 27 | 28 | class Space_pio : public Space 29 | { 30 | private: 31 | Paddr hbmp, gbmp; 32 | 33 | static inline mword idx_to_virt(mword idx) 34 | { 35 | return SPC_LOCAL_IOP + (idx / 8 / sizeof(mword)) * sizeof(mword); 36 | } 37 | 38 | static inline mword idx_to_mask(mword idx) { return 1UL << (idx % (8 * sizeof(mword))); } 39 | 40 | void update(bool, mword, mword); 41 | 42 | public: 43 | /// Construct a new Port I/O space. 44 | /// 45 | /// During the construction, this function will modify the page table to setup the IO Permission 46 | /// Bitmap. See `Tss::build`. 47 | Space_pio(Space_mem* mem); 48 | 49 | ~Space_pio(); 50 | 51 | Paddr walk(bool = false, mword = 0); 52 | 53 | Tlb_cleanup update(Mdb*, mword = 0); 54 | }; 55 | -------------------------------------------------------------------------------- /include/spinlock.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic Spinlock 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "assert.hpp" 22 | #include "atomic.hpp" 23 | #include "config.hpp" 24 | #include "types.hpp" 25 | #include "x86.hpp" 26 | 27 | // A spinlock implementation based on a ticket lock. 28 | // 29 | // The spinlock is best used via the Lock_guard class to avoid mismatched lock/unlock calls. 30 | class Spinlock 31 | { 32 | private: 33 | using Ticket = uint8; 34 | 35 | // We use 8-bits for the individual ticket counts in val. If we ever need more CPUs, we need to use larger 36 | // integer types, because in the worst case each CPU can request one ticket. 37 | static_assert(NUM_CPU < 256, "Ticket counter can overflow"); 38 | 39 | // The next ticket that we will give out. 40 | Ticket next_ticket{0}; 41 | 42 | // The ticket that may enter the critical section. 43 | Ticket served_ticket{0}; 44 | 45 | public: 46 | void lock() 47 | { 48 | Ticket const our_ticket{ 49 | Atomic::fetch_add(next_ticket, static_cast(1))}; 50 | 51 | while (Atomic::load(served_ticket) != our_ticket) { 52 | relax(); 53 | } 54 | } 55 | 56 | void unlock() 57 | { 58 | assert_slow(is_locked()); 59 | 60 | // Only the lock holder modifies served_ticket, so we are free to use a non-atomic access here, 61 | // because there can only be other readers besides us. 62 | Ticket const next_served_ticket{static_cast(served_ticket + 1)}; 63 | 64 | Atomic::store(served_ticket, next_served_ticket); 65 | } 66 | 67 | // Check whether the lock is currently locked. 68 | // 69 | // This method is _only_ useful for positive assertions, i.e. to check whether a spinlock is currently 70 | // held. 71 | bool is_locked() const { return Atomic::load(next_ticket) != Atomic::load(served_ticket); } 72 | }; 73 | -------------------------------------------------------------------------------- /include/static_vector.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A vector with statically-allocated backing store 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "assert.hpp" 21 | #include "types.hpp" 22 | #include "util.hpp" 23 | 24 | // A vector with statically allocated backing store and a maximum size. 25 | template class Static_vector 26 | { 27 | private: 28 | // The number of elements in the vector. 29 | size_t size_{0}; 30 | 31 | // The actual backing storage for the vector elements. 32 | alignas(T) char backing[sizeof(T) * N]; 33 | 34 | public: 35 | T* data() { return reinterpret_cast(backing); } 36 | T const* data() const { return reinterpret_cast(backing); } 37 | 38 | T& operator[](size_t i) { return data()[i]; } 39 | T const& operator[](size_t i) const { return data()[i]; }; 40 | 41 | T* begin() { return &data()[0]; } 42 | T const* begin() const { return &data()[0]; } 43 | 44 | T* end() { return &data()[size()]; } 45 | T const* end() const { return &data()[size()]; } 46 | 47 | size_t size() const { return size_; }; 48 | constexpr size_t max_size() const { return N; } 49 | 50 | template void emplace_back(ARGS&&... args) 51 | { 52 | assert(size() < max_size()); 53 | 54 | new (&data()[size_++]) T(forward(args)...); 55 | } 56 | 57 | void push_back(T const& o) { emplace_back(o); } 58 | 59 | void reset() 60 | { 61 | // We cannot call resize(0) here, because resize only works for types that are default constructible. 62 | for (T& elem : *this) { 63 | elem.~T(); 64 | } 65 | 66 | size_ = 0; 67 | } 68 | 69 | void resize(size_t new_size, T const& new_value = {}) 70 | { 71 | assert(new_size <= max_size()); 72 | 73 | // Shrink the container to the given size. 74 | while (new_size < size()) { 75 | data()[--size_].~T(); 76 | } 77 | 78 | // Grow the container to the given size with the given value. 79 | while (new_size > size()) { 80 | push_back(new_value); 81 | } 82 | 83 | assert(new_size == size()); 84 | } 85 | 86 | ~Static_vector() { reset(); } 87 | }; 88 | -------------------------------------------------------------------------------- /include/stdio.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Standard I/O 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "console.hpp" 24 | #include "string.hpp" 25 | 26 | // Returns the current CPU ID or a placeholder value if the CPU ID is not yet known. 27 | // 28 | // This function is only intended to be called from the trace macro below. 29 | int trace_id(); 30 | 31 | // Emit a log message to all configured consoles. 32 | // 33 | // The first parameter is one of the TRACE_ values defined below. Messages will only be printed, if the trace 34 | // value is included in trace_mask. 35 | #define trace(T, format, ...) \ 36 | do { \ 37 | if (EXPECT_FALSE((trace_mask & (T)) == (T))) { \ 38 | Console::print("[%3d][%s:%d] " format, trace_id(), FILENAME, __LINE__, ##__VA_ARGS__); \ 39 | } \ 40 | } while (0) 41 | 42 | // Possible trace events. 43 | enum 44 | { 45 | TRACE_CPU = 1UL << 0, 46 | TRACE_APIC = 1UL << 2, 47 | TRACE_VMX = 1UL << 4, 48 | TRACE_ACPI = 1UL << 8, 49 | TRACE_MEMORY = 1UL << 13, 50 | TRACE_PCI = 1UL << 14, 51 | TRACE_SCHEDULE = 1UL << 16, 52 | TRACE_DEL = 1UL << 18, 53 | TRACE_REV = 1UL << 19, 54 | TRACE_RCU = 1UL << 20, 55 | TRACE_SYSCALL = 1UL << 30, 56 | TRACE_ERROR = 1UL << 31, 57 | }; 58 | 59 | // Enabled trace events. 60 | constexpr unsigned trace_mask = 61 | #ifdef DEBUG 62 | TRACE_VMX | 63 | #endif 64 | TRACE_CPU | TRACE_ERROR; 65 | -------------------------------------------------------------------------------- /include/string.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * String Functions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | #if __STDC_HOSTED__ 25 | #include 26 | #else 27 | 28 | extern "C" NONNULL void* memcpy(void* d, void const* s, size_t n); 29 | extern "C" NONNULL void* memmove(void* d, void const* s, size_t n); 30 | 31 | extern "C" NONNULL void* memset(void* d, int c, size_t n); 32 | 33 | #endif // __STDC_HOSTED__ 34 | 35 | /// Check whether the first n bytes in two strings match. 36 | bool strnmatch(char const* s1, char const* s2, size_t n); 37 | 38 | // Expands to the file name without path components. Does this at compile time. 39 | // See https://blog.galowicz.de/2016/02/20/short_file_macro/ 40 | #define FILENAME \ 41 | ({ \ 42 | constexpr const char* const sf__{past_last_slash(__FILE__)}; \ 43 | sf__; \ 44 | }) 45 | 46 | // Compile-time C-string search. Returns the component after the last slash. 47 | // Useful to get the filename of a path. 48 | static constexpr const char* past_last_slash(const char* const str, const char* const last_slash) 49 | { 50 | return *str == '\0' ? last_slash 51 | : *str == '/' ? past_last_slash(str + 1, str + 1) 52 | : past_last_slash(str + 1, last_slash); 53 | } 54 | 55 | static constexpr const char* past_last_slash(const char* const str) { return past_last_slash(str, str); } 56 | -------------------------------------------------------------------------------- /include/string_impl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * String Functions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | inline void* impl_memcpy(void* d, void const* s, size_t n) 26 | { 27 | void* dummy; 28 | asm volatile("rep; movsb" : "=D"(dummy), "+S"(s), "+c"(n) : "0"(d) : "memory"); 29 | return d; 30 | } 31 | 32 | inline void* impl_memmove(void* d, void const* s, size_t n) 33 | { 34 | if (d < s) { 35 | return impl_memcpy(d, s, n); 36 | } else { 37 | char* d_end = static_cast(d) + n - 1; 38 | char const* s_end = static_cast(s) + n - 1; 39 | 40 | asm volatile("std; rep movsb; cld" : "+S"(s_end), "+D"(d_end), "+c"(n) : : "memory"); 41 | 42 | return d; 43 | } 44 | } 45 | 46 | inline void* impl_memset(void* d, int c, size_t n) 47 | { 48 | void* dummy; 49 | asm volatile("rep; stosb" : "=D"(dummy), "+c"(n) : "0"(d), "a"(c) : "memory"); 50 | return d; 51 | } 52 | 53 | inline bool impl_strnmatch(char const* s1, char const* s2, size_t n) 54 | { 55 | while (n && *s1 == *s2) 56 | s1++, s2++, n--; 57 | 58 | return n == 0; 59 | } 60 | -------------------------------------------------------------------------------- /include/suspend.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ACPI Sleep State Support 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "acpi_facs.hpp" 21 | #include "types.hpp" 22 | 23 | class Suspend 24 | { 25 | private: 26 | // Set to true while suspend is ongoing. 27 | static inline bool in_progress{false}; 28 | 29 | // A pristine copy of the FACS. 30 | // 31 | // Userspace might not expect the FACS to change, but during 32 | // suspend/resume we clobber the content of the FACS. So we keep a copy 33 | // around to be able to restore its content. 34 | static inline Acpi_table_facs saved_facs; 35 | 36 | // This function needs to be called on all CPUs to prepare them to 37 | // sleep. 38 | static void prepare_cpu_for_suspend(); 39 | 40 | public: 41 | // Enter an ACPI Sleep State 42 | // 43 | // This function implements the bulk of the machine_ctrl suspend 44 | // operation. It will park all application processors, save any internal 45 | // state that will be lost while sleeping, flush caches and finally 46 | // program SLP_TYPx fields and sets the SLP_EN bit to enter the sleep 47 | // state. The wake vector in the FACS will be temporarily overwritten 48 | // and restored after the system has resumed. 49 | // 50 | // Calling this function concurrently will result in all invocations but 51 | // one failing. 52 | // 53 | // On a successful suspend this function will not return. 54 | static void suspend(uint8 slp_typa, uint8 slp_typb); 55 | 56 | // Clean up any state that was modified during suspend. 57 | static void resume_bsp() asm("resume_bsp"); 58 | }; 59 | -------------------------------------------------------------------------------- /include/time.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Time related functions 3 | * 4 | * Copyright (C) 2022 Stefan Hertrampf, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "types.hpp" 19 | 20 | constexpr uint64 ONE_SEC_IN_US{1000u * 1000u}; 21 | 22 | // Convert a given amount of microseconds to TSC clock ticks. 23 | inline uint64 us_as_ticks_in_freq(uint32 freq_khz, uint32 microseconds) 24 | { 25 | return static_cast(freq_khz) * microseconds / 1000; 26 | } 27 | -------------------------------------------------------------------------------- /include/tss.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Task State Segment (TSS) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * Copyright (C) 2018 Thomas Prescher, Cyberus Technology GmbH. 10 | * 11 | * This file is part of the Hedron hypervisor. 12 | * 13 | * Hedron is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU General Public License version 2 as 15 | * published by the Free Software Foundation. 16 | * 17 | * Hedron is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License version 2 for more details. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "compiler.hpp" 26 | #include "selectors.hpp" 27 | #include "types.hpp" 28 | 29 | class Tss 30 | { 31 | public: 32 | uint32 : 32; // 0x0 33 | uint64 sp0 PACKED; // 0x4 34 | uint64 sp1 PACKED; // 0xc 35 | uint64 sp2 PACKED; // 0x14 36 | uint64 ist[8] PACKED; // 0x1c 37 | uint64 : 64 PACKED; 38 | 39 | uint16 trap; // 0x64 40 | uint16 iobm; // 0x66 41 | 42 | static Tss& local(); 43 | static Tss& remote(unsigned id); 44 | 45 | static void setup(); 46 | static void build(); 47 | static void load(); 48 | }; 49 | -------------------------------------------------------------------------------- /include/types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Constant-Width Types 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | typedef unsigned char uint8; 24 | typedef unsigned short uint16; 25 | typedef unsigned int uint32; 26 | typedef unsigned long long uint64; 27 | 28 | typedef signed char int8; 29 | typedef signed short int16; 30 | typedef signed int int32; 31 | typedef signed long long int64; 32 | 33 | typedef unsigned long mword; 34 | typedef unsigned long Paddr; 35 | -------------------------------------------------------------------------------- /include/unique_ptr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A simple smart pointer implementation for unique pointers 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "util.hpp" 21 | 22 | // A simplified unique_ptr implementation. 23 | // 24 | // This class works exactly like std::unique_ptr, but there is no support for 25 | // custom deleters and type conversions are not supported yet. 26 | template class Unique_ptr 27 | { 28 | public: 29 | Unique_ptr(T* ptr_ = nullptr) : ptr(ptr_) {} 30 | Unique_ptr(Unique_ptr&& ref) : ptr(ref.release()) {} 31 | 32 | Unique_ptr(Unique_ptr const& ref) = delete; 33 | 34 | T* operator->() const { return ptr; } 35 | T& operator*() const { return *ptr; } 36 | 37 | Unique_ptr& operator=(Unique_ptr&& ref) 38 | { 39 | reset(ref.release()); 40 | return *this; 41 | } 42 | 43 | Unique_ptr& operator=(Unique_ptr const& ref) = delete; 44 | 45 | ~Unique_ptr() { reset(); } 46 | 47 | T* get() const { return ptr; } 48 | 49 | operator bool() const { return ptr != nullptr; } 50 | 51 | // Release ownership of the object. 52 | T* release() 53 | { 54 | T* old{ptr}; 55 | 56 | ptr = nullptr; 57 | return old; 58 | } 59 | 60 | // Reset the stored pointer to the given pointer. 61 | void reset(T* new_ptr = nullptr) 62 | { 63 | T* released{release()}; 64 | 65 | // Delete should accept nullptr, but the buddy allocator doesn't 66 | // like it and changing it to accept nullptr might mask bugs. 67 | if (released) { 68 | delete released; 69 | } 70 | 71 | ptr = new_ptr; 72 | } 73 | 74 | private: 75 | // The underlying pointer. 76 | T* ptr{nullptr}; 77 | }; 78 | 79 | template inline Unique_ptr make_unique(ARGS&&... args) 80 | { 81 | return {new T(forward(args)...)}; 82 | } 83 | -------------------------------------------------------------------------------- /include/util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Utility Functions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | #include "types.hpp" 23 | 24 | template struct integral_constant { 25 | using value_type = T; 26 | 27 | static constexpr value_type value = v; 28 | constexpr operator value_type() const { return v; } 29 | }; 30 | 31 | using true_type = integral_constant; 32 | using false_type = integral_constant; 33 | 34 | template struct remove_reference { 35 | using type = T; 36 | }; 37 | template struct remove_reference { 38 | using type = T; 39 | }; 40 | template struct remove_reference { 41 | using type = T; 42 | }; 43 | 44 | template struct is_lvalue_reference : false_type { 45 | }; 46 | template struct is_lvalue_reference : true_type { 47 | }; 48 | 49 | template constexpr T&& forward(typename remove_reference::type& arg) 50 | { 51 | return static_cast(arg); 52 | } 53 | 54 | template constexpr T&& forward(typename remove_reference::type&& arg) 55 | { 56 | static_assert(not is_lvalue_reference::value, "Invalid rvalue to lvalue conversion"); 57 | return static_cast(arg); 58 | } 59 | 60 | template typename remove_reference::type&& move(T&& v) 61 | { 62 | return static_cast::type&&>(v); 63 | } 64 | 65 | template struct is_same : false_type { 66 | }; 67 | 68 | template struct is_same : true_type { 69 | }; 70 | 71 | template struct is_void : is_same { 72 | }; 73 | 74 | /// Wrap a member function together with its parameters into a callable. 75 | /// 76 | /// Example: 77 | /// 78 | /// std::for_each(begin, end, mem_fn_closure(&Foo:method)(param1, param2)); 79 | template auto mem_fn_closure(RET T::*method) 80 | { 81 | return [method](auto... args) { return [method, args...](T& object) { (object.*method)(args...); }; }; 82 | } 83 | 84 | #if !__STDC_HOSTED__ 85 | 86 | // Placement new operator 87 | inline void* operator new(size_t, void* p) { return p; } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /include/vlapic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual LAPIC Page 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "memory.hpp" 21 | #include "types.hpp" 22 | 23 | class Vlapic 24 | { 25 | private: 26 | char opaque_data[PAGE_SIZE]; 27 | 28 | public: 29 | static void* operator new(size_t size); 30 | static void operator delete(void* ptr); 31 | }; 32 | -------------------------------------------------------------------------------- /include/vmx_types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Machine Extensions (VMX) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 10 | * 11 | * This file is part of the Hedron hypervisor. 12 | * 13 | * Hedron is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU General Public License version 2 as 15 | * published by the Free Software Foundation. 16 | * 17 | * Hedron is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License version 2 for more details. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "types.hpp" 26 | 27 | union vmx_basic { 28 | uint64 val; 29 | struct { 30 | uint32 revision; 31 | uint32 size : 13, : 3, width : 1, dual : 1, type : 4, insouts : 1, ctrl : 1; 32 | }; 33 | }; 34 | 35 | union vmx_ept_vpid { 36 | uint64 val; 37 | struct { 38 | uint32 : 16, super : 2, : 2, invept : 1, : 11; 39 | uint32 invvpid : 1; 40 | }; 41 | }; 42 | 43 | union vmx_ctrl_pin { 44 | uint64 val; 45 | struct { 46 | uint32 set, clr; 47 | }; 48 | }; 49 | 50 | struct vmx_ctrl_cpu { 51 | union { 52 | uint64 val; 53 | struct { 54 | uint32 set, clr; 55 | }; 56 | }; 57 | uint32 non_passthrough_set{0}; 58 | }; 59 | 60 | union vmx_ctrl_exi { 61 | uint64 val; 62 | struct { 63 | uint32 set, clr; 64 | }; 65 | }; 66 | 67 | union vmx_ctrl_ent { 68 | uint64 val; 69 | struct { 70 | uint32 set, clr; 71 | }; 72 | }; 73 | -------------------------------------------------------------------------------- /include/vpid.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual Processor Identifier (VPID) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "compiler.hpp" 22 | 23 | class Invvpid 24 | { 25 | private: 26 | uint64 vpid; 27 | uint64 addr; 28 | 29 | public: 30 | inline Invvpid(unsigned long v, mword a) : vpid(v), addr(a) {} 31 | }; 32 | 33 | class Vpid 34 | { 35 | public: 36 | enum Type 37 | { 38 | ADDRESS = 0, 39 | CONTEXT_GLOBAL = 1, 40 | CONTEXT_NOGLOBAL = 3 41 | }; 42 | 43 | static inline void flush(Type t, unsigned long vpid, mword addr = 0) 44 | { 45 | Invvpid desc{vpid, addr}; 46 | asm volatile("invvpid %0, %1" : : "m"(desc), "r"(static_cast(t)) : "cc"); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Hedron Documentation 2 | nav: 3 | - Home: index.md 4 | - User Documentation: 5 | - System Call Interface: 6 | - user-documentation/index.md 7 | - user-documentation/data-structures.md 8 | - user-documentation/syscall-binary-interface.md 9 | - user-documentation/syscall-reference.md 10 | - Developer Documentation: 11 | - Implementation Details: implementation.md 12 | - Design Proposals: proposals.md 13 | 14 | theme: 15 | name: material 16 | icon: 17 | repo: fontawesome/brands/gitlab 18 | features: 19 | - navigation.indexes 20 | - navigation.instant 21 | 22 | markdown_extensions: 23 | - toc: 24 | toc_depth: 2 25 | - admonition 26 | - footnotes 27 | - pymdownx.superfences: 28 | custom_fences: 29 | - name: mermaid 30 | class: mermaid 31 | format: !!python/name:pymdownx.superfences.fence_code_format 32 | 33 | plugins: 34 | - search 35 | - tags: 36 | tags_file: index.md 37 | - drawio-exporter: 38 | # Diagrams are cached to speed up site generation. The default path is 39 | # drawio-exporter, relative to the documentation directory. 40 | cache_dir: 'cache/drawio-exporter' 41 | # Drawio executable is managed by nix here 42 | drawio_executable: null 43 | # Additional Draw.io CLI args 44 | drawio_args: [] 45 | format: svg 46 | # Embed format 47 | # * The default is to embed via the tag, only rewriting the 48 | # value of the src attribute. 49 | # * Consider 50 | # to enable interactive elements (like hyperlinks) in SVGs. 51 | embed_format: '{img_open}{img_src}{img_close}' 52 | # Glob pattern for matching source files 53 | sources: '*.drawio' 54 | -------------------------------------------------------------------------------- /nix/build.nix: -------------------------------------------------------------------------------- 1 | { 2 | stdenv, 3 | catch2, 4 | cmake, 5 | nix-gitignore, 6 | python3, 7 | lib, 8 | buildType ? "Debug", 9 | # Specify a kernel heap size in MiB. This overrides the default and 10 | # is advisable for more sophisticated workloads. 11 | heapSizeMiB ? null 12 | }: 13 | 14 | let 15 | gitIgnores = lib.optional (builtins.pathExists ../.gitignore) ../.gitignore; 16 | in 17 | stdenv.mkDerivation { 18 | name = "hedron"; 19 | src = nix-gitignore.gitignoreSourcePure ([".git\nnix\n"] ++ gitIgnores) ./..; 20 | 21 | nativeBuildInputs = [ 22 | cmake 23 | 24 | # For tools/check-elf-segments. 25 | (python3.withPackages(ps: [ ps.pyelftools ])) 26 | ]; 27 | 28 | checkInputs = [ catch2 ]; 29 | 30 | cmakeBuildType = buildType; 31 | cmakeFlags = [ "-DENABLE_ELF_SEGMENT_CHECKS:bool=ON" ] 32 | ++ lib.optional (heapSizeMiB != null) "-DHEAP_SIZE_MB=${toString heapSizeMiB}"; 33 | 34 | hardeningDisable = [ "all" ]; 35 | enableParallelBuilding = true; 36 | doCheck = true; 37 | 38 | postPatch = '' 39 | patchShebangs tools/check-elf-segments 40 | ''; 41 | 42 | meta = { 43 | description = "Hedron hypervisor by Cyberus Technology"; 44 | homepage = "https://github.com/cyberus-technology/hedron"; 45 | license = lib.licenses.gpl2; 46 | platforms = [ "x86_64-linux" ]; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /nix/clang-tidy.nix: -------------------------------------------------------------------------------- 1 | { pkgs, hedron }: 2 | hedron.overrideAttrs ( 3 | old: { 4 | name = "hedron-clang-tidy"; 5 | cmakeFlags = old.cmakeFlags or [] ++ [ 6 | "-DENABLE_CLANG_TIDY=ON" 7 | "-DBUILD_TESTING=ON" 8 | ]; 9 | nativeBuildInputs = old.nativeBuildInputs or [] ++ [ 10 | pkgs.clang-tools 11 | ]; 12 | } 13 | ) 14 | -------------------------------------------------------------------------------- /nix/cmake-modules.nix: -------------------------------------------------------------------------------- 1 | { src, stdenvNoCC }: 2 | stdenvNoCC.mkDerivation { 3 | name = "cmake-modules"; 4 | inherit src; 5 | 6 | patchPhase = '' 7 | # gcovr itself is a bash script that wraps the python script already 8 | sed -i 's/''${Python_EXECUTABLE} ''${GCOVR_PATH}/''${GCOVR_PATH}/' CodeCoverage.cmake 9 | ''; 10 | 11 | installPhase = '' 12 | mkdir $out 13 | cp -r * $out/ 14 | ''; 15 | } 16 | -------------------------------------------------------------------------------- /nix/coverage.nix: -------------------------------------------------------------------------------- 1 | { hedron 2 | , cmake-modules 3 | , gcovr 4 | , python3Packages 5 | }: 6 | hedron.overrideAttrs ( 7 | old: { 8 | name = "hedron-coverage"; 9 | cmakeBuildType = "Debug"; 10 | cmakeFlags = [ 11 | "-DCOVERAGE=true" 12 | "-DCMAKE_MODULE_PATH=${cmake-modules}" 13 | "-DCMAKE_BUILD_TYPE=Debug" 14 | ]; 15 | 16 | checkInputs = old.checkInputs ++ [ gcovr python3Packages.python python3Packages.setuptools ]; 17 | 18 | makeFlags = [ "test_unit_coverage" ]; 19 | installPhase = '' 20 | mkdir -p $out 21 | cp -r test_unit_coverage/* $out/ 22 | ''; 23 | } 24 | ) 25 | -------------------------------------------------------------------------------- /nix/cyberus-overlay.nix: -------------------------------------------------------------------------------- 1 | self: super: 2 | let 3 | # We deliberately do not use the nixpkgs that we are overlaying to 4 | # build Hedron, because this means that the user does not get the 5 | # version we actually tested. 6 | thisPackage = import ./release.nix {}; 7 | 8 | builds = thisPackage.hedron.builds; 9 | in { 10 | hedron = super.pkgs.lib.warn 11 | "Using the hedron attributes directly is deprecated. Use hedron.default instead." 12 | { 13 | inherit (builds) default-release default-debug; 14 | 15 | builds = { 16 | inherit (builds) default-release default-debug; 17 | }; 18 | }; 19 | 20 | default = builds.default-release; 21 | debug = builds.default-debug; 22 | 23 | # As long as we do use our own nixpkgs to build all of the above, 24 | # there is no reason to expose the integration tests, as they 25 | # cannot show any different result than in our local pipeline. 26 | } 27 | -------------------------------------------------------------------------------- /nix/docs.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , drawio-headless 4 | , python3 5 | , python3Packages 6 | }: 7 | stdenv.mkDerivation { 8 | name = "hedron-docs"; 9 | 10 | src = lib.sourceByRegex ../. [ 11 | "mkdocs.yml" 12 | "^docs.*" 13 | ]; 14 | 15 | propagatedBuildInputs = [ drawio-headless ]; 16 | 17 | nativeBuildInputs = [ 18 | python3 19 | ] ++ (with python3Packages; [ 20 | mkdocs 21 | mkdocs-material 22 | mkdocs-drawio-exporter 23 | ]); 24 | 25 | dontConfigure = true; 26 | 27 | buildPhase = '' 28 | mkdocs build 29 | ''; 30 | 31 | installPhase = '' 32 | cp -a site/ $out/ 33 | ''; 34 | } 35 | -------------------------------------------------------------------------------- /nix/integration-test.nix: -------------------------------------------------------------------------------- 1 | { hedron, grub2, mtools, OVMF, xorriso, stdenv, qemuBoot }: 2 | let 3 | grub_image = "grub_image.iso"; 4 | in 5 | stdenv.mkDerivation { 6 | name = "hedron-integration-tests"; 7 | inherit (hedron) src; 8 | 9 | nativeBuildInputs = [ grub2 mtools OVMF xorriso qemuBoot ]; 10 | 11 | postPatch = '' 12 | patchShebangs tools/gen_usb.sh 13 | ''; 14 | 15 | buildPhase = '' 16 | # This takes a while on old Qemus, because of very inefficient Multiboot loading. Should be fixed in Qemu So let's do this only once. 17 | echo "# Testing legacy direct kernel boot." 18 | qemu-boot ${hedron}/share/hedron/hypervisor.elf32 | tee output.log 19 | 20 | tools/gen_usb.sh ${grub_image} ${hedron}/share/hedron/hypervisor.elf32 tools/grub.cfg.tmpl 21 | 22 | # Test whether Hedron deals with many CPUs. The goal is not to crash. The number of CPUs that we expect to see here should be 23 | # equal to NUM_CPU. 24 | qemu-boot ${grub_image} --cpus 255 --expected-cpus 128 --disk-image | tee -a output.log 25 | 26 | # We boot our disk images with different amounts of RAM to exercise relocation. 27 | # If this fails, check whether the hypervisor heap actually fits. 28 | for mem in 768 1024 3192; do 29 | echo "# Testing legacy disk image boot with $mem MiB of memory." 30 | qemu-boot ${grub_image} --memory $mem --disk-image | tee -a output.log 31 | echo "# Testing UEFI disk image boot with $mem MiB of memory." 32 | qemu-boot ${grub_image} --memory $mem --disk-image --uefi --uefi-firmware-path ${OVMF.fd}/FV | tee -a output.log 33 | done 34 | 35 | echo "# Testing done." 36 | ''; 37 | 38 | installPhase = '' 39 | cp output.log $out 40 | ''; 41 | 42 | requiredSystemFeatures = [ 43 | # Running Hedron with many (virtual) CPUs on small machines is not working well. 44 | # 45 | # See #214. 46 | "big-parallel" 47 | 48 | # The tests will be faster when KVM is available. 49 | "kvm" 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /nix/overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: 2 | let 3 | # We deliberately do not use the nixpkgs that we are overlaying to 4 | # build Hedron, because this means that the user does not get the 5 | # version we actually tested. 6 | thisPackage = import ./release.nix { }; 7 | 8 | builds = thisPackage.hedron.builds; 9 | in 10 | { 11 | cyberus = prev.cyberus or { } // { 12 | hedron = { 13 | default = builds.default-release; 14 | debug = builds.default-debug; 15 | 16 | # As long as we do use our own nixpkgs to build all of the above, 17 | # there is no reason to expose the integration tests, as they 18 | # cannot show any different result than in our local pipeline. 19 | 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /nix/qemu-boot.nix: -------------------------------------------------------------------------------- 1 | { stdenv, python3, qemu, netcat }: 2 | 3 | stdenv.mkDerivation { 4 | pname = "boot-qemu"; 5 | version = "0"; 6 | 7 | src = ../test/integration; 8 | 9 | buildInputs = [ ]; 10 | propagatedBuildInputs = [ qemu python3.pkgs.pexpect netcat ]; 11 | 12 | checkInputs = [ python3.pkgs.black ]; 13 | 14 | nativeBuildInputs = [ python3.pkgs.wrapPython ]; 15 | 16 | dontConfigure = true; 17 | dontBuild = true; 18 | doCheck = true; 19 | 20 | checkPhase = '' 21 | black --check --diff qemu-boot 22 | ''; 23 | 24 | installPhase = '' 25 | mkdir -p $out/bin 26 | install -m 755 qemu-boot $out/bin 27 | ''; 28 | 29 | postFixup = '' 30 | wrapPythonPrograms 31 | ''; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /nix/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake-modules": { 3 | "branch": "master", 4 | "description": "Additional CMake functionality. Most of the modules are from Ryan Pavlik (https://github.com/rpavlik/cmake-modules)", 5 | "homepage": "", 6 | "owner": "bilke", 7 | "repo": "cmake-modules", 8 | "rev": "877bab9dd1b17468c5d939cacaa2ad7ba99d1977", 9 | "sha256": "14nbsmlhsj6c8504hdlzkkqwn07ac97ypvzwh4gyr5i2ma8bzwwf", 10 | "type": "tarball", 11 | "url": "https://github.com/bilke/cmake-modules/archive/877bab9dd1b17468c5d939cacaa2ad7ba99d1977.tar.gz", 12 | "url_template": "https://github.com///archive/.tar.gz" 13 | }, 14 | "nixpkgs": { 15 | "branch": "nixos-23.05", 16 | "description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to", 17 | "homepage": "https://github.com/NixOS/nixpkgs", 18 | "owner": "NixOS", 19 | "repo": "nixpkgs", 20 | "rev": "d3bb401dcfc5a46ce51cdfb5762e70cc75d082d2", 21 | "sha256": "0hvln80nwzmndqqhqh1nsk89ypxdigswcv6krsv21vqg8vzm1xd0", 22 | "type": "tarball", 23 | "url": "https://github.com/NixOS/nixpkgs/archive/d3bb401dcfc5a46ce51cdfb5762e70cc75d082d2.tar.gz", 24 | "url_template": "https://github.com///archive/.tar.gz" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nix/stylecheck.nix: -------------------------------------------------------------------------------- 1 | { runCommandNoCC 2 | , clang-tools 3 | , lib 4 | , nix-gitignore 5 | }: 6 | 7 | runCommandNoCC "hedron-style-check" 8 | { 9 | nativeBuildInputs = [ clang-tools ]; 10 | src = lib.cleanSourceWith { 11 | name = "hedron-source"; 12 | filter = nix-gitignore.gitignoreFilterPure (_: _: true) [ ".git" "nix" ../.gitignore ] ./..; 13 | src = ./..; 14 | }; 15 | } '' 16 | cpp_regex='.*\.\(cpp\|hpp\)$' 17 | files=$(find "$src" -regex "$cpp_regex") 18 | 19 | # if clang-format finds style violations, it exits immediately. There is no 20 | # need to check the exit code of clang-format 21 | clang-format --dry-run --Werror --ferror-limit 1 $files 22 | 23 | echo "Style is good." 24 | touch $out 25 | '' 26 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ], 6 | "nix": { 7 | "enabled": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { sources ? import ./nix/sources.nix 2 | , nixpkgs ? sources.nixpkgs 3 | , pkgs ? import nixpkgs { }}: 4 | 5 | let 6 | release = import ./nix/release.nix { inherit sources pkgs; }; 7 | in 8 | pkgs.mkShell { 9 | 10 | # A compiler invoked from a nix-shell is a wrapper which may add unexpected 11 | # compile flags to harden the build. One example is `-fPIC` which causes the 12 | # release build to fail with: 13 | # 14 | # lto1: error: code model kernel does not support PIC mode 15 | # 16 | # These can be debugged via `NIX_DEBUG=1 `. 17 | hardeningDisable = [ "all" ]; 18 | 19 | inputsFrom = [ 20 | release.hedron.builds.default-debug 21 | release.hedron.stylecheck 22 | release.hedron.docs 23 | ]; 24 | 25 | buildInputs = [ 26 | # To manipulate Nix dependencies. 27 | pkgs.niv 28 | 29 | # To modify cmake build variables with ccmake. 30 | pkgs.cmakeCurses 31 | 32 | # Prevent that CLion IDE complains about a missing dependency. 33 | pkgs.catch2 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/acpi_fadt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "acpi_fadt.hpp" 20 | #include "acpi.hpp" 21 | #include "io.hpp" 22 | #include "x86.hpp" 23 | 24 | void Acpi_table_fadt::init(const Acpi_table_fadt* fadt) 25 | { 26 | Acpi::feature = fadt->flags; 27 | 28 | Acpi::pm1a_sts.init(fadt->pm1a_sts()); 29 | Acpi::pm1a_ena.init(fadt->pm1a_ena()); 30 | Acpi::pm1b_sts.init(fadt->pm1b_sts()); 31 | Acpi::pm1b_ena.init(fadt->pm1b_ena()); 32 | 33 | Acpi::pm1a_cnt.init(fadt->pm1a_cnt()); 34 | Acpi::pm1b_cnt.init(fadt->pm1b_cnt()); 35 | Acpi::pm2_cnt.init(fadt->pm2_cnt()); 36 | 37 | Acpi::pm_tmr.init(fadt->pm_tmr()); 38 | 39 | Acpi::gpe0_sts.init(fadt->gpe0_sts()); 40 | Acpi::gpe0_ena.init(fadt->gpe0_ena()); 41 | Acpi::gpe1_sts.init(fadt->gpe1_sts()); 42 | Acpi::gpe1_ena.init(fadt->gpe1_ena()); 43 | 44 | Acpi::facs = fadt->facs(); 45 | 46 | if (fadt->smi_cmd && fadt->acpi_enable) { 47 | Io::out(fadt->smi_cmd, fadt->acpi_enable); 48 | while (!(Acpi::read(Acpi::PM1_CNT) & Acpi::PM1_CNT_SCI_EN)) 49 | relax(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/acpi_madt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #include "acpi_madt.hpp" 23 | #include "acpi.hpp" 24 | #include "config.hpp" 25 | #include "cpu.hpp" 26 | #include "io.hpp" 27 | #include "stdio.hpp" 28 | 29 | void Acpi_table_madt::parse() const { parse_entry(Acpi_apic::LAPIC, &parse_lapic); } 30 | 31 | void Acpi_table_madt::parse_entry(Acpi_apic::Type type, void (*handler)(Acpi_apic const*)) const 32 | { 33 | for (Acpi_apic const* ptr = apic; 34 | ptr < reinterpret_cast(reinterpret_cast(this) + length); 35 | ptr = reinterpret_cast(reinterpret_cast(ptr) + ptr->length)) 36 | if (ptr->type == type) 37 | (*handler)(ptr); 38 | } 39 | 40 | void Acpi_table_madt::parse_lapic(Acpi_apic const* ptr) 41 | { 42 | Acpi_lapic const* p = static_cast(ptr); 43 | 44 | if (p->flags & 1 && Cpu::online < NUM_CPU) { 45 | Cpu::acpi_id[Cpu::online] = p->acpi_id; 46 | Cpu::apic_id[Cpu::online++] = p->apic_id; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/acpi_mcfg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "acpi_mcfg.hpp" 22 | #include "pci.hpp" 23 | 24 | void Acpi_table_mcfg::parse() const 25 | { 26 | for (Acpi_mcfg const* x = mcfg; 27 | x + 1 <= reinterpret_cast(reinterpret_cast(this) + length); x++) 28 | if (!x->seg) { 29 | Pci::cfg_base = static_cast(x->addr); 30 | Pci::cfg_size = ((x->bus_e - x->bus_s + 1) << 8) * PAGE_SIZE; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/acpi_rsdp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "acpi_rsdp.hpp" 20 | #include "acpi.hpp" 21 | #include "acpi_table.hpp" 22 | #include "algorithm.hpp" 23 | #include "hpt.hpp" 24 | 25 | bool Acpi_rsdp::good_signature() const { return signature[0] == SIG("RSD ") && signature[1] == SIG("PTR "); } 26 | 27 | bool Acpi_rsdp::good_checksum(size_t len) const { return Acpi_table::do_checksum(this, len) == 0; } 28 | 29 | Acpi_rsdp* Acpi_rsdp::find(mword start, unsigned len) 30 | { 31 | for (mword addr = start; addr < start + len; addr += 16) { 32 | Acpi_rsdp* rsdp = reinterpret_cast(addr); 33 | if (rsdp->good_signature() && rsdp->good_checksum()) 34 | return rsdp; 35 | } 36 | 37 | return nullptr; 38 | } 39 | 40 | void Acpi_rsdp::parse(mword rdsp_addr) 41 | { 42 | Acpi_rsdp* rsdp; 43 | 44 | if (rdsp_addr) { 45 | rsdp = reinterpret_cast(rdsp_addr); 46 | if (not(rsdp->good_signature() and rsdp->good_checksum())) 47 | return; 48 | } else { 49 | mword map = reinterpret_cast(Hpt::remap(rdsp_addr)); 50 | 51 | if (!(rsdp = Acpi_rsdp::find(map + (*reinterpret_cast(map + 0x40e) << 4), 0x400)) && 52 | !(rsdp = Acpi_rsdp::find(map + 0xe0000, 0x20000))) 53 | return; 54 | } 55 | 56 | Acpi::rsdt = rsdp->rsdt_addr; 57 | 58 | if (rsdp->revision > 1 && rsdp->good_checksum(rsdp->length)) 59 | Acpi::xsdt = static_cast(rsdp->xsdt_addr); 60 | } 61 | -------------------------------------------------------------------------------- /src/acpi_rsdt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "acpi_rsdt.hpp" 22 | #include "acpi.hpp" 23 | #include "hpt.hpp" 24 | 25 | struct Acpi_table_rsdt::table_map const Acpi_table_rsdt::map[] = { 26 | {SIG("APIC"), &Acpi::madt}, 27 | {SIG("DMAR"), &Acpi::dmar}, 28 | {SIG("FACP"), &Acpi::fadt}, 29 | {SIG("MCFG"), &Acpi::mcfg}, 30 | }; 31 | 32 | void Acpi_table_rsdt::parse(Paddr addr, size_t size) const 33 | { 34 | if (!good_checksum(addr)) 35 | return; 36 | 37 | unsigned long count = entries(size); 38 | 39 | Paddr table[count]; 40 | for (unsigned i = 0; i < count; i++) 41 | table[i] = static_cast(size == sizeof(xsdt_) ? xsdt(i) : rsdt(i)); 42 | 43 | for (unsigned i = 0; i < count; i++) { 44 | 45 | Acpi_table* acpi = static_cast(Hpt::remap(table[i])); 46 | 47 | if (acpi->good_checksum(table[i])) 48 | for (unsigned j = 0; j < sizeof map / sizeof *map; j++) 49 | if (acpi->signature == map[j].sig) 50 | *map[j].ptr = table[i]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/acpi_table.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Advanced Configuration and Power Interface (ACPI) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "acpi_table.hpp" 20 | #include "algorithm.hpp" 21 | #include "stdio.hpp" 22 | 23 | uint8 Acpi_table::do_checksum(const void* table, size_t len) 24 | { 25 | return static_cast( 26 | accumulate(static_cast(table), static_cast(table) + len, 0)); 27 | } 28 | 29 | bool Acpi_table::good_checksum(Paddr addr) const 30 | { 31 | bool valid{do_checksum() == 0}; 32 | 33 | trace(TRACE_ACPI, "%.4s:%#010llx REV:%2d TBL:%8.8s OEM:%6.6s LEN:%5u (%s)", 34 | reinterpret_cast(&signature), static_cast(addr), revision, oem_table_id, 35 | oem_id, length, valid ? "ok" : "bad"); 36 | 37 | return valid; 38 | } 39 | -------------------------------------------------------------------------------- /src/cmdline.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Command Line Parser 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2014 Udo Steinberg, FireEye, Inc. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #include "cmdline.hpp" 23 | #include "string.hpp" 24 | 25 | struct Cmdline::param_map const Cmdline::map[] = { 26 | {"serial", &Cmdline::serial}, {"nodl", &Cmdline::nodl}, {"nopcid", &Cmdline::nopcid}, 27 | {"novga", &Cmdline::novga}, {"novpid", &Cmdline::novpid}, 28 | }; 29 | 30 | char const* Cmdline::get_arg(char const** line, unsigned& len) 31 | { 32 | len = 0; 33 | 34 | for (; **line == ' '; ++*line) 35 | ; 36 | 37 | if (!**line) 38 | return nullptr; 39 | 40 | char const* arg = *line; 41 | 42 | for (; **line != ' '; ++*line) { 43 | if (!**line) 44 | return arg; 45 | len++; 46 | } 47 | 48 | return arg; 49 | } 50 | 51 | void Cmdline::init(char const* line) 52 | { 53 | char const* arg; 54 | unsigned len; 55 | 56 | while ((arg = get_arg(&line, len))) 57 | for (size_t i = 0; i < sizeof map / sizeof *map; i++) { 58 | if (strnmatch(map[i].arg, arg, len)) 59 | *map[i].ptr = true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/console_serial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Console 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "console_serial.hpp" 22 | #include "cmdline.hpp" 23 | #include "hpt.hpp" 24 | #include "initprio.hpp" 25 | #include "x86.hpp" 26 | 27 | Console_serial::Console_serial() 28 | { 29 | if (!Cmdline::serial) 30 | return; 31 | 32 | char* mem = static_cast(Hpt::remap(0)); 33 | if (!(base = *reinterpret_cast(mem + 0x400)) && 34 | !(base = *reinterpret_cast(mem + 0x402))) 35 | base = 0x3f8; 36 | 37 | out(LCR, 0x80); 38 | out(DLL, (freq / 115200) & 0xff); 39 | out(DLM, (freq / 115200) >> 8); 40 | out(LCR, 3); 41 | out(IER, 0); 42 | out(FCR, 7); 43 | out(MCR, 3); 44 | 45 | enable(); 46 | } 47 | 48 | void Console_serial::putc(int c) 49 | { 50 | if (c == '\n') 51 | putc('\r'); 52 | 53 | while (EXPECT_FALSE(!(in(LSR)&0x20))) 54 | relax(); 55 | 56 | out(THR, c); 57 | } 58 | -------------------------------------------------------------------------------- /src/console_vga.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * VGA Console 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "console_vga.hpp" 22 | #include "cmdline.hpp" 23 | #include "pd.hpp" 24 | 25 | Console_vga::Console_vga() : num(25), row(0), col(0) 26 | { 27 | if (Cmdline::novga) 28 | return; 29 | 30 | Pd::kern->claim_mmio_page(HV_GLOBAL_FBUF, 0xb9000, false); 31 | 32 | set_page(1); 33 | 34 | enable(); 35 | } 36 | 37 | void Console_vga::putc(int c) 38 | { 39 | if (EXPECT_FALSE(c == '\f')) { 40 | clear_all(); 41 | row = col = 0; 42 | return; 43 | } 44 | 45 | if (EXPECT_TRUE(c != '\n')) { 46 | put(row, col, COLOR_LIGHT_WHITE, c); 47 | if (EXPECT_TRUE(++col < 80)) 48 | return; 49 | } 50 | 51 | col = 0; 52 | 53 | if (EXPECT_TRUE(++row == num)) 54 | clear_row(--row); 55 | } 56 | -------------------------------------------------------------------------------- /src/ec_vmx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Execution Context 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "ec.hpp" 22 | #include "lapic.hpp" 23 | #include "vcpu.hpp" 24 | #include "vmx.hpp" 25 | #include "vmx_preemption_timer.hpp" 26 | 27 | void Ec::handle_vmx() 28 | { 29 | assert_slow(get_ds() == 0ul); 30 | assert_slow(get_es() == 0ul); 31 | assert_slow(get_fs() == 0ul); 32 | 33 | // The VM exit has re-set the TR segment limit to 0x67. This breaks the 34 | // IO permission bitmap. Restore the correct value. 35 | Gdt::unbusy_tss(); 36 | Tss::load(); 37 | 38 | Cpu::setup_msrs(); 39 | 40 | // A VM exit occured. We pass the control flow to the vCPU object and let it handle the exit. 41 | assert(current()->vcpu != nullptr); 42 | current()->vcpu->handle_vmx(); 43 | } 44 | 45 | Vcpu_acquire_result Ec::try_acquire_vcpu(Vcpu* vcpu) 46 | { 47 | assert(Ec::current()->vcpu == nullptr); 48 | 49 | auto result{vcpu->try_acquire()}; 50 | if (result.is_ok()) { 51 | Ec::current()->vcpu.reset(vcpu); 52 | } 53 | return result; 54 | } 55 | 56 | void Ec::release_vcpu() 57 | { 58 | assert(Ec::current()->vcpu != nullptr); 59 | 60 | Ec::current()->vcpu->release(); // Release the ownership of the vCPU. 61 | Ec::current()->vcpu.release(); // Release the pointer to the vCPU. 62 | } 63 | 64 | void Ec::run_vcpu(Mtd mtd) 65 | { 66 | assert(Ec::current()->vcpu != nullptr); 67 | 68 | Ec::current()->vcpu->mtd(mtd); 69 | resume_vcpu(); 70 | } 71 | 72 | void Ec::resume_vcpu() 73 | { 74 | assert(Ec::current()->vcpu != nullptr); 75 | 76 | handle_hazards(resume_vcpu); 77 | 78 | Ec::current()->vcpu->run(); 79 | } 80 | -------------------------------------------------------------------------------- /src/ept.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Intel VT Extended page table (EPT) modification 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "ept.hpp" 19 | #include "hpt.hpp" 20 | #include "mdb.hpp" 21 | 22 | Ept::level_t Ept::supported_leaf_levels{1}; 23 | 24 | static Ept::pte_t attr_from_hpt(mword a) 25 | { 26 | auto const none{static_cast(0)}; 27 | Ept::pte_t const mt{((a >> Hpt::PTE_MT_SHIFT) & Hpt::MT_MASK) << Ept::PTE_MT_SHIFT}; 28 | 29 | if (a & Hpt::PTE_P) { 30 | // Only user accessible and delegatable mappings should ever end up in the 31 | // EPT. 32 | assert((a & Hpt::PTE_U) != 0); 33 | assert((a & Hpt::PTE_NODELEG) == 0); 34 | 35 | return mt | Ept::PTE_R | (a & Hpt::PTE_W ? Ept::PTE_W : none) | (a & Hpt::PTE_NX ? none : Ept::PTE_X); 36 | } 37 | 38 | return none; 39 | } 40 | 41 | Ept::Mapping Ept::convert_mapping(Hpt::Mapping const& hpt_mapping) 42 | { 43 | return {hpt_mapping.vaddr, hpt_mapping.paddr, attr_from_hpt(hpt_mapping.attr), hpt_mapping.order}; 44 | } 45 | 46 | void Ept::set_supported_leaf_levels(Ept::level_t level) 47 | { 48 | assert(level > 0); 49 | supported_leaf_levels = level; 50 | } 51 | -------------------------------------------------------------------------------- /src/gdt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Global Descriptor Table (GDT) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "gdt.hpp" 22 | #include "cpu.hpp" 23 | #include "cpulocal.hpp" 24 | #include "memory.hpp" 25 | #include "tss.hpp" 26 | 27 | Gdt::Gdt_array Gdt::global_gdt; 28 | 29 | Gdt& Gdt::gdt(uint32 sel) { return global_gdt[sel >> 3]; } 30 | 31 | void Gdt::build() 32 | { 33 | gdt(SEL_KERN_CODE).set32(CODE_XRA, PAGES, BIT_16, true, 0, 0, ~0ul); 34 | gdt(SEL_KERN_DATA).set32(DATA_RWA, PAGES, BIT_16, true, 0, 0, ~0ul); 35 | 36 | gdt(SEL_USER_CODE).set32(CODE_XRA, PAGES, BIT_16, true, 3, 0, ~0ul); 37 | gdt(SEL_USER_DATA).set32(DATA_RWA, PAGES, BIT_16, true, 3, 0, ~0ul); 38 | gdt(SEL_USER_CODE_L).set32(CODE_XRA, PAGES, BIT_16, true, 3, 0, ~0ul); 39 | 40 | for (unsigned cpu = 0; cpu < NUM_CPU; cpu++) { 41 | mword const tss_addr{reinterpret_cast(&Tss::remote(cpu))}; 42 | 43 | gdt(remote_tss_selector(cpu)) 44 | .set64(SYS_TSS, BYTES, BIT_16, false, 0, tss_addr, SPC_LOCAL_IOP_E - tss_addr); 45 | } 46 | } 47 | 48 | uint16 Gdt::remote_tss_selector(unsigned cpu) 49 | { 50 | return static_cast(SEL_TSS_CPU0 + cpu * TSS_DESC_SIZE); 51 | } 52 | 53 | uint16 Gdt::local_tss_selector() { return remote_tss_selector(Cpu::id()); } 54 | 55 | void Gdt::unbusy_tss() { gdt(local_tss_selector()).val[1] &= ~0x200; } 56 | -------------------------------------------------------------------------------- /src/idt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Interrupt Descriptor Table (IDT) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "idt.hpp" 20 | #include "assert.hpp" 21 | #include "extern.hpp" 22 | #include "idt_handlers.hpp" 23 | #include "selectors.hpp" 24 | 25 | ALIGNED(8) Idt Idt::idt[NUM_INT_VECTORS]; 26 | 27 | void Idt::set(Idt::Type type, unsigned dpl, unsigned selector, mword offset, unsigned ist) 28 | { 29 | val[0] = static_cast(selector << 16 | (offset & 0xffff)); 30 | val[1] = static_cast((offset & 0xffff0000) | 1u << 15 | dpl << 13 | type | ist); 31 | val[2] = static_cast(offset >> 32); 32 | val[3] = 0; 33 | } 34 | 35 | void Idt::build() 36 | { 37 | for (unsigned vector = 0; vector < NUM_INT_VECTORS; vector++) { 38 | const mword idt_mode{handlers[vector] & IDT_MODE_MASK}; 39 | const mword handler{handlers[vector] & ~IDT_MODE_MASK}; 40 | 41 | unsigned dpl; 42 | unsigned ist; 43 | 44 | switch (idt_mode) { 45 | case IDT_MODE_DPL0: 46 | dpl = 0; 47 | ist = 0; 48 | break; 49 | case IDT_MODE_DPL3: 50 | dpl = 3; 51 | ist = 0; 52 | break; 53 | case IDT_MODE_DPL0_ALTSTACK: 54 | dpl = 0; 55 | ist = 1; 56 | break; 57 | default: 58 | // We messed up the handlers table if we got here. 59 | assert(false); 60 | } 61 | 62 | idt[vector].set(SYS_INTR_GATE, dpl, SEL_KERN_CODE, handler, ist); 63 | } 64 | } 65 | 66 | void Idt::load() 67 | { 68 | Pseudo_descriptor desc{sizeof(idt) - 1, reinterpret_cast(idt)}; 69 | asm volatile("lidt %0" : : "m"(desc)); 70 | } 71 | -------------------------------------------------------------------------------- /src/mca.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Machine-Check Architecture (MCA) 3 | * 4 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "mca.hpp" 19 | #include "compiler.hpp" 20 | #include "cpu.hpp" 21 | #include "msr.hpp" 22 | #include "stdio.hpp" 23 | #include "x86.hpp" 24 | 25 | void Mca::init(Cpu_info const& cpu_info) 26 | { 27 | if (EXPECT_FALSE(!Cpu::feature(Cpu::FEAT_MCE))) 28 | return; 29 | 30 | set_cr4(get_cr4() | Cpu::CR4_MCE); 31 | 32 | if (EXPECT_FALSE(!Cpu::feature(Cpu::FEAT_MCA))) 33 | return; 34 | 35 | mword cap = Msr::read(Msr::IA32_MCG_CAP); 36 | 37 | Msr::write(Msr::IA32_MCG_STATUS, 0); 38 | 39 | if (cap & 0x100) 40 | Msr::write(Msr::IA32_MCG_CTL, ~0ULL); 41 | 42 | Cpulocal::get().mca_banks = cap & 0xff; 43 | 44 | for (unsigned i = 45 | (cpu_info.vendor == Cpu_vendor::INTEL and cpu_info.family == 6 and cpu_info.model < 0x1a); 46 | i < banks(); i++) { 47 | Msr::write(Msr::Register(4 * i + Msr::IA32_MCI_CTL), ~0ULL); 48 | Msr::write(Msr::Register(4 * i + Msr::IA32_MCI_STATUS), 0); 49 | } 50 | } 51 | 52 | void Mca::vector() 53 | { 54 | uint64 sts; 55 | 56 | for (unsigned i = 0; i < banks(); i++) 57 | if ((sts = Msr::read(Msr::Register(4 * i + Msr::IA32_MCI_STATUS))) & 1ULL << 63) 58 | trace(TRACE_ERROR, "Machine Check B%u: %#018llx", i, sts); 59 | } 60 | -------------------------------------------------------------------------------- /src/mdb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Mapping Database 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "mdb.hpp" 20 | #include "lock_guard.hpp" 21 | 22 | INIT_PRIORITY(PRIO_SLAB) 23 | Slab_cache Mdb::cache(sizeof(Mdb), 16); 24 | 25 | Spinlock Mdb::lock; 26 | 27 | bool Mdb::insert_node(Mdb* p, mword a) 28 | { 29 | Lock_guard guard(lock); 30 | 31 | if (!p->alive()) 32 | return false; 33 | 34 | if (!(node_attr = p->node_attr & a)) 35 | return false; 36 | 37 | prev = prnt = p; 38 | next = p->next; 39 | dpth = static_cast(p->dpth + 1); 40 | p->next = p->next->prev = this; 41 | 42 | return true; 43 | } 44 | 45 | void Mdb::demote_node(mword a) 46 | { 47 | Lock_guard guard(lock); 48 | 49 | node_attr &= ~a; 50 | } 51 | 52 | bool Mdb::remove_node() 53 | { 54 | if (node_attr) 55 | return false; 56 | 57 | Lock_guard guard(lock); 58 | 59 | if (!alive()) 60 | return false; 61 | 62 | if (next->dpth > dpth) 63 | return false; 64 | 65 | next->prev = prev; 66 | prev->next = next; 67 | 68 | return true; 69 | } 70 | -------------------------------------------------------------------------------- /src/memory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual-Memory Layout 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "memory.hpp" 22 | #include "types.hpp" 23 | 24 | mword hwdev_addr = HV_GLOBAL_FBUF; 25 | -------------------------------------------------------------------------------- /src/mtrr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory Type Range Registers (MTRR) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #include "mtrr.hpp" 23 | #include "memory.hpp" 24 | #include "msr.hpp" 25 | #include "nodestruct.hpp" 26 | #include "stdio.hpp" 27 | 28 | static No_destruct global_mtrr_state; 29 | 30 | Mtrr_state& Mtrr_state::get() { return *&global_mtrr_state; } 31 | -------------------------------------------------------------------------------- /src/panic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Panic handling 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "panic.hpp" 19 | 20 | #include "console.hpp" 21 | #include "x86.hpp" 22 | 23 | #include 24 | 25 | void panic(char const* format, ...) 26 | { 27 | va_list ap; 28 | 29 | va_start(ap, format); 30 | 31 | Console::print("PANIC: Hedron encountered an unrecoverable error near RIP %p:", 32 | __builtin_return_address(0)); 33 | Console::vprint(format, ap); 34 | shutdown(); 35 | 36 | va_end(ap); 37 | } 38 | -------------------------------------------------------------------------------- /src/pt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Portal 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "pt.hpp" 22 | #include "ec.hpp" 23 | #include "stdio.hpp" 24 | 25 | INIT_PRIORITY(PRIO_SLAB) 26 | Slab_cache Pt::cache(sizeof(Pt), 32); 27 | 28 | Pt::Pt(Pd* own, mword sel, Ec* e, Mtd m, mword addr) 29 | : Typed_kobject(static_cast(own), sel, PERM_CTRL | PERM_CALL, free), ec(e), mtd(m), ip(addr), 30 | id(0) 31 | { 32 | trace(TRACE_SYSCALL, "PT:%p created (EC:%p IP:%#lx)", this, e, ip); 33 | } 34 | -------------------------------------------------------------------------------- /src/rcu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Read-Copy Update (RCU) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "rcu.hpp" 22 | #include "atomic.hpp" 23 | #include "barrier.hpp" 24 | #include "cpu.hpp" 25 | #include "hazards.hpp" 26 | #include "hip.hpp" 27 | #include "initprio.hpp" 28 | #include "lapic.hpp" 29 | #include "stdio.hpp" 30 | 31 | mword Rcu::state = RCU_CMP; 32 | mword Rcu::count; 33 | 34 | void Rcu::invoke_batch() 35 | { 36 | for (Rcu_elem *e = done().head, *n = nullptr; n != done().head; e = n) { 37 | n = e->next; 38 | e->next = nullptr; 39 | (e->func)(e); 40 | } 41 | 42 | done().clear(); 43 | } 44 | 45 | void Rcu::start_batch(State s) 46 | { 47 | mword v, m = RCU_CMP | RCU_PND; 48 | 49 | do 50 | if ((v = state) >> 2 != l_batch()) 51 | return; 52 | while (!(v & s) && !Atomic::cmp_swap(state, v, v | s)); 53 | 54 | if ((v ^ ~s) & m) 55 | return; 56 | 57 | count = Cpu::online; 58 | 59 | barrier(); 60 | 61 | state++; 62 | } 63 | 64 | void Rcu::quiet() 65 | { 66 | if (Atomic::sub(count, 1UL) == 0) 67 | start_batch(RCU_CMP); 68 | } 69 | 70 | void Rcu::update() 71 | { 72 | if (l_batch() != batch()) { 73 | l_batch() = batch(); 74 | Atomic::set_mask(Cpu::hazard(), HZD_RCU); 75 | } 76 | 77 | if (!curr().empty() && complete(c_batch())) 78 | done().append(&curr()); 79 | 80 | if (curr().empty() && !next().empty()) { 81 | curr().append(&next()); 82 | 83 | c_batch() = l_batch() + 1; 84 | 85 | start_batch(RCU_PND); 86 | } 87 | 88 | if (!curr().empty() && !next().empty() && (next().count > 2000 || curr().count > 2000)) 89 | for (unsigned cpu = 0; cpu < NUM_CPU; cpu++) { 90 | 91 | if (!Hip::cpu_online(cpu) || Cpu::id() == cpu) 92 | continue; 93 | 94 | Atomic::set_mask(Cpu::hazard(cpu), HZD_IDL); 95 | Lapic::send_nmi(cpu); 96 | } 97 | 98 | if (!done().empty()) 99 | invoke_batch(); 100 | } 101 | -------------------------------------------------------------------------------- /src/sm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Semaphore 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "sm.hpp" 22 | #include "stdio.hpp" 23 | 24 | INIT_PRIORITY(PRIO_SLAB) 25 | Slab_cache Sm::cache(sizeof(Sm), 32); 26 | 27 | Sm::Sm(Pd* own, mword sel, mword cnt) 28 | : Typed_kobject(static_cast(own), sel, Sm::PERM_ALL, free), counter(cnt) 29 | { 30 | trace(TRACE_SYSCALL, "SM:%p created (CNT:%lu)", this, cnt); 31 | } 32 | -------------------------------------------------------------------------------- /src/space.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "space.hpp" 22 | #include "lock_guard.hpp" 23 | #include "math.hpp" 24 | #include "mdb.hpp" 25 | 26 | Mdb* Space::tree_lookup(mword idx, bool next) 27 | { 28 | Lock_guard guard(lock); 29 | return Mdb::lookup(tree, idx, next); 30 | } 31 | 32 | bool Space::tree_insert(Mdb* node) 33 | { 34 | Lock_guard guard(node->space->lock); 35 | return Mdb::insert(&node->space->tree, node); 36 | } 37 | 38 | bool Space::tree_remove(Mdb* node) 39 | { 40 | Lock_guard guard(node->space->lock); 41 | return Mdb::remove(&node->space->tree, node); 42 | } 43 | 44 | void Space::addreg(mword addr, size_t size, mword attr, mword type) 45 | { 46 | Lock_guard guard(lock); 47 | 48 | for (mword o; size; size -= 1UL << o, addr += 1UL << o) 49 | Mdb::insert(&tree, new Mdb(nullptr, addr, addr, (o = max_order(addr, size)), attr, type)); 50 | } 51 | -------------------------------------------------------------------------------- /src/space_pio.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Port I/O Space 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * 9 | * This file is part of the Hedron hypervisor. 10 | * 11 | * Hedron is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 as 13 | * published by the Free Software Foundation. 14 | * 15 | * Hedron is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License version 2 for more details. 19 | */ 20 | 21 | #include "assert.hpp" 22 | #include "lock_guard.hpp" 23 | #include "pd.hpp" 24 | 25 | Space_pio::Space_pio(Space_mem* mem) 26 | { 27 | assert(mem); 28 | 29 | hbmp = Buddy::ptr_to_phys(Buddy::allocator.alloc(1, Buddy::FILL_1)); 30 | gbmp = Buddy::ptr_to_phys(Buddy::allocator.alloc(1, Buddy::FILL_1)); 31 | 32 | // This mapping of the IO Permission Bitmap is only used by the CPU to do access control. Map it 33 | // read-only. 34 | mem->insert(SPC_LOCAL_IOP, 1, Hpt::PTE_NX | Hpt::PTE_A | Hpt::PTE_P, hbmp); 35 | } 36 | 37 | Space_pio::~Space_pio() 38 | { 39 | Buddy::allocator.free(reinterpret_cast(Buddy::phys_to_ptr(gbmp))); 40 | Buddy::allocator.free(reinterpret_cast(Buddy::phys_to_ptr(hbmp))); 41 | } 42 | 43 | Paddr Space_pio::walk(bool host, mword idx) 44 | { 45 | return (host ? hbmp : gbmp) | (idx_to_virt(idx) & (2 * PAGE_SIZE - 1)); 46 | } 47 | 48 | void Space_pio::update(bool host, mword idx, mword attr) 49 | { 50 | mword* m = static_cast(Buddy::phys_to_ptr(walk(host, idx))); 51 | 52 | if (attr) 53 | Atomic::clr_mask(*m, idx_to_mask(idx)); 54 | else 55 | Atomic::set_mask(*m, idx_to_mask(idx)); 56 | } 57 | 58 | Tlb_cleanup Space_pio::update(Mdb* mdb, mword r) 59 | { 60 | assert(this == mdb->space && this != &Pd::kern); 61 | 62 | Lock_guard guard(mdb->node_lock); 63 | 64 | for (unsigned long i = 0; i < (1UL << mdb->node_order); i++) { 65 | if (mdb->node_sub & SUBSPACE_HOST) { 66 | update(true, mdb->node_base + i, mdb->node_attr & ~r); 67 | } 68 | 69 | if (mdb->node_sub & SUBSPACE_GUEST) { 70 | update(false, mdb->node_base + i, mdb->node_attr & ~r); 71 | } 72 | } 73 | 74 | return {}; 75 | } 76 | -------------------------------------------------------------------------------- /src/stdio.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Standard I/O 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "stdio.hpp" 19 | #include "cpu.hpp" 20 | #include "cpulocal.hpp" 21 | 22 | // This trivial function does not live in the header to avoid pulling in many headers from trace.hpp. 23 | int trace_id() { return Cpulocal::is_initialized() ? Cpu::id() : -1; } 24 | -------------------------------------------------------------------------------- /src/string.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * String Functions 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * This file is part of the Hedron hypervisor. 8 | * 9 | * Hedron is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2 as 11 | * published by the Free Software Foundation. 12 | * 13 | * Hedron is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License version 2 for more details. 17 | */ 18 | 19 | #include "string.hpp" 20 | #include "string_impl.hpp" 21 | 22 | // USED attributes are important to prevent linker failures when link-time 23 | // optimization is enabled. 24 | 25 | USED void* memcpy(void* d, void const* s, size_t n) { return impl_memcpy(d, s, n); } 26 | USED void* memmove(void* d, void const* s, size_t n) { return impl_memmove(d, s, n); } 27 | 28 | USED void* memset(void* d, int c, size_t n) { return impl_memset(d, c, n); } 29 | 30 | bool strnmatch(char const* s1, char const* s2, size_t n) { return impl_strnmatch(s1, s2, n); } 31 | -------------------------------------------------------------------------------- /src/tss.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Task State Segment (TSS) 3 | * 4 | * Copyright (C) 2009-2011 Udo Steinberg 5 | * Economic rights: Technische Universitaet Dresden (Germany) 6 | * 7 | * Copyright (C) 2012 Udo Steinberg, Intel Corporation. 8 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 9 | * 10 | * This file is part of the Hedron hypervisor. 11 | * 12 | * Hedron is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU General Public License version 2 as 14 | * published by the Free Software Foundation. 15 | * 16 | * Hedron is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License version 2 for more details. 20 | */ 21 | 22 | #include "tss.hpp" 23 | #include "cpu.hpp" 24 | #include "cpulocal.hpp" 25 | #include "hpt.hpp" 26 | 27 | static_assert((TSS_AREA_E - TSS_AREA) / sizeof(Tss) >= NUM_CPU, 28 | "TSS area too small to fit TSSs for all CPUs"); 29 | static_assert(SPC_LOCAL_IOP >= TSS_AREA_E, "IO permission bitmap must lie behind TSS area"); 30 | static_assert(SPC_LOCAL_IOP_E - TSS_AREA < (1 << 16), 31 | "TSS and IO permission bitmap must fit in a 64K segment"); 32 | 33 | Tss& Tss::remote(unsigned id) 34 | { 35 | assert(id < NUM_CPU); 36 | return reinterpret_cast(TSS_AREA)[id]; 37 | } 38 | 39 | Tss& Tss::local() { return remote(Cpu::id()); } 40 | 41 | void Tss::setup() 42 | { 43 | for (mword page = TSS_AREA; page < TSS_AREA_E; page += PAGE_SIZE) { 44 | mword page_p{Buddy::ptr_to_phys(Buddy::allocator.alloc(0, Buddy::FILL_0))}; 45 | 46 | Hpt::boot_hpt().update({page, page_p, Hpt::PTE_NX | Hpt::PTE_G | Hpt::PTE_W | Hpt::PTE_P, PAGE_BITS}); 47 | } 48 | } 49 | 50 | void Tss::build() 51 | { 52 | auto& tss{local()}; 53 | 54 | // The normal kernel stack. 55 | tss.sp0 = reinterpret_cast(&Cpulocal::get().self); 56 | 57 | // See entry.S for when this is used. 58 | tss.ist[1] = Cpulocal::alt_stack_pointer(Cpu::id()); 59 | 60 | tss.iobm = static_cast(SPC_LOCAL_IOP - reinterpret_cast(&tss)); 61 | } 62 | 63 | void Tss::load() { asm volatile("ltr %w0" : : "rm"(Gdt::local_tss_selector())); } 64 | -------------------------------------------------------------------------------- /src/vlapic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Virtual LAPIC Page 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "vlapic.hpp" 19 | #include "assert.hpp" 20 | #include "buddy.hpp" 21 | 22 | static_assert(sizeof(Vlapic) == PAGE_SIZE, "Virtual LAPIC page can only be page sized"); 23 | 24 | void* Vlapic::operator new(size_t size) 25 | { 26 | assert(size == sizeof(Vlapic)); 27 | 28 | return Buddy::allocator.alloc(0, Buddy::FILL_0); 29 | } 30 | 31 | void Vlapic::operator delete(void* ptr) 32 | { 33 | mword const ptr_int{reinterpret_cast(ptr)}; 34 | 35 | assert((ptr_int & PAGE_MASK) == 0); 36 | Buddy::allocator.free(reinterpret_cast(ptr)); 37 | } 38 | -------------------------------------------------------------------------------- /test/unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message(STATUS "Building tests: Check the README file for instructions on disabling them") 2 | 3 | find_package(Catch2 REQUIRED) 4 | find_package(Threads REQUIRED) 5 | 6 | add_executable(test_unit 7 | acpi_fadt.cpp 8 | algorithm.cpp 9 | atomic.cpp 10 | bitmap.cpp 11 | list.cpp 12 | main.cpp 13 | math.cpp 14 | mtrr.cpp 15 | optional.cpp 16 | page_table.cpp 17 | result.cpp 18 | scope_guard.cpp 19 | spinlock.cpp 20 | static_vector.cpp 21 | string.cpp 22 | time.cpp 23 | unique_ptr.cpp 24 | vmx_msr_bitmap.cpp 25 | vmx_preemption_timer.cpp 26 | ) 27 | 28 | target_link_libraries(test_unit Catch2::Catch2 Threads::Threads) 29 | 30 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 31 | target_compile_options(test_unit PRIVATE -fsanitize=address -fsanitize=undefined) 32 | target_link_options(test_unit PRIVATE -fsanitize=address -fsanitize=undefined) 33 | 34 | # At least some GCC versions get their linking wrong with ASAN and produce the following linking warning: 35 | # 36 | # ASan runtime does not come first in initial library list; you 37 | # should either link runtime to your application or manually preload 38 | # it with LD_PRELOAD. 39 | # 40 | # Workaround by linking sanitizers statically. 41 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 42 | target_link_options(test_unit PRIVATE -static-libasan -static-libubsan) 43 | endif() 44 | endif() 45 | 46 | # We consciously don't use catch_discover_tests to auto-discover 47 | # tests, because this results in no tests being run and success being 48 | # reported, when the test binary is not able to list its tests. 49 | add_test(NAME combined_unit_test COMMAND test_unit) 50 | 51 | if(COVERAGE) 52 | 53 | include(CodeCoverage) 54 | APPEND_COVERAGE_COMPILER_FLAGS() 55 | 56 | SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML( 57 | NAME test_unit_coverage 58 | EXECUTABLE test_unit 59 | DEPENDENCIES test_unit) 60 | 61 | endif() 62 | -------------------------------------------------------------------------------- /test/unit/acpi_fadt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ACPI FADT Parse Tests 3 | * 4 | * Copyright (C) 2022 Sebastian Eydam, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "acpi_fadt.hpp" 19 | #include "acpi_fadt_test_helpers.hpp" 20 | 21 | #include 22 | 23 | #include 24 | 25 | // This unit test checks whether the ACPI registers, that are contained in the FADT, are parsed correctly. 26 | 27 | namespace 28 | { 29 | // This function compares the parsed values of a given fadt with the desired values for that FADT. 30 | void check_gas_fields(const Gas_values& desired_values, const void* test_fadt) 31 | { 32 | const Acpi_table_fadt* fadt_table{static_cast(test_fadt)}; 33 | 34 | CHECK(desired_values.pm1a_sts == fadt_table->pm1a_sts()); 35 | CHECK(desired_values.pm1a_ena == fadt_table->pm1a_ena()); 36 | CHECK(desired_values.pm1b_sts == fadt_table->pm1b_sts()); 37 | CHECK(desired_values.pm1b_ena == fadt_table->pm1b_ena()); 38 | CHECK(desired_values.pm1a_cnt == fadt_table->pm1a_cnt()); 39 | CHECK(desired_values.pm1b_cnt == fadt_table->pm1b_cnt()); 40 | 41 | CHECK(desired_values.pm2_cnt == fadt_table->pm2_cnt()); 42 | CHECK(desired_values.pm_tmr == fadt_table->pm_tmr()); 43 | 44 | CHECK(desired_values.gpe0_sts == fadt_table->gpe0_sts()); 45 | CHECK(desired_values.gpe0_ena == fadt_table->gpe0_ena()); 46 | CHECK(desired_values.gpe1_sts == fadt_table->gpe1_sts()); 47 | CHECK(desired_values.gpe1_ena == fadt_table->gpe1_ena()); 48 | } 49 | } // anonymous namespace 50 | 51 | TEST_CASE("ACPI registers are parsed correctly") 52 | { 53 | // Each test compares the parsing result of a given FADT with the desired result for the given FADT. 54 | 55 | SECTION("ACPI registers of the XPS 13 are parsed correctly") 56 | { 57 | check_gas_fields(xps_gas_values, fadt_xps.data()); 58 | } 59 | 60 | SECTION("ACPI registers of the Tuxedo laptop are parsed correctly") 61 | { 62 | check_gas_fields(tuxedo_gas_values, fadt_tuxedo.data()); 63 | } 64 | 65 | SECTION("ACPI registers of a Qemu virtual machine are parsed correctly") 66 | { 67 | check_gas_fields(qemu_gas_values, fadt_qemu.data()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/unit/algorithm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Algorithm Tests 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include 19 | 20 | #include "algorithm.hpp" 21 | 22 | TEST_CASE("accumulate works") 23 | { 24 | std::vector const empty; 25 | std::vector const example{1, 2, 3}; 26 | 27 | CHECK(::accumulate(std::begin(empty), std::end(empty), 0) == 0); 28 | CHECK(::accumulate(std::begin(empty), std::end(empty), 17) == 17); 29 | 30 | CHECK(::accumulate(std::begin(example), std::end(example), 0) == 6); 31 | CHECK(::accumulate(std::begin(example), std::end(example), 17) == 23); 32 | } 33 | 34 | TEST_CASE("array_begin/array_end work with algorithms") 35 | { 36 | const int example[]{1, 2, 3}; 37 | 38 | CHECK(array_size(example) == array_end(example) - array_begin(example)); 39 | CHECK(::accumulate(array_begin(example), array_end(example), 0) == 6); 40 | } 41 | 42 | TEST_CASE("find_if works") 43 | { 44 | std::vector empty; 45 | std::vector example{1, 2, 3}; 46 | 47 | auto is_even{[](int i) { return i % 2 == 0; }}; 48 | 49 | CHECK(::find_if(std::begin(empty), std::end(empty), is_even) == std::end(empty)); 50 | CHECK(::find_if(std::begin(example), std::end(example), is_even) == ++std::begin(example)); 51 | } 52 | 53 | TEST_CASE("for_each works") 54 | { 55 | std::vector const example{1, 2, 3}; 56 | size_t pos{0}; 57 | 58 | ::for_each(std::begin(example), std::end(example), [&](int v) { CHECK(example[pos++] == v); }); 59 | } 60 | -------------------------------------------------------------------------------- /test/unit/atomic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Atomic Tests 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include 19 | 20 | #include "atomic.hpp" 21 | 22 | TEST_CASE("Atomic read-modify-write operations return new value") 23 | { 24 | const int old_value{128}; 25 | int value_to_modify{old_value}; 26 | 27 | SECTION("add") 28 | { 29 | CHECK(Atomic::add(value_to_modify, 1) == old_value + 1); 30 | CHECK(value_to_modify == old_value + 1); 31 | }; 32 | SECTION("sub") 33 | { 34 | CHECK(Atomic::sub(value_to_modify, 1) == old_value - 1); 35 | CHECK(value_to_modify == old_value - 1); 36 | }; 37 | } 38 | 39 | TEST_CASE("Atomic fetch read-modify-write operations return old value") 40 | { 41 | const int old_value{128}; 42 | int value_to_modify{old_value}; 43 | 44 | SECTION("fetch-add") 45 | { 46 | CHECK(Atomic::fetch_add(value_to_modify, 1) == old_value); 47 | CHECK(value_to_modify == old_value + 1); 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /test/unit/construct_counter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Constructor/Destructor call counting 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "types.hpp" 21 | 22 | // Count calls to the constructor and destructor of this class. 23 | // 24 | // This is a useful helper to test whether library code properly frees 25 | // resources. 26 | // 27 | // We use a tagged class to get distinct counters. To use this, create an empty 28 | // tag class in a local scope. 29 | template class construct_counter 30 | { 31 | public: 32 | inline static size_t constructed; 33 | inline static size_t destructed; 34 | 35 | construct_counter() { constructed++; } 36 | construct_counter(construct_counter const& /* rhs */) : construct_counter() {} 37 | 38 | ~construct_counter() { destructed++; } 39 | }; 40 | -------------------------------------------------------------------------------- /test/unit/list.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * List Tests 3 | * 4 | * Copyright (C) 2020 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "list.hpp" 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | namespace 26 | { 27 | 28 | class Element : public Forward_list 29 | { 30 | public: 31 | int value; 32 | 33 | Element(Element*& head, int value_) : Forward_list{head}, value{value_} {} 34 | }; 35 | 36 | class Test_list 37 | { 38 | // A vector that keeps track of Elements in order to clean them up. 39 | std::vector> backing_store; 40 | 41 | public: 42 | Element* head = nullptr; 43 | 44 | Test_list(std::initializer_list const& init) 45 | { 46 | for (int v : init) { 47 | backing_store.emplace_back(std::make_unique(head, v)); 48 | } 49 | } 50 | }; 51 | 52 | // This operator compares Elements to integers by their value. 53 | bool operator==(Forward_list_range const& range, std::vector const& vector) 54 | { 55 | return std::equal(range.begin(), range.end(), vector.begin(), vector.end(), 56 | [](Element const& el, int i) { return el.value == i; }); 57 | } 58 | 59 | } // namespace 60 | 61 | TEST_CASE("Forward_list iterators works", "[list]") 62 | { 63 | Test_list test_list{1, 2, 3}; 64 | auto range{Forward_list_range(test_list.head)}; 65 | 66 | auto cur{std::begin(range)}; 67 | 68 | CHECK(cur->value == 1); 69 | CHECK((++cur)->value == 2); 70 | CHECK((++cur)->value == 3); 71 | 72 | CHECK((++cur) == std::end(range)); 73 | } 74 | 75 | TEST_CASE("Empty lists work", "[list]") 76 | { 77 | Element* el{nullptr}; 78 | auto range{Forward_list_range(el)}; 79 | 80 | CHECK(std::begin(range) == std::end(range)); 81 | } 82 | 83 | TEST_CASE("Algorithms work on lists", "[list]") 84 | { 85 | Test_list test_list{1, 2, 3}; 86 | 87 | CHECK(Forward_list_range(test_list.head) == std::vector{1, 2, 3}); 88 | } 89 | 90 | TEST_CASE("Range-based for works on lists", "[list]") 91 | { 92 | Test_list test_list{1, 2, 3}; 93 | std::vector result; 94 | 95 | for (auto const& el : Forward_list_range(test_list.head)) { 96 | result.push_back(el.value); 97 | } 98 | 99 | CHECK(result == std::vector{1, 2, 3}); 100 | } 101 | -------------------------------------------------------------------------------- /test/unit/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Catch Main Function 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #define CATCH_CONFIG_MAIN 19 | #include 20 | 21 | // Do not write tests into this file. It is just meant to compile the 22 | // heavy-weight part of Catch. 23 | -------------------------------------------------------------------------------- /test/unit/math.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Math Function Tests 3 | * 4 | * Copyright (C) 2019 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include 19 | 20 | #include "math.hpp" 21 | 22 | TEST_CASE("Minimum is computed", "[math]") 23 | { 24 | CHECK(min(-1, 2) == -1); 25 | CHECK(min(2, -1) == -1); 26 | CHECK(min(2, 2) == 2); 27 | } 28 | 29 | TEST_CASE("Maximum is computed", "[math]") 30 | { 31 | CHECK(max(-1, 2) == 2); 32 | CHECK(max(2, -1) == 2); 33 | CHECK(max(2, 2) == 2); 34 | } 35 | 36 | TEST_CASE("Bit scans work", "[math]") 37 | { 38 | SECTION("zero is handled correctly") 39 | { 40 | CHECK(bit_scan_forward(0) == -1); 41 | CHECK(bit_scan_reverse(0) == -1); 42 | } 43 | 44 | SECTION("normal bit scans work") 45 | { 46 | CHECK(bit_scan_forward(1 << 4 | 1 << 3) == 3); 47 | CHECK(bit_scan_reverse(1 << 4 | 1 << 3) == 4); 48 | } 49 | } 50 | 51 | TEST_CASE("Finding maximum order works", "[math]") 52 | { 53 | CHECK(max_order(0, 0) == -1); 54 | CHECK(max_order(0, 1 << 4) == 4); 55 | CHECK(max_order(1 << 2, 1 << 4) == 2); 56 | } 57 | 58 | TEST_CASE("Alignment functions work", "[math]") 59 | { 60 | CHECK(align_dn(0x4000, 0x1000) == 0x4000); 61 | CHECK(align_dn(0x4005, 0x1000) == 0x4000); 62 | 63 | CHECK(align_up(0x4000, 0x1000) == 0x4000); 64 | CHECK(align_up(0x4005, 0x1000) == 0x5000); 65 | } 66 | -------------------------------------------------------------------------------- /test/unit/scope_guard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Scope Guard Tests 3 | * 4 | * Copyright (C) 2022 Julian Stecklina, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | #include "scope_guard.hpp" 19 | 20 | #include 21 | 22 | TEST_CASE("Scope_guard calls cleanup on destruct", "[scope_guard]") 23 | { 24 | int i = 0; 25 | 26 | { 27 | Scope_guard g{[&i] { i++; }}; 28 | 29 | CHECK(i == 0); 30 | } 31 | 32 | CHECK(i == 1); 33 | } 34 | -------------------------------------------------------------------------------- /test/unit/time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Time tests 3 | * 4 | * Copyright (C) 2022 Stefan Hertrampf, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | // Include the class under test first to detect any missing includes early 19 | #include "time.hpp" 20 | 21 | #include 22 | #include 23 | 24 | TEST_CASE("us_to_ticks_works", "[time]") 25 | { 26 | // Use some real world TSC frequency 27 | uint32 freq_tsc_khz = 0x2f3ec2; 28 | 29 | CHECK(us_as_ticks_in_freq(freq_tsc_khz, 0) == 0); 30 | CHECK(us_as_ticks_in_freq(freq_tsc_khz, 1000) == freq_tsc_khz); 31 | 32 | // No overflow when using max values 33 | CHECK(us_as_ticks_in_freq(~0u, ~0u) == 0x4189374b439581); 34 | } 35 | -------------------------------------------------------------------------------- /test/unit/vmx_preemption_timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * VMX Preemption Timer tests 3 | * 4 | * Copyright (C) 2021 Stefan Hertrampf, Cyberus Technology GmbH. 5 | * 6 | * This file is part of the Hedron hypervisor. 7 | * 8 | * Hedron is free software: you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | * Hedron is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License version 2 for more details. 16 | */ 17 | 18 | // Include the class under test first to detect any missing includes early 19 | #include 20 | 21 | #include 22 | 23 | TEST_CASE("tsc_to_timer_value_calculation_works", "[vmx_preemption_timer]") 24 | { 25 | // Zero stays zero and is not rounded up 26 | CHECK(vmx_timer::calc_timeout(0, 0) == 0); 27 | CHECK(vmx_timer::calc_timeout(0, 5) == 0); 28 | 29 | // If shift is zero we do not lose precision 30 | CHECK(vmx_timer::calc_timeout(0xffff, 0) == 0xffff); 31 | CHECK(vmx_timer::calc_timeout(0xffffffff, 0) == 0xffffffff); 32 | 33 | // If shift is present but no information is lost due to shift we do not 34 | // round up 35 | for (int i{0}; i < 4; i++) { 36 | CHECK(vmx_timer::calc_timeout(0xf0, i) == (0xf0 >> i)); 37 | } 38 | 39 | // We do not overflow the available 32bits 40 | CHECK(vmx_timer::calc_timeout(~0ull, 0) == 0xffffffff); 41 | CHECK(vmx_timer::calc_timeout(~0ull, 1) == 0xffffffff); 42 | CHECK(vmx_timer::calc_timeout(~0ull, 31) == 0xffffffff); 43 | 44 | // Rounding up works 45 | for (int i{0xf1}; i < 0x100; i++) { 46 | CHECK(vmx_timer::calc_timeout(i, 4) == 0x10); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tools/check-elf-segments: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import sys 5 | 6 | from elftools.elf.elffile import ELFFile 7 | 8 | 9 | def eprint(*args, **kwargs): 10 | """A helper function to print to stderr. Works like print().""" 11 | print(*args, file=sys.stderr, **kwargs) 12 | 13 | 14 | def main(): 15 | parser = argparse.ArgumentParser(description="Check hypervisor ELF") 16 | parser.add_argument("hypervisor", help="The filename of the hypervisor ELF") 17 | 18 | args = parser.parse_args() 19 | 20 | print("Checking hypervisor ELF '{}' for obvious issues.".format(args.hypervisor)) 21 | 22 | with open(args.hypervisor, "rb") as hv_file: 23 | elf = ELFFile(hv_file) 24 | load_segments = [s for s in elf.iter_segments() if s.header.p_type == "PT_LOAD"] 25 | 26 | expected_load_segments = 3 27 | if len(load_segments) != expected_load_segments: 28 | eprint( 29 | "Failure: ELF has {} segments instead of {}. Please update this script.".format( 30 | len(load_segments), expected_load_segments 31 | ) 32 | ) 33 | sys.exit(1) 34 | 35 | # The two "high" segments in the hypervisor ELF must be contiguous in physical memory. If there is 36 | # space between the two segments, an UEFI loader might not know whether this is usable memory or 37 | # not. By having them contiguous this question does not arise. 38 | # 39 | # See also Hip::add_mhv in src/hip.cpp. 40 | if ( 41 | load_segments[1].header.p_paddr + load_segments[1].header.p_memsz 42 | != load_segments[2].header.p_paddr 43 | ): 44 | eprint( 45 | "Failure: ELF high segments are not contiguous. This is an error in the linker script." 46 | ) 47 | sys.exit(1) 48 | 49 | print("Looks good. 👍") 50 | 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /tools/gen_usb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e -u 4 | 5 | die () { 6 | echo >&2 "ERROR: $@" 7 | echo "Usage: ./gen_usb.sh IMG_FILE_NAME PATH_TO_HEDRON GRUB_CONFIG" 8 | exit 1 9 | } 10 | 11 | # Returns true, if a program is available. 12 | have_exec() { 13 | command -v "$1" > /dev/null 2>&1 14 | } 15 | 16 | if [ "$#" -eq "0" ] ; then 17 | die "no parameters provided." 18 | fi 19 | 20 | [ "$#" -eq 3 ] || die "invalid number of argument $#." 21 | 22 | img_filename=$1 23 | hedron_filename=$2 24 | grub_config=$3 25 | 26 | if have_exec grub2-mkrescue; then 27 | mkrescue=grub2-mkrescue 28 | elif have_exec grub-mkrescue; then 29 | mkrescue=grub-mkrescue 30 | else 31 | echo >&2 "No grub-mkrescue found." 32 | exit 1 33 | fi 34 | 35 | tmp_dir=$(mktemp -d -t filesystem.XXXXXX) || die "unable to create temp directory." 36 | trap 'rm -r "$tmp_dir"' EXIT 37 | 38 | echo "======== Build details ========" 39 | echo "Image: $img_filename" 40 | echo "Hedron: $hedron_filename" 41 | echo "Grub config: $grub_config" 42 | echo "Tmp-dir: $tmp_dir" 43 | echo "===============================" 44 | 45 | if [ ! -f "$hedron_filename" ] ; then 46 | die "Hedron file does not exist." 47 | fi 48 | 49 | if [ ! -f "$grub_config" ] ; then 50 | die "Grub config file does not exist." 51 | fi 52 | 53 | if [ -f "$img_filename" ] ; then 54 | rm "$img_filename" 55 | fi 56 | 57 | mkdir -p "$tmp_dir/boot/grub" 58 | 59 | cp "$hedron_filename" "$tmp_dir/boot/hypervisor-x86_64" 60 | cp "$grub_config" "$tmp_dir/boot/grub/grub.cfg" 61 | 62 | $mkrescue -o "$img_filename" "$tmp_dir" 63 | 64 | if [ -f "$img_filename" ] ; then 65 | echo "$img_filename is ready!" 66 | exit 0 67 | fi 68 | 69 | echo >&2 "ERROR: $img_filename should exist now, but does not!" 70 | exit 1 71 | -------------------------------------------------------------------------------- /tools/grub.cfg.tmpl: -------------------------------------------------------------------------------- 1 | set timeout=0 2 | 3 | menuentry 'Load Hedron' { 4 | insmod part_msdos 5 | multiboot2 /boot/hypervisor-x86_64 serial novga 6 | } 7 | --------------------------------------------------------------------------------