├── src ├── stdlib │ ├── hpp │ │ ├── new │ │ ├── cassert │ │ ├── cstddef │ │ ├── cstdint │ │ └── iostream │ └── h │ │ ├── assert.h │ │ ├── stddef.h │ │ └── stdint.h ├── arch │ ├── x64 │ │ ├── include │ │ │ ├── align.hpp │ │ │ ├── stddef.h │ │ │ ├── types.hpp │ │ │ └── stdint.h │ │ ├── syscall │ │ │ ├── handler.hpp │ │ │ ├── args.hpp │ │ │ ├── handler.s │ │ │ ├── args.cpp │ │ │ ├── module.hpp │ │ │ └── module.cpp │ │ ├── public │ │ │ ├── init.hpp │ │ │ ├── region-list.hpp │ │ │ ├── boot-info.hpp │ │ │ ├── multiboot-region-list.hpp │ │ │ ├── multiboot.hpp │ │ │ ├── region-list.cpp │ │ │ ├── init.cpp │ │ │ └── multiboot-region-list.cpp │ │ ├── interrupts │ │ │ ├── raw-isr.hpp │ │ │ ├── vectors.hpp │ │ │ ├── isr-types.hpp │ │ │ ├── isr.hpp │ │ │ ├── apic │ │ │ │ ├── x2apic.hpp │ │ │ │ ├── ioapic-module.hpp │ │ │ │ ├── lapic-module.hpp │ │ │ │ ├── xapic.hpp │ │ │ │ ├── x2apic.cpp │ │ │ │ ├── lapic-module.cpp │ │ │ │ ├── lapic.hpp │ │ │ │ ├── xapic.cpp │ │ │ │ ├── lapic.cpp │ │ │ │ ├── ioapic.hpp │ │ │ │ ├── ioapic-module.cpp │ │ │ │ └── ioapic.cpp │ │ │ ├── pic.hpp │ │ │ ├── idt.hpp │ │ │ ├── irt.hpp │ │ │ ├── idt.cpp │ │ │ ├── raw-isr.s │ │ │ ├── irt.cpp │ │ │ ├── idt-types.hpp │ │ │ ├── pic.cpp │ │ │ └── isr.cpp │ │ ├── acpi │ │ │ ├── rsdt.hpp │ │ │ ├── xsdt.hpp │ │ │ ├── xsdt.cpp │ │ │ ├── rsdt.cpp │ │ │ ├── acpi-pointer.hpp │ │ │ ├── acpi-module.hpp │ │ │ ├── acpi-root.cpp │ │ │ ├── acpi-root.hpp │ │ │ ├── hpet-table.hpp │ │ │ ├── acpi-pointer.cpp │ │ │ ├── acpi-module.cpp │ │ │ ├── apic-table.hpp │ │ │ └── apic-table.cpp │ │ ├── clock │ │ │ ├── stoppable.hpp │ │ │ ├── pit.hpp │ │ │ ├── hpet.hpp │ │ │ ├── module.hpp │ │ │ ├── hpet.cpp │ │ │ ├── module.cpp │ │ │ └── pit.cpp │ │ ├── critical │ │ │ ├── module.hpp │ │ │ ├── functions.cpp │ │ │ └── module.cpp │ │ ├── segments │ │ │ ├── short-descriptor.cpp │ │ │ ├── local-segment.hpp │ │ │ ├── tss.cpp │ │ │ ├── tss.hpp │ │ │ ├── short-descriptor.hpp │ │ │ ├── local-segment.cpp │ │ │ ├── gdt.hpp │ │ │ └── gdt.cpp │ │ ├── timer │ │ │ ├── module.hpp │ │ │ ├── lapic-timer.hpp │ │ │ ├── lapic-timer.cpp │ │ │ └── module.cpp │ │ ├── vmm │ │ │ ├── global │ │ │ │ ├── global-malloc.hpp │ │ │ │ ├── free-finder.hpp │ │ │ │ ├── global-malloc.cpp │ │ │ │ ├── map-setup.hpp │ │ │ │ ├── global-map.hpp │ │ │ │ ├── free-finder.cpp │ │ │ │ └── map-setup.cpp │ │ │ ├── tlb.hpp │ │ │ ├── user │ │ │ │ ├── user-map.hpp │ │ │ │ └── free-list.hpp │ │ │ └── page-table.hpp │ │ ├── common.hpp │ │ ├── smp │ │ │ ├── startup-code.hpp │ │ │ ├── proc-entry.s │ │ │ ├── cpu.hpp │ │ │ ├── startup-code.cpp │ │ │ └── cpu.cpp │ │ ├── panic │ │ │ ├── panic.hpp │ │ │ └── panic.cpp │ │ ├── state │ │ │ ├── state.hpp │ │ │ └── state.cpp │ │ ├── domains │ │ │ ├── domain.hpp │ │ │ ├── domain-list.hpp │ │ │ └── domain.cpp │ │ ├── pmm │ │ │ ├── step-allocator.hpp │ │ │ ├── buddy-allocator.hpp │ │ │ └── step-allocator.cpp │ │ ├── console │ │ │ ├── text-console.hpp │ │ │ └── text-console.cpp │ │ └── common.cpp │ └── api │ │ ├── panic.hpp │ │ ├── critical.hpp │ │ ├── page-delegate.cpp │ │ ├── clock-module.hpp │ │ ├── domain-list.hpp │ │ ├── global-map.hpp │ │ ├── clock.cpp │ │ ├── syscall-module.hpp │ │ ├── page-delegate.hpp │ │ ├── console.hpp │ │ ├── state.hpp │ │ ├── syscall-args.hpp │ │ ├── virtual-allocator.hpp │ │ ├── clock.hpp │ │ ├── user-map.hpp │ │ ├── timer.hpp │ │ ├── memory-map.hpp │ │ ├── domain.hpp │ │ ├── domain.cpp │ │ ├── syscall-ret.hpp │ │ ├── thread.hpp │ │ └── allocator.hpp ├── util │ ├── assert.cpp │ ├── critical.cpp │ ├── lock.cpp │ ├── assert.hpp │ ├── lock.hpp │ ├── critical.hpp │ ├── stream.hpp │ └── stream.cpp └── memory │ ├── phys-copy.cpp │ ├── new.hpp │ ├── phys-copy.hpp │ ├── easy-map.hpp │ ├── malloc.hpp │ ├── easy-map.cpp │ └── malloc.cpp ├── include └── anarch │ ├── lock │ ├── new │ ├── assert │ ├── stream │ ├── critical │ ├── easy-map │ ├── malloc │ ├── api │ ├── clock │ ├── domain │ ├── panic │ ├── state │ ├── thread │ ├── timer │ ├── console │ ├── user-map │ ├── allocator │ ├── domain-list │ ├── global-map │ ├── memory-map │ ├── syscall-ret │ ├── clock-module │ ├── page-delegate │ ├── syscall-args │ ├── syscall-module │ └── virtual-allocator │ ├── phys-copy │ ├── x64 │ ├── init │ ├── boot-info │ ├── multiboot │ ├── region-list │ └── multiboot-region-list │ ├── align │ ├── stddef │ ├── stdint │ └── types ├── .gitignore ├── test ├── util │ ├── dummy-api │ │ ├── panic.cpp │ │ ├── thread.cpp │ │ ├── critical.hpp │ │ ├── critical.cpp │ │ ├── console.hpp │ │ └── console.cpp │ ├── test-assert.cpp │ ├── test-stream.cpp │ ├── Makefile │ └── test-critical.cpp ├── stdlib-api │ ├── src │ │ ├── assert.cpp │ │ ├── print.cpp │ │ └── alloc.cpp │ ├── Makefile │ └── include │ │ └── stdlib-api │ │ ├── print │ │ ├── alloc │ │ ├── assert │ │ └── scoped-pass ├── build-objects.coffee └── build-objects ├── Makefile └── README.md /src/stdlib/hpp/new: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/h/assert.h: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/h/stddef.h: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/h/stdint.h: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/hpp/cassert: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/hpp/cstddef: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /src/stdlib/hpp/cstdint: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /include/anarch/lock: -------------------------------------------------------------------------------- 1 | #include "../../src/util/lock.hpp" -------------------------------------------------------------------------------- /include/anarch/new: -------------------------------------------------------------------------------- 1 | #include "../../src/memory/new.hpp" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | dependencies 4 | 5 | -------------------------------------------------------------------------------- /include/anarch/assert: -------------------------------------------------------------------------------- 1 | #include "../../src/util/assert.hpp" -------------------------------------------------------------------------------- /include/anarch/stream: -------------------------------------------------------------------------------- 1 | #include "../../src/util/stream.hpp" -------------------------------------------------------------------------------- /include/anarch/critical: -------------------------------------------------------------------------------- 1 | #include "../../src/util/critical.hpp" -------------------------------------------------------------------------------- /include/anarch/easy-map: -------------------------------------------------------------------------------- 1 | #include "../../src/memory/easy-map.hpp" -------------------------------------------------------------------------------- /include/anarch/malloc: -------------------------------------------------------------------------------- 1 | #include "../../src/memory/malloc.hpp" -------------------------------------------------------------------------------- /src/arch/x64/include/align.hpp: -------------------------------------------------------------------------------- 1 | #define ANARCH_OBJECT_ALIGN 0x8 -------------------------------------------------------------------------------- /include/anarch/api/clock: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/clock.hpp" -------------------------------------------------------------------------------- /include/anarch/api/domain: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/domain.hpp" -------------------------------------------------------------------------------- /include/anarch/api/panic: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/panic.hpp" -------------------------------------------------------------------------------- /include/anarch/api/state: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/state.hpp" -------------------------------------------------------------------------------- /include/anarch/api/thread: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/thread.hpp" -------------------------------------------------------------------------------- /include/anarch/api/timer: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/timer.hpp" -------------------------------------------------------------------------------- /include/anarch/phys-copy: -------------------------------------------------------------------------------- 1 | #include "../../src/memory/phys-copy.hpp" -------------------------------------------------------------------------------- /include/anarch/api/console: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/console.hpp" -------------------------------------------------------------------------------- /include/anarch/api/user-map: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/user-map.hpp" -------------------------------------------------------------------------------- /include/anarch/x64/init: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/x64/public/init.hpp" -------------------------------------------------------------------------------- /include/anarch/api/allocator: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/allocator.hpp" -------------------------------------------------------------------------------- /include/anarch/api/domain-list: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/domain-list.hpp" -------------------------------------------------------------------------------- /include/anarch/api/global-map: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/global-map.hpp" -------------------------------------------------------------------------------- /include/anarch/api/memory-map: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/memory-map.hpp" -------------------------------------------------------------------------------- /include/anarch/api/syscall-ret: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/syscall-ret.hpp" -------------------------------------------------------------------------------- /include/anarch/api/clock-module: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/clock-module.hpp" -------------------------------------------------------------------------------- /include/anarch/api/page-delegate: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/page-delegate.hpp" -------------------------------------------------------------------------------- /include/anarch/api/syscall-args: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/syscall-args.hpp" -------------------------------------------------------------------------------- /include/anarch/x64/boot-info: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/x64/public/boot-info.hpp" -------------------------------------------------------------------------------- /include/anarch/x64/multiboot: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/x64/public/multiboot.hpp" -------------------------------------------------------------------------------- /include/anarch/api/syscall-module: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/syscall-module.hpp" -------------------------------------------------------------------------------- /include/anarch/x64/region-list: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/x64/public/region-list.hpp" -------------------------------------------------------------------------------- /include/anarch/api/virtual-allocator: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/api/virtual-allocator.hpp" -------------------------------------------------------------------------------- /include/anarch/x64/multiboot-region-list: -------------------------------------------------------------------------------- 1 | #include "../../../src/arch/x64/public/multiboot-region-list.hpp" -------------------------------------------------------------------------------- /include/anarch/align: -------------------------------------------------------------------------------- 1 | #ifdef __ANARCH_TARGET_X64__ 2 | #include "../../src/arch/x64/include/align.hpp" 3 | #endif -------------------------------------------------------------------------------- /include/anarch/stddef: -------------------------------------------------------------------------------- 1 | #ifdef __ANARCH_TARGET_X64__ 2 | #include "../../src/arch/x64/include/stddef.h" 3 | #endif -------------------------------------------------------------------------------- /include/anarch/stdint: -------------------------------------------------------------------------------- 1 | #ifdef __ANARCH_TARGET_X64__ 2 | #include "../../src/arch/x64/include/stdint.h" 3 | #endif -------------------------------------------------------------------------------- /include/anarch/types: -------------------------------------------------------------------------------- 1 | #ifdef __ANARCH_TARGET_X64__ 2 | #include "../../src/arch/x64/include/types.hpp" 3 | #endif -------------------------------------------------------------------------------- /test/util/dummy-api/panic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace anarch { 4 | 5 | void Panic(const char * str) { 6 | throw str; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/util/assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | 5 | int __assert(const char * msg) { 6 | anarch::Panic(msg); 7 | return 0; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/util/dummy-api/thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace anarch { 4 | 5 | Thread & Thread::GetCurrent() { 6 | return *(Thread *)0; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /test/util/dummy-api/critical.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace anarch { 4 | 5 | namespace dummy { 6 | 7 | void SetIgnoreCriticality(bool flag); 8 | 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/stdlib-api/src/assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | 6 | int Die(const char * msg) { 7 | std::cerr << msg << std::endl; 8 | exit(1); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/arch/api/panic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_PANIC_HPP__ 2 | #define __ANARCH_API_PANIC_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | void Panic(const char * msg) ANSA_NORETURN; 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /test/stdlib-api/Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS=-std=c++11 -Wall -Wextra 2 | INCLUDES=-Iinclude 3 | 4 | all: build 5 | ../build-objects $(CXX) $(INCLUDES) $(CXXFLAGS) -c src/*.cpp -o build 6 | 7 | build: 8 | mkdir build 9 | 10 | clean: 11 | rm -rf build 12 | -------------------------------------------------------------------------------- /src/arch/api/critical.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_CRITICAL_HPP__ 2 | #define __ANARCH_API_CRITICAL_HPP__ 3 | 4 | namespace anarch { 5 | 6 | bool IgnoreCriticality(); 7 | bool GetCritical(); 8 | void SetCritical(bool flag); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/stdlib/hpp/iostream: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_STDLIB_IOSTREAM_HPP__ 2 | #define __ANARCH_STDLIB_IOSTREAM_HPP__ 3 | 4 | #include 5 | 6 | namespace std { 7 | 8 | using anarch::cout; 9 | using anarch::cerr; 10 | using anarch::endl; 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_SYSCALL_HANDLER_HPP__ 2 | #define __ANARCH_X64_SYSCALL_HANDLER_HPP__ 3 | 4 | /** 5 | * The entry point of the syscall handler. 6 | * @critical 7 | */ 8 | void AnarchRawSyscallHandler() __asm__("AnarchRawSyscallHandler"); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /test/stdlib-api/include/stdlib-api/print: -------------------------------------------------------------------------------- 1 | #ifndef __STDLIB_API_PRINT_HPP__ 2 | #define __STDLIB_API_PRINT_HPP__ 3 | 4 | extern "C" { 5 | 6 | void PrintString(const char * str); 7 | void PrintError(const char * str); 8 | void PrintNumber(unsigned long long number); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/util/critical.cpp: -------------------------------------------------------------------------------- 1 | #include "critical.hpp" 2 | 3 | namespace anarch { 4 | 5 | ScopedCritical::ScopedCritical() : wasCritical(GetCritical()) { 6 | if (!wasCritical) SetCritical(true); 7 | } 8 | 9 | ScopedCritical::~ScopedCritical() { 10 | if (!wasCritical) SetCritical(false); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /test/stdlib-api/include/stdlib-api/alloc: -------------------------------------------------------------------------------- 1 | #ifndef __STDLIB_API_ALLOC_HPP__ 2 | #define __STDLIB_API_ALLOC_HPP__ 3 | 4 | extern "C" { 5 | 6 | void * AlignMemory(unsigned long size, unsigned long align); 7 | void * AllocMemory(unsigned long size); 8 | void FreeMemory(void * mem); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/memory/phys-copy.cpp: -------------------------------------------------------------------------------- 1 | #include "phys-copy.hpp" 2 | #include "easy-map.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | void PhysCopy(void * dest, PhysAddr source, size_t size) { 8 | EasyMap map(source, size); 9 | ansa::Memcpy(dest, (uint8_t *)map.GetStart(), size); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dependencies: 2 | mkdir dependencies 3 | git clone https://github.com/unixpickle/ansa.git dependencies/ansa 4 | git clone https://github.com/unixpickle/analloc2.git dependencies/analloc2 5 | git clone https://github.com/unixpickle/makemaker.git dependencies/makemaker 6 | 7 | clean-all: 8 | rm -rf dependencies 9 | -------------------------------------------------------------------------------- /src/arch/x64/include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STDDEF_H__ 2 | #define __ANARCH_X64_STDDEF_H__ 3 | 4 | #ifndef NULL 5 | #ifdef __cplusplus 6 | #define NULL 0 7 | #else 8 | #define NULL ((void *)0) 9 | #endif 10 | #endif 11 | 12 | typedef unsigned long int size_t; 13 | typedef long int ssize_t; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/arch/x64/public/init.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_INIT_HPP__ 2 | #define __ANARCH_X64_INIT_HPP__ 3 | 4 | #include "boot-info.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | void InitializeSingletons(); 11 | void SetBootInfo(const BootInfo * info); 12 | const BootInfo * GetBootInfo(); 13 | 14 | } 15 | 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/util/lock.cpp: -------------------------------------------------------------------------------- 1 | #include "lock.hpp" 2 | #include "critical.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | // CriticalLock // 8 | 9 | void CriticalLock::Seize() { 10 | AssertCritical(); 11 | super::Seize(); 12 | } 13 | 14 | void CriticalLock::Release() { 15 | AssertCritical(); 16 | super::Release(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/arch/api/page-delegate.cpp: -------------------------------------------------------------------------------- 1 | #include "page-delegate.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace { 7 | 8 | PageDelegate gDelegate = NULL; 9 | 10 | } 11 | 12 | void SetGlobalPageDelegate(PageDelegate obj) { 13 | gDelegate = obj; 14 | } 15 | 16 | PageDelegate GetGlobalPageDelegate() { 17 | return gDelegate; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/raw-isr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_RAW_ISR_HPP__ 2 | #define __ANARCH_X64_RAW_ISR_HPP__ 3 | 4 | extern "C" { 5 | 6 | // these three routines are all I need to do in Assembly 7 | 8 | void RawNonCodedIsr() __asm__("RawNonCodedIsr"); 9 | void RawCodedIsr() __asm__("RawCodedIsr"); 10 | void RawPicEoiIsr() __asm__("RawPicEoiIsr"); 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/rsdt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_RSDT_HPP__ 2 | #define __ANARCH_X64_RSDT_HPP__ 3 | 4 | #include "acpi-root.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class Rsdt : public AcpiRoot { 11 | public: 12 | Rsdt(PhysAddr phys); 13 | 14 | virtual int GetCount(); 15 | virtual PhysAddr GetTable(int i); 16 | }; 17 | 18 | } 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/xsdt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_XSDT_HPP__ 2 | #define __ANARCH_X64_XSDT_HPP__ 3 | 4 | #include "acpi-root.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class Xsdt : public AcpiRoot { 11 | public: 12 | Xsdt(PhysAddr phys); 13 | 14 | virtual int GetCount(); 15 | virtual PhysAddr GetTable(int i); 16 | }; 17 | 18 | } 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/arch/api/clock-module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_CLOCK_MODULE_HPP__ 2 | #define __ANARCH_API_CLOCK_MODULE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | class Clock; 9 | 10 | class ClockModule : public ansa::Module { 11 | public: 12 | static ClockModule & GetGlobal(); 13 | 14 | virtual Clock & GetClock() = 0; // @ambicritical 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/xsdt.cpp: -------------------------------------------------------------------------------- 1 | #include "xsdt.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | Xsdt::Xsdt(PhysAddr phys) : AcpiRoot(phys) { 8 | } 9 | 10 | int Xsdt::GetCount() { 11 | return (int)((tableSize - 0x24) / 8); 12 | } 13 | 14 | PhysAddr Xsdt::GetTable(int i) { 15 | uint64_t * ptr = (uint64_t *)(map.GetStart() + 0x24); 16 | return ptr[i]; 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/rsdt.cpp: -------------------------------------------------------------------------------- 1 | #include "rsdt.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | Rsdt::Rsdt(PhysAddr phys) : AcpiRoot(phys) { 8 | } 9 | 10 | int Rsdt::GetCount() { 11 | return (int)((tableSize - 0x24) / 4); 12 | } 13 | 14 | PhysAddr Rsdt::GetTable(int i) { 15 | uint32_t * ptr = (uint32_t *)(map.GetStart() + 0x24); 16 | return (PhysAddr)ptr[i]; 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/vectors.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_VECTORS_HPP__ 2 | #define __ANARCH_X64_VECTORS_HPP__ 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | namespace IntVectors { 9 | 10 | const uint8_t Pit = 0x20; 11 | const uint8_t LapicTimer = 0x21; 12 | const uint8_t Invlpg = 0x22; 13 | const uint8_t Wakeup = 0x23; 14 | const uint8_t Panic = 0xef; 15 | 16 | }; 17 | 18 | } 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/memory/new.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_UTIL_NEW_HPP__ 2 | #define __ANARCH_UTIL_NEW_HPP__ 3 | 4 | #include 5 | 6 | inline void * operator new(size_t, void * p) { 7 | return p; 8 | } 9 | 10 | inline void * operator new[](size_t, void * p) { 11 | return p; 12 | } 13 | 14 | inline void operator delete(void *, void *) { 15 | } 16 | 17 | inline void operator delete[](void *, void *) { 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/arch/api/domain-list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_DOMAIN_LIST_HPP__ 2 | #define __ANARCH_API_DOMAIN_LIST_HPP__ 3 | 4 | #include "domain.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | class DomainList : public ansa::Module { 10 | public: 11 | static DomainList & GetGlobal(); 12 | 13 | virtual int GetCount() = 0; 14 | virtual Domain & operator[](int idx) = 0; 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /test/stdlib-api/include/stdlib-api/assert: -------------------------------------------------------------------------------- 1 | #ifndef __STDLIB_API_ASSERT_H__ 2 | #define __STDLIB_API_ASSERT_H__ 3 | 4 | #define STDLIB_API_ASSERT_STRX(x) #x 5 | #define STDLIB_API_ASSERT_STR(x) STDLIB_API_ASSERT_STRX(x) 6 | #define Assert(x) (void)((x) || (Die("Assertion failure: " #x " at " __FILE__ ":" STDLIB_API_ASSERT_STR(__LINE__)))); 7 | 8 | extern "C" { 9 | 10 | int Die(const char * msg); 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /test/stdlib-api/src/print.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | 6 | void PrintString(const char * str) { 7 | printf("%s", str); 8 | fflush(stdout); 9 | } 10 | 11 | void PrintError(const char * str) { 12 | fprintf(stderr, "%s", str); 13 | fflush(stderr); 14 | } 15 | 16 | void PrintNumber(unsigned long long number) { 17 | printf("0x%llx", number); 18 | fflush(stdout); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/arch/x64/clock/stoppable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STOPPABLE_HPP__ 2 | #define __ANARCH_X64_STOPPABLE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class StoppableClock : public Clock { 11 | public: 12 | virtual ~StoppableClock() { 13 | } 14 | 15 | virtual void Start() = 0; // @noncritical 16 | virtual void Stop() = 0; // @noncritical 17 | }; 18 | 19 | } 20 | 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/memory/phys-copy.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_PHYS_COPY_HPP__ 2 | #define __ANARCH_PHYS_COPY_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | /** 10 | * Temporarily maps a physical address to the virtual address space using an 11 | * EasyMap, then copies that memory, then unmaps it. 12 | * @noncritical 13 | */ 14 | void PhysCopy(void * dest, PhysAddr source, size_t size); 15 | 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /test/stdlib-api/src/alloc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | 6 | void * AlignMemory(unsigned long size, unsigned long align) { 7 | void * buf; 8 | if (posix_memalign(&buf, (size_t)align, (size_t)size)) { 9 | return NULL; 10 | } 11 | return buf; 12 | } 13 | 14 | void * AllocMemory(unsigned long size) { 15 | return malloc((size_t)size); 16 | } 17 | 18 | void FreeMemory(void * mem) { 19 | free(mem); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /test/util/test-assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | ScopedPass pass("assert()"); 8 | try { 9 | assert(true); 10 | assert(3 == 3); 11 | try { 12 | assert(false); 13 | Die("assert(false) should Panic!"); 14 | } catch (const char * x) { 15 | } 16 | } catch (const char * msg) { 17 | Die(msg); 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/isr-types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_ISR_TYPES_HPP__ 2 | #define __ANARCH_X64_ISR_TYPES_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | struct IsrStack { 12 | uint64_t rip; 13 | uint64_t cs; 14 | uint64_t rflags; 15 | uint64_t rsp; 16 | uint64_t ss; 17 | }; 18 | 19 | static_assert(sizeof(IsrStack) == 0x28, "invalid IRETQ stack size"); 20 | 21 | } 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/util/dummy-api/critical.cpp: -------------------------------------------------------------------------------- 1 | namespace anarch { 2 | 3 | namespace { 4 | 5 | bool ignoreCriticality = true; 6 | bool critical = true; 7 | 8 | } 9 | 10 | namespace dummy { 11 | 12 | void SetIgnoreCriticality(bool flag) { 13 | ignoreCriticality = flag; 14 | } 15 | 16 | } 17 | 18 | bool IgnoreCriticality() { 19 | return ignoreCriticality; 20 | } 21 | 22 | bool GetCritical() { 23 | return critical; 24 | } 25 | 26 | void SetCritical(bool flag) { 27 | critical = flag; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/arch/x64/critical/module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_CRITICAL_MODULE_HPP__ 2 | #define __ANARCH_X64_CRITICAL_MODULE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class CriticalModule : public ansa::Module { 11 | public: 12 | static void InitGlobal(); 13 | static CriticalModule & GetGlobal(); 14 | 15 | protected: 16 | virtual ansa::DepList GetDependencies(); 17 | virtual void Initialize(); 18 | }; 19 | 20 | } 21 | 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/util/assert.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_UTIL_ASSERT_H__ 2 | #define __ANARCH_UTIL_ASSERT_H__ 3 | 4 | #ifdef NDEBUG 5 | #define assert(x) 6 | #else 7 | #define ASSERT_STRX(x) #x 8 | #define ASSERT_STR(x) ASSERT_STRX(x) 9 | #define assert(x) (void)((x) || (__assert("Assertion failure: " #x " at " __FILE__ ":" ASSERT_STR(__LINE__)))); 10 | #endif 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | int __assert(const char * msg); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/arch/x64/segments/short-descriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "short-descriptor.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | ShortDescriptor::ShortDescriptor(bool privileged, bool executable) 8 | : limit(0), baseLow(0), baseMid(0), accessBit(0), 9 | writable(executable ? 0 : 1), direction(0), 10 | executable(executable ? 1 : 0), reservedOne(1), 11 | privilege(privileged ? 0 : 3), present(1), limitHigh(0), reservedZero(0), 12 | longMode(1), size(0), granularity(0), baseHigh(0) { 13 | } 14 | 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/arch/api/global-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_GLOBAL_MAP_HPP__ 2 | #define __ANARCH_API_GLOBAL_MAP_HPP__ 3 | 4 | #include 5 | #include "memory-map.hpp" 6 | 7 | namespace anarch { 8 | 9 | class GlobalMap : public ansa::Module, public MemoryMap { 10 | public: 11 | // all @ambicritical 12 | static GlobalMap & GetGlobal(); 13 | static int GetPageSizeCount(); 14 | static size_t GetPageSize(int); 15 | static size_t GetPageSizeAlign(int); 16 | static Capabilities GetCapabilities(); 17 | }; 18 | 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/util/lock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_UTIL_LOCK_HPP__ 2 | #define __ANARCH_UTIL_LOCK_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | class Thread; 11 | 12 | /** 13 | * A lock only to be used in critical sections. 14 | */ 15 | class CriticalLock : public ansa::OrderedLock { 16 | public: 17 | typedef ansa::OrderedLock super; 18 | virtual void Seize(); 19 | virtual void Release(); 20 | }; 21 | 22 | using ansa::ScopedLock; 23 | 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/arch/x64/timer/module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_TIMER_MODULE_HPP__ 2 | #define __ANARCH_X64_TIMER_MODULE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class TimerModule : public ansa::Module { 11 | public: 12 | static void InitGlobal(); 13 | static TimerModule & GetGlobal(); 14 | 15 | protected: 16 | virtual ansa::DepList GetDependencies(); 17 | virtual void Initialize(); 18 | 19 | private: 20 | static void CalibrateMethod(); 21 | }; 22 | 23 | } 24 | 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/isr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_ISR_HPP__ 2 | #define __ANARCH_X64_ISR_HPP__ 3 | 4 | #include "isr-types.hpp" 5 | 6 | extern "C" { 7 | 8 | void InterruptCoded(uint64_t vector, anarch::x64::IsrStack * stack, 9 | uint64_t code) __asm__("InterruptCoded"); 10 | 11 | void InterruptNonCoded(uint64_t vector, anarch::x64::IsrStack * stack) 12 | __asm__("InterruptNonCoded"); 13 | 14 | void InterruptPicEoi(uint64_t vector, anarch::x64::IsrStack * stack) 15 | __asm__("InterruptPicEoi"); 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/global-malloc.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | class GlobalMalloc : public ansa::Module { 10 | public: 11 | static void InitGlobal(); 12 | static GlobalMalloc & GetGlobal(); 13 | 14 | VirtualAllocator & GetAllocator(); 15 | 16 | protected: 17 | virtual ansa::DepList GetDependencies(); 18 | virtual void Initialize(); 19 | 20 | private: 21 | char mallocBuf[sizeof(Malloc)] ANSA_ALIGNED(8); 22 | }; 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/x2apic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_X2APIC_HPP__ 2 | #define __ANARCH_X64_X2APIC_HPP__ 3 | 4 | #include "lapic.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class X2Apic : public Lapic { 11 | public: 12 | virtual uint64_t ReadReg(uint16_t reg); 13 | virtual void WriteReg(uint16_t reg, uint64_t value); 14 | virtual void Enable(); 15 | virtual uint32_t GetId(); 16 | virtual void SendIpi(uint32_t cpu, uint8_t vector, uint8_t mode, 17 | uint8_t level, uint8_t trigger); 18 | }; 19 | 20 | } 21 | 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/arch/x64/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_COMMON_HPP__ 2 | #define __ANARCH_X64_COMMON_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | /** 11 | * @critical 12 | */ 13 | void OutB(uint16_t port, uint8_t byte); 14 | 15 | /** 16 | * @critical 17 | */ 18 | void CpuID(uint32_t eax, uint32_t * ebx, uint32_t * edx, uint32_t * ecx); 19 | 20 | /** 21 | * @critical 22 | */ 23 | uint64_t ReadMsr(uint32_t cell); 24 | 25 | /** 26 | * @critical 27 | */ 28 | void WriteMsr(uint32_t cell, uint64_t value); 29 | 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/arch/x64/critical/functions.cpp: -------------------------------------------------------------------------------- 1 | #include "module.hpp" 2 | 3 | namespace anarch { 4 | 5 | bool IgnoreCriticality() { 6 | return !x64::CriticalModule::GetGlobal().IsInitialized(); 7 | } 8 | 9 | bool GetCritical() { 10 | if (IgnoreCriticality()) return true; 11 | 12 | unsigned long value; 13 | __asm__("pushfq\n" 14 | "pop %0" : "=r" (value)); 15 | return (value & (1 << 9)) == 0; 16 | } 17 | 18 | void SetCritical(bool flag) { 19 | if (IgnoreCriticality()) return; 20 | 21 | if (flag) { 22 | __asm__("cli"); 23 | } else { 24 | __asm__("sti"); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/ioapic-module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANACRH_X64_IOAPIC_MODULE_HPP__ 2 | #define __ANACRH_X64_IOAPIC_MODULE_HPP__ 3 | 4 | #include "ioapic.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class IOApicModule : public ansa::Module { 12 | public: 13 | static void InitGlobal(); 14 | static IOApicModule & GetGlobal(); 15 | 16 | IOApic & GetBaseIOApic(); 17 | 18 | protected: 19 | virtual ansa::DepList GetDependencies(); 20 | virtual void Initialize(); 21 | 22 | private: 23 | IOApic * baseIOApic; 24 | }; 25 | 26 | } 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/pic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_PIC_HPP__ 2 | #define __ANARCH_X64_PIC_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class Pic : public ansa::Module { 12 | public: 13 | static void InitGlobal(); 14 | static Pic & GetGlobal(); 15 | 16 | void Remap(uint8_t masterBase, uint8_t slaveBase, uint8_t masterMask, 17 | uint8_t slaveMask); 18 | 19 | protected: 20 | virtual ansa::DepList GetDependencies(); 21 | virtual void Initialize(); // disables PIC 22 | }; 23 | 24 | } 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/arch/api/clock.cpp: -------------------------------------------------------------------------------- 1 | #include "clock.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | uint64_t Clock::GetMicros() { 7 | return GetMicrosPerTick().ScaleInteger(GetTicks()); 8 | } 9 | 10 | void Clock::WaitUntil(uint64_t ticks) { 11 | AssertNoncritical(); 12 | while (GetTicks() < ticks); 13 | } 14 | 15 | void Clock::Sleep(uint64_t ticks) { 16 | WaitUntil(GetTicks() + ticks); 17 | } 18 | 19 | void Clock::MicroSleep(uint64_t micros) { 20 | uint64_t now = GetTicks(); 21 | uint64_t tickCount = GetMicrosPerTick().Flip().ScaleInteger(micros); 22 | WaitUntil(now + tickCount); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/arch/x64/segments/local-segment.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_LOCAL_SEGMENT_HPP__ 2 | #define __ANARCH_X64_LOCAL_SEGMENT_HPP__ 3 | 4 | #include "../interrupts/isr-types.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class LocalSegment { 11 | public: 12 | static void Swap(); // @critical 13 | static uint64_t Read(); // @critical 14 | static void Write(uint64_t); // @critical 15 | 16 | class SwapScope { 17 | public: 18 | SwapScope(uint8_t vector, const IsrStack & stack); 19 | ~SwapScope(); 20 | private: 21 | bool didSwap; 22 | }; 23 | }; 24 | 25 | } 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/arch/x64/public/region-list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_REGION_LIST_HPP__ 2 | #define __ANARCH_X64_REGION_LIST_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class RegionList { 12 | public: 13 | virtual const ANAlloc::RegionList & GetLowerRegions() const = 0; 14 | virtual const ANAlloc::RegionList & GetUpperRegions() const = 0; 15 | 16 | virtual const ANAlloc::Region * FindRegion(PhysAddr addr) const; 17 | virtual const ANAlloc::Region * NextRegion(const ANAlloc::Region * reg) 18 | const; 19 | }; 20 | 21 | } 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/util/critical.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_UTIL_CRITICAL_HPP__ 2 | #define __ANARCH_UTIL_CRITICAL_HPP__ 3 | 4 | #include "assert.hpp" 5 | #include "../arch/api/critical.hpp" 6 | 7 | #define AssertCritical() assert(::anarch::IgnoreCriticality() || \ 8 | ::anarch::GetCritical()); 9 | #define AssertNoncritical() assert(::anarch::IgnoreCriticality() || \ 10 | !::anarch::GetCritical()); 11 | 12 | namespace anarch { 13 | 14 | class ScopedCritical { 15 | public: 16 | ScopedCritical(); // @ambicritical (x) 17 | ~ScopedCritical(); // @critical -> @ambicritical (x) 18 | 19 | protected: 20 | bool wasCritical; 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/arch/x64/public/boot-info.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_BOOT_INFO_HPP__ 2 | #define __ANARCH_X64_BOOT_INFO_HPP__ 3 | 4 | #include "region-list.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class BootInfo { 12 | public: 13 | BootInfo(const RegionList & regs, PhysAddr end) 14 | : regions(regs), kernelEnd(end) {} 15 | 16 | const RegionList & GetRegions() const { 17 | return regions; 18 | } 19 | 20 | PhysAddr GetKernelEnd() const { 21 | return kernelEnd; 22 | } 23 | 24 | private: 25 | const RegionList & regions; 26 | PhysAddr kernelEnd; 27 | }; 28 | 29 | } 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /test/util/test-stream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "dummy-api/console.hpp" 6 | 7 | using namespace anarch; 8 | 9 | int main() { 10 | ScopedPass pass("[cout/cerr/StreamModule]"); 11 | 12 | StreamModule::GetGlobal().Load(); 13 | cout << "abcd" << endl; 14 | cerr << "efgh" << endl; 15 | cout << (unsigned int)32 << endl; 16 | 17 | dummy::LogConsole & console = dummy::LogConsole::GetGlobal(); 18 | Assert(console.GetBacklogSize() == 15); 19 | Assert(ansa::Memcmp(console.GetBacklog(), "abcd\nefgh\n0x20\n", 15) == 0); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/args.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | class SyscallArgs : public anarch::SyscallArgs { 8 | public: 9 | SyscallArgs(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, 10 | uint64_t arg5); 11 | 12 | virtual bool PopBool(); 13 | virtual int PopInt(); 14 | virtual uint32_t PopUInt32(); 15 | virtual uint64_t PopUInt64(); 16 | virtual PhysAddr PopPhysAddr(); 17 | virtual VirtAddr PopVirtAddr(); 18 | virtual PhysSize PopPhysSize(); 19 | virtual size_t PopVirtSize(); 20 | 21 | private: 22 | uint64_t arguments[5]; 23 | int idx = 0; 24 | }; 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/arch/x64/clock/pit.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_PIT_HPP__ 2 | #define __ANARCH_X64_PIT_HPP__ 3 | 4 | #include "stoppable.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class Pit : public StoppableClock { 12 | public: 13 | Pit(uint16_t divisor); 14 | 15 | virtual void Start(); // @critical 16 | virtual void Stop(); // @critical 17 | 18 | virtual uint64_t GetTicks(); // @ambicritical 19 | virtual ansa::Rational GetMicrosPerTick(); // @ambicritical 20 | 21 | private: 22 | uint16_t divisor; 23 | ansa::Atomic counter; 24 | 25 | static void InterruptHandler(); 26 | }; 27 | 28 | } 29 | 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/arch/x64/include/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_TYPES_HPP__ 2 | #define __ANARCH_X64_TYPES_HPP__ 3 | 4 | #include 5 | 6 | /** 7 | * A numerical representation of a physical address. 8 | */ 9 | typedef uint64_t PhysAddr; 10 | 11 | /** 12 | * A numerical representation of the size of a chunk of physical memory. 13 | */ 14 | typedef uint64_t PhysSize; 15 | 16 | /** 17 | * A numerical representation of a virtual address. 18 | */ 19 | typedef uint64_t VirtAddr; 20 | 21 | /** 22 | * A numerical type that is the native size of the processor. 23 | */ 24 | typedef int64_t NativeInt; 25 | 26 | /** 27 | * An unsigned NativeInt 28 | */ 29 | typedef uint64_t NativeUInt; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/arch/x64/smp/startup-code.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STARTUP_CODE_HPP__ 2 | #define __ANARCH_X64_STARTUP_CODE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | /** 11 | * This class configures and destroys trampoline code lower memory for CPU 12 | * initialization 13 | */ 14 | class StartupCode { 15 | public: 16 | StartupCode(void (* callbackFunc)()); 17 | ~StartupCode(); 18 | 19 | void ResetStartupStack(); 20 | 21 | private: 22 | static const VirtAddr CodeBase = 0x5000; 23 | static const VirtAddr PageTableBase = 0x3000; 24 | 25 | uint64_t callbackFunc; 26 | 27 | void * dataBackup; 28 | }; 29 | 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /test/stdlib-api/include/stdlib-api/scoped-pass: -------------------------------------------------------------------------------- 1 | #ifndef __STDLIB_API_SCOPED_PASS_HPP__ 2 | #define __STDLIB_API_SCOPED_PASS_HPP__ 3 | 4 | #include "print" 5 | 6 | class ScopedPass { 7 | public: 8 | template 9 | inline ScopedPass(Y... args) { 10 | PrintString("testing"); 11 | Initializer(args...); 12 | } 13 | 14 | inline ~ScopedPass() { 15 | PrintString("passed!\n"); 16 | } 17 | 18 | inline void Initializer() { 19 | PrintString(" ... "); 20 | } 21 | 22 | template 23 | inline void Initializer(X arg1, Y... args) { 24 | PrintString(" "); 25 | PrintString(arg1); 26 | Initializer(args...); 27 | } 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-pointer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_ACPI_POINTER_HPP__ 2 | #define __ANARCH_ACPI_POINTER_HPP__ 3 | 4 | #include "acpi-root.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | // this structure is also known as the RSDP (or XSDP) 13 | class AcpiPointer { 14 | public: 15 | uint64_t signature; 16 | uint8_t checksum; 17 | char oemid[6]; 18 | uint8_t revision; 19 | uint32_t ptrRSDT; 20 | uint32_t length; 21 | uint64_t ptrXSDT; 22 | uint8_t xChecksum; 23 | char reserved[3]; 24 | 25 | AcpiRoot * GenerateRoot(); 26 | 27 | static AcpiPointer * Find(); 28 | } ANSA_PACKED; 29 | 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/arch/api/syscall-module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_SYSCALL_MODULE_HPP__ 2 | #define __ANARCH_API_SYSCALL_MODULE_HPP__ 3 | 4 | #include "syscall-args.hpp" 5 | #include "syscall-ret.hpp" 6 | #include 7 | 8 | namespace anarch { 9 | 10 | class SyscallModule : public ansa::Module { 11 | public: 12 | typedef SyscallRet (* SyscallHandler)(uint16_t number, SyscallArgs & args); 13 | 14 | static SyscallModule & GetGlobal(); // @ambicritical 15 | 16 | /** 17 | * Set the global syscall handler. You must call this before any user-space 18 | * task triggers a system call. 19 | * @ambicritical 20 | */ 21 | virtual void SetHandler(SyscallHandler handler) = 0; 22 | }; 23 | 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/arch/api/page-delegate.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_PAGE_DELEGATE_HPP__ 2 | #define __ANARCH_API_PAGE_DELEGATE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | /** 9 | * A function which may be called to handle a page fault. 10 | */ 11 | typedef void (* PageDelegate)(VirtAddr addr, bool write); 12 | 13 | /** 14 | * Set the global page fault handler. You should call this before initializing 15 | * any anarch modules. 16 | * @ambicritical 17 | */ 18 | void SetGlobalPageDelegate(PageDelegate); 19 | 20 | /** 21 | * Returns the global page delegate. If no delegate has been set, this returns 22 | * `NULL`. 23 | * @ambicritical 24 | */ 25 | PageDelegate GetGlobalPageDelegate(); 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/idt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_IDT_HPP__ 2 | #define __ANARCH_X64_IDT_HPP__ 3 | 4 | #include "idt-types.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class Idt : public ansa::Module { 12 | public: 13 | static void InitGlobal(); 14 | static Idt & GetGlobal(); 15 | 16 | void SetEntry(int idx, void * fn, uint8_t flags); 17 | void SetIst(int idx, uint8_t ist); 18 | 19 | void Set(); 20 | 21 | protected: 22 | virtual ansa::DepList GetDependencies(); 23 | 24 | private: 25 | IdtEntry entries[0x100] ANSA_ALIGNED(8); 26 | IdtHandler handlers[0x100]; 27 | 28 | IdtPointer idtPtr ANSA_ALIGNED(8); 29 | }; 30 | 31 | } 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/arch/api/console.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_CONSOLE_HPP__ 2 | #define __ANARCH_API_CONSOLE_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | class Console : public ansa::Module { 9 | public: 10 | static Console & GetGlobal(); 11 | 12 | typedef enum { 13 | ColorBlack = 0, 14 | ColorBlue = 1, 15 | ColorGreen = 2, 16 | ColorCyan = 3, 17 | ColorRed = 4, 18 | ColorMagenta = 5, 19 | ColorBrown = 6, 20 | ColorLightGray = 7 21 | } Color; 22 | 23 | /** 24 | * @ambicritical 25 | */ 26 | virtual void PrintString(const char * string) = 0; 27 | 28 | /** 29 | * @ambicritical 30 | */ 31 | virtual void SetColor(Color color, bool bright) = 0; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/free-finder.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_FREE_FINDER_HPP__ 2 | #define __ANARCH_X64_FREE_FINDER_HPP__ 3 | 4 | #include "../page-table.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class FreeFinder : public ansa::NoCopy { 12 | public: 13 | FreeFinder(PageTable & pt); 14 | 15 | bool Alloc(VirtAddr &, size_t size, size_t align); 16 | void Free(VirtAddr, size_t size); 17 | 18 | void Reserve(VirtAddr addr, size_t size); 19 | 20 | protected: 21 | PageTable & pageTable; 22 | 23 | VirtAddr freeStart = 0; 24 | size_t freeSize = 0; 25 | 26 | void UpdateFreeRegion(); 27 | bool CanAllocate(size_t size, size_t align); 28 | }; 29 | 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/arch/x64/panic/panic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_PANIC_HPP__ 2 | #define __ANARCH_X64_PANIC_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class PanicModule : public ansa::Module { 13 | public: 14 | static void InitGlobal(); 15 | static PanicModule & GetGlobal(); 16 | 17 | void Panic(const char * msg) ANSA_NORETURN; 18 | 19 | protected: 20 | virtual void Initialize(); 21 | virtual ansa::DepList GetDependencies(); 22 | 23 | private: 24 | ansa::Atomic panicCount; 25 | 26 | void DistributeError(); 27 | static void WriteError(const char * msg); 28 | static void HaltCpu(); 29 | }; 30 | 31 | } 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/handler.s: -------------------------------------------------------------------------------- 1 | global AnarchRawSyscallHandler 2 | extern AnarchSyscallMainEntry 3 | 4 | AnarchRawSyscallHandler: 5 | swapgs ; get our CPU data section 6 | mov r10, rsp ; save the user stack 7 | mov rsp, [gs:0x8] ; syscallStack field 8 | 9 | ; push the old user stack pointer and the return address 10 | push r10 11 | push rcx 12 | 13 | ; set the 4th argument since this register was used by SYSCALL 14 | mov rcx, rbx 15 | 16 | ; standard System V ABI function; saves some regs for us 17 | call AnarchSyscallMainEntry ; sets RAX and RDX to return value 18 | 19 | pop rcx 20 | pop rsp 21 | 22 | mov r11, 0x200 23 | ; TODO: verify that RCX is canonical! THIS IS A SECURITY ISSUE 24 | 25 | swapgs 26 | o64 sysret 27 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/lapic-module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_LAPIC_MODULE_HPP__ 2 | #define __ANARCH_X64_LAPIC_MODULE_HPP__ 3 | 4 | #include "x2apic.hpp" 5 | #include "xapic.hpp" 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | namespace x64 { 12 | 13 | class LapicModule : public ansa::Module { 14 | public: 15 | static void InitGlobal(); 16 | static LapicModule & GetGlobal(); 17 | 18 | virtual Lapic & GetLapic(); // @critical 19 | 20 | protected: 21 | virtual ansa::DepList GetDependencies(); 22 | virtual void Initialize(); 23 | 24 | private: 25 | char xapicData[sizeof(XApic)] ANSA_ALIGNED(8); 26 | char x2apicData[sizeof(X2Apic)] ANSA_ALIGNED(8); 27 | }; 28 | 29 | } 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/arch/x64/clock/hpet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_HPET_HPP__ 2 | #define __ANARCH_X64_HPET_HPP__ 3 | 4 | #include "stoppable.hpp" 5 | #include "../acpi/hpet-table.hpp" 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class Hpet : public StoppableClock { 13 | public: 14 | Hpet(const HpetTable & info); // @noncritical 15 | 16 | // destructor not shown, but it's also @noncritical 17 | 18 | virtual void Start(); // @critical 19 | virtual void Stop(); // @critical 20 | 21 | virtual uint64_t GetTicks(); // @ambicritical 22 | virtual ansa::Rational GetMicrosPerTick(); // @ambicritical 23 | 24 | private: 25 | EasyMap map; 26 | ansa::Rational microsPerTick; 27 | }; 28 | 29 | } 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/arch/x64/public/multiboot-region-list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_MULTIBOOT_REGION_LIST_HPP__ 2 | #define __ANARCH_X64_MULTIBOOT_REGION_LIST_HPP__ 3 | 4 | #include "region-list.hpp" 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class MultibootRegionList : public RegionList { 11 | public: 12 | MultibootRegionList(void * mbootPtr); 13 | 14 | virtual const ANAlloc::RegionList & GetLowerRegions() const; 15 | virtual const ANAlloc::RegionList & GetUpperRegions() const; 16 | 17 | private: 18 | static const int MaximumCount = 8; 19 | 20 | ANAlloc::FixedRegionList lowerRegions; 21 | ANAlloc::FixedRegionList upperRegions; 22 | 23 | void AddRegion(const ANAlloc::Region & region); 24 | }; 25 | 26 | } 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/arch/x64/segments/tss.cpp: -------------------------------------------------------------------------------- 1 | #include "tss.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | TssDescriptor::TssDescriptor(Tss * tss) 8 | : limit_0(0x67), type(9), res0(0), dpl(0), present(1), limit_16(0), 9 | available(1), res1(0), granularity(0), res2(0) { 10 | // as much as I love initializer lists, I like code too. 11 | uint64_t ptrVal = (uint64_t)tss; 12 | base_0 = ptrVal & 0xffff; 13 | base_16 = (ptrVal >> 16) & 0xff; 14 | base_24 = (ptrVal >> 24) & 0xff; 15 | base_32 = ptrVal >> 0x20; 16 | } 17 | 18 | 19 | Tss * TssDescriptor::GetPointer() { 20 | uint64_t ptrVal = 0; 21 | ptrVal |= base_0; 22 | ptrVal |= base_16 << 16; 23 | ptrVal |= base_24 << 24; 24 | ptrVal |= (uint64_t)base_32 << 0x20; 25 | return (Tss *)ptrVal; 26 | } 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/irt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_IRT_HPP__ 2 | #define __ANARCH_X64_IRT_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class Irt : public ansa::Module { 13 | public: 14 | static void InitGlobal(); 15 | static Irt & GetGlobal(); 16 | 17 | void * Get(uint8_t idx); // @ambicritical 18 | void Set(uint8_t idx, void * r); // @ambicritical 19 | void Unset(uint8_t idx); // @ambicritical 20 | 21 | void ConfigurePicEoi(); 22 | void Configure(); 23 | 24 | protected: 25 | virtual ansa::DepList GetDependencies(); 26 | virtual void Initialize(); 27 | 28 | private: 29 | ansa::Atomic routines[0x100]; 30 | }; 31 | 32 | } 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_ACPI_MODULE_HPP__ 2 | #define __ANARCH_X64_ACPI_MODULE_HPP__ 3 | 4 | #include 5 | #include "acpi-root.hpp" 6 | #include "apic-table.hpp" 7 | #include "hpet-table.hpp" 8 | 9 | namespace anarch { 10 | 11 | namespace x64 { 12 | 13 | class AcpiModule : public ansa::Module { 14 | public: 15 | static void InitGlobal(); 16 | static AcpiModule & GetGlobal(); 17 | 18 | AcpiRoot & GetRoot(); 19 | ApicTable * GetApicTable(); 20 | HpetTable * GetHpetTable(); 21 | 22 | protected: 23 | virtual ansa::DepList GetDependencies(); 24 | virtual void Initialize(); 25 | 26 | private: 27 | AcpiRoot * root; 28 | ApicTable * apicTable = NULL; 29 | HpetTable * hpetTable = NULL; 30 | 31 | }; 32 | 33 | } 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/arch/api/state.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_STATE_HPP__ 2 | #define __ANARCH_API_STATE_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | class State : public ansa::NoCopy { 10 | public: 11 | // all @noncritical 12 | static State & NewKernel(void (*)()); 13 | static State & NewKernel(void (*)(void *), void *); 14 | static State & NewUser(void (*)()); 15 | static State & NewUser(void (*)(void *), void *); 16 | 17 | virtual void Delete() = 0; // @noncritical 18 | 19 | virtual void Resume() ANSA_NORETURN = 0; // @critical 20 | virtual void SuspendAndCall(void (*)()) = 0; // @critical 21 | virtual void SuspendAndCall(void (*)(void *), void *) = 0; // @critical 22 | 23 | protected: 24 | virtual ~State() {} 25 | }; 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/xapic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_XAPIC_HPP__ 2 | #define __ANARCH_X64_XAPIC_HPP__ 3 | 4 | #include "lapic.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class XApic : public Lapic { 13 | public: 14 | XApic(PhysAddr base); // @noncritical 15 | 16 | // destructor is not listed but is also @noncritical 17 | 18 | virtual uint64_t ReadReg(uint16_t reg); 19 | virtual void WriteReg(uint16_t reg, uint64_t value); 20 | virtual void Enable(); 21 | virtual uint32_t GetId(); 22 | virtual void SendIpi(uint32_t cpu, uint8_t vector, uint8_t mode, 23 | uint8_t level, uint8_t trigger); 24 | 25 | private: 26 | EasyMap map; 27 | PhysAddr base; 28 | }; 29 | 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-root.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi-root.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | namespace { 9 | 10 | uint32_t ReadPhysSize(PhysAddr addr) { 11 | uint32_t res; 12 | PhysCopy(&res, addr, 4); 13 | return res; 14 | } 15 | 16 | } 17 | 18 | AcpiRoot::AcpiRoot(PhysAddr tableBase) 19 | : tableSize(ReadPhysSize(tableBase + 4)), 20 | map(tableBase, tableSize) { 21 | } 22 | 23 | int AcpiRoot::FindTable(const char * name) { 24 | uint32_t num = *((uint32_t *)name); 25 | int count = GetCount(); 26 | for (int i = 0; i < count; i++) { 27 | PhysAddr tableAddr = GetTable(i); 28 | uint32_t typeNum; 29 | PhysCopy(&typeNum, tableAddr, 4); 30 | if (typeNum == num) { 31 | return i; 32 | } 33 | } 34 | return -1; 35 | } 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/arch/x64/state/state.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STATE_HPP__ 2 | #define __ANARCH_X64_STATE_HPP__ 3 | 4 | #include "../interrupts/isr-types.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class State : public anarch::State { 13 | public: 14 | static const size_t StackSize = 0x4000; 15 | 16 | State(uint64_t rip, uint64_t rdi, bool kernel); 17 | 18 | void * GetStackTop(); 19 | 20 | // from anarch::State 21 | virtual ~State(); 22 | virtual void Delete(); 23 | virtual void Resume() ANSA_NORETURN; 24 | virtual void SuspendAndCall(void (*)()); 25 | virtual void SuspendAndCall(void (*)(void *), void *); 26 | 27 | private: 28 | uint64_t rdi; 29 | IsrStack iretInfo; 30 | void * stackStart; 31 | }; 32 | 33 | } 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-root.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_ACPI_ROOT_HPP__ 2 | #define __ANARCH_X64_ACPI_ROOT_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class AcpiRoot : public ansa::NoCopy { 12 | public: 13 | AcpiRoot(PhysAddr tableBase); // @noncritical 14 | 15 | // destructor is not declared but is also @noncritical 16 | 17 | virtual int GetCount() = 0; // @ambicritical 18 | virtual PhysAddr GetTable(int i) = 0; // @ambicritical 19 | 20 | /** 21 | * Find the index of the table going by the specified 4-letter name. 22 | * @return -1 if not found, an index otherwise 23 | * @ambicritical 24 | */ 25 | virtual int FindTable(const char * name); 26 | 27 | protected: 28 | size_t tableSize; 29 | EasyMap map; 30 | }; 31 | 32 | } 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/arch/api/syscall-args.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_SYSCALL_ARGS_HPP__ 2 | #define __ANARCH_API_SYSCALL_ARGS_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | /** 11 | * A list of arguments passed to a system call. This class must be able to 12 | * store up to five arguments. If you pop more arguments than were pushed, an 13 | * undefined value will be returned OR a page fault will be triggered. 14 | */ 15 | class SyscallArgs { 16 | public: 17 | virtual bool PopBool() = 0; 18 | virtual int PopInt() = 0; 19 | virtual uint32_t PopUInt32() = 0; 20 | virtual uint64_t PopUInt64() = 0; 21 | virtual PhysAddr PopPhysAddr() = 0; 22 | virtual VirtAddr PopVirtAddr() = 0; 23 | virtual PhysSize PopPhysSize() = 0; 24 | virtual size_t PopVirtSize() = 0; 25 | }; 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/arch/api/virtual-allocator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_VIRTUAL_ALLOCATOR_HPP__ 2 | #define __ANARCH_API_VIRTUAL_ALLOCATOR_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | class VirtualAllocator : public ansa::NoCopy { 12 | public: 13 | virtual bool Alloc(void *& addr, size_t size) = 0; // @noncritical 14 | virtual void Free(void * addr) = 0; // @noncritical 15 | virtual bool Owns(void * ptr) = 0; // @noncritical 16 | 17 | template 18 | T * New(Args... args) { 19 | void * buf; 20 | if (!Alloc(buf, sizeof(T))) return NULL; 21 | return new(buf) T(args...); 22 | } 23 | 24 | template 25 | void Delete(T * ptr) { 26 | ptr->~T(); 27 | Free((void *)ptr); 28 | } 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/arch/x64/clock/module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_CLOCK_MODULE_HPP__ 2 | #define __ANARCH_X64_CLOCK_MODULE_HPP__ 3 | 4 | #include 5 | #include 6 | #include "stoppable.hpp" 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class ClockModule : public anarch::ClockModule { 13 | public: 14 | static void InitGlobal(); 15 | static ClockModule & GetGlobal(); 16 | 17 | // try to setup the Time Stamp Counter as a system clock 18 | virtual void TryTsc(); // @noncritical 19 | virtual bool IsUsingTsc(); // @ambicritical 20 | 21 | // anarch::ClockModule 22 | virtual Clock & GetClock(); 23 | 24 | protected: 25 | virtual ansa::DepList GetDependencies(); 26 | virtual void Initialize(); 27 | 28 | private: 29 | StoppableClock * clock = NULL; 30 | bool isTsc = false; 31 | }; 32 | 33 | } 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/arch/x64/domains/domain.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_DOMAIN_HPP__ 2 | #define __ANARCH_X64_DOMAIN_HPP__ 3 | 4 | #include "../smp/cpu.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class Domain : public anarch::Domain { 12 | public: 13 | Domain(int capacity); 14 | ~Domain(); 15 | 16 | Cpu & GetCpu(int idx); // @ambicritical 17 | int InitNewCpu(); // @noncritical 18 | 19 | // anarch::Domain 20 | virtual anarch::Domain & GetSibling(int); 21 | virtual int GetThreadCount(); 22 | virtual Thread & GetThread(int idx); 23 | virtual Allocator & GetAllocator(); 24 | virtual VirtualAllocator & GetVirtualAllocator(); 25 | 26 | private: 27 | Allocator & allocator; 28 | VirtualAllocator & virtualAllocator; 29 | 30 | char * cpuData; 31 | int capacity; 32 | int count = 0; 33 | }; 34 | 35 | } 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/hpet-table.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_HPET_TABLE_HPP__ 2 | #define __ANARCH_X64_HPET_TABLE_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | struct HpetTable { 12 | struct Address { 13 | uint8_t addressSpaceId; 14 | uint8_t registerBitWidth; 15 | uint8_t registerBitOffset; 16 | uint8_t reserved; 17 | uint64_t address; 18 | } ANSA_PACKED; 19 | 20 | uint32_t signature; // 'HPET' 21 | uint32_t length; 22 | uint8_t revision; 23 | uint8_t checksum; 24 | char oemid[6]; 25 | uint64_t oemTableId; 26 | uint32_t oemRevision; 27 | uint32_t creatorId; 28 | uint32_t creatorRevision; 29 | 30 | uint32_t blockID; 31 | Address address; 32 | uint8_t hpetNumber; 33 | uint16_t counterMinimum; 34 | uint8_t pageProtectionAndOEM; 35 | }; 36 | 37 | } 38 | 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/arch/x64/public/multiboot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_MULTIBOOT_HPP__ 2 | #define __ANARCH_X64_MULTIBOOT_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class MultibootBootInfo { 12 | public: 13 | uint32_t flags; 14 | uint32_t mem_lower; 15 | uint32_t mem_upper; 16 | uint32_t boot_device; 17 | uint32_t cmdline; 18 | uint32_t mods_count; 19 | uint32_t mods_addr; 20 | char syms[0x10]; 21 | uint32_t mmap_length; 22 | uint32_t mmap_addr; 23 | uint32_t drives_length; 24 | uint32_t drives_addr; 25 | uint32_t config_table; 26 | uint32_t boot_loader_name; 27 | uint32_t apm_table; 28 | } ANSA_PACKED; 29 | 30 | class MultibootMmapInfo { 31 | public: 32 | uint32_t size; 33 | uint64_t base_addr; 34 | uint64_t length; 35 | uint32_t type; 36 | } ANSA_PACKED; 37 | 38 | } 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/memory/easy-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_EASY_MAP_HPP__ 2 | #define __ANARCH_EASY_MAP_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | /** 10 | * This class makes it easy to map arbitrary misaligned regions of physical 11 | * memory to virtual memory. Additionally, it can provide a simple scoping 12 | * mechanism for memory mapping (if you're into that kinda thing). 13 | */ 14 | class EasyMap : public ansa::NoCopy { 15 | private: 16 | VirtAddr mapStart; 17 | size_t pageSize; 18 | size_t pageAlign; 19 | size_t pageCount; 20 | 21 | VirtAddr start; 22 | 23 | public: 24 | /** 25 | * @noncritical 26 | */ 27 | EasyMap(PhysAddr start, size_t size); 28 | 29 | /** 30 | * @noncritical 31 | */ 32 | ~EasyMap(); 33 | 34 | /** 35 | * @ambicritical 36 | */ 37 | VirtAddr GetStart() const; 38 | }; 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/global-malloc.cpp: -------------------------------------------------------------------------------- 1 | #include "global-malloc.hpp" 2 | #include "global-map.hpp" 3 | #include 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | namespace { 11 | 12 | GlobalMalloc gMalloc; 13 | 14 | } 15 | 16 | void GlobalMalloc::InitGlobal() { 17 | new(&gMalloc) GlobalMalloc(); 18 | } 19 | 20 | GlobalMalloc & GlobalMalloc::GetGlobal() { 21 | return gMalloc; 22 | } 23 | 24 | VirtualAllocator & GlobalMalloc::GetAllocator() { 25 | return *(Malloc *)mallocBuf; 26 | } 27 | 28 | ansa::DepList GlobalMalloc::GetDependencies() { 29 | return ansa::DepList(&GlobalMap::GetGlobal(), &StreamModule::GetGlobal()); 30 | } 31 | 32 | void GlobalMalloc::Initialize() { 33 | cout << "Initializing GlobalMalloc..."; 34 | Malloc * mallocPtr = (Malloc *)mallocBuf; 35 | new(mallocPtr) Malloc(0x200000, GlobalMap::GetGlobal().GetPageAllocator()); 36 | cout << " [OK]" << endl; 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/util/dummy-api/console.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_DUMMY_CONSOLE_HPP__ 2 | #define __ANARCH_DUMMY_CONSOLE_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace dummy { 10 | 11 | class LogConsole : public Console { 12 | public: 13 | static const size_t Capacity = 25 * 80; 14 | 15 | static LogConsole & GetGlobal(); // no need for InitGlobal on real platform 16 | 17 | virtual void PrintString(const char * str); 18 | 19 | virtual void SetColor(Color, bool) { 20 | } 21 | 22 | inline char * GetBacklog() { 23 | return backlog; 24 | } 25 | 26 | inline size_t GetBacklogSize() { 27 | return backlogSize; 28 | } 29 | 30 | protected: 31 | char backlog[Capacity]; 32 | size_t backlogSize = 0; 33 | 34 | virtual ansa::DepList GetDependencies() { 35 | return ansa::DepList(); 36 | } 37 | 38 | virtual void Initialize(); 39 | }; 40 | 41 | } 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/arch/x64/segments/tss.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_TSS_HPP__ 2 | #define __ANARCH_X64_TSS_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | struct Tss { 12 | uint32_t res0; 13 | uint64_t rsp[3]; 14 | uint64_t res1; 15 | uint64_t ist[7]; 16 | uint64_t res2; 17 | uint16_t res3; 18 | uint16_t ioplBase; 19 | } ANSA_PACKED; 20 | 21 | struct TssDescriptor { 22 | uint16_t limit_0; 23 | uint16_t base_0; 24 | uint8_t base_16; 25 | unsigned type : 4; 26 | unsigned res0 : 1; 27 | unsigned dpl : 2; 28 | unsigned present : 1; 29 | unsigned limit_16 : 4; 30 | unsigned available : 1; 31 | unsigned res1 : 2; 32 | unsigned granularity : 1; 33 | uint8_t base_24; 34 | uint32_t base_32; 35 | uint32_t res2; 36 | 37 | TssDescriptor(Tss * tss); 38 | Tss * GetPointer(); 39 | } ANSA_PACKED; 40 | 41 | static_assert(sizeof(TssDescriptor) == 16, "Invalid TSS descriptor size"); 42 | 43 | } 44 | 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/arch/x64/segments/short-descriptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_SHORT_DESCRIPTOR_HPP__ 2 | #define __ANARCH_X64_SHORT_DESCRIPTOR_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | struct ShortDescriptor { 12 | ShortDescriptor(bool privileged, bool executable); 13 | 14 | uint16_t limit; 15 | uint16_t baseLow; 16 | uint8_t baseMid; 17 | 18 | // access byte 19 | unsigned accessBit : 1; 20 | unsigned writable : 1; 21 | unsigned direction : 1; 22 | unsigned executable : 1; 23 | unsigned reservedOne : 1; 24 | unsigned privilege : 2; 25 | unsigned present : 1; 26 | 27 | unsigned limitHigh : 4; 28 | 29 | // flags half-byte 30 | unsigned reservedZero : 1; 31 | unsigned longMode : 1; 32 | unsigned size : 1; 33 | unsigned granularity : 1; 34 | 35 | uint8_t baseHigh; 36 | } ANSA_PACKED; 37 | 38 | static_assert(sizeof(ShortDescriptor) == 8, "Invalid short descriptor size"); 39 | 40 | } 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/arch/x64/segments/local-segment.cpp: -------------------------------------------------------------------------------- 1 | #include "local-segment.hpp" 2 | #include "../common.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | void LocalSegment::Swap() { 10 | AssertCritical(); 11 | __asm__ __volatile__("swapgs"); 12 | } 13 | 14 | uint64_t LocalSegment::Read() { 15 | AssertCritical(); 16 | return ReadMsr(0xc0000101); 17 | } 18 | 19 | void LocalSegment::Write(uint64_t value) { 20 | AssertCritical(); 21 | WriteMsr(0xc0000101, value); 22 | } 23 | 24 | LocalSegment::SwapScope::SwapScope(uint8_t vector, const IsrStack & stack) { 25 | if (vector != 0x2 && vector != 0x12) { 26 | didSwap = (stack.cs & 3) != 0; 27 | } else { 28 | // TODO: here, possbily use the Task Register to identify the CPU 29 | didSwap = (LocalSegment::Read() == 0); 30 | } 31 | if (didSwap) { 32 | LocalSegment::Swap(); 33 | } 34 | } 35 | 36 | LocalSegment::SwapScope::~SwapScope() { 37 | if (didSwap) { 38 | LocalSegment::Swap(); 39 | } 40 | } 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/arch/x64/pmm/step-allocator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STEP_ALLOCATOR_HPP__ 2 | #define __ANARCH_X64_STEP_ALLOCATOR_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | /** 11 | * A simple allocator for temporary use while the OS is initializing. This 12 | * allocator is not appropriate for permanent use because it does not support 13 | * any operation other than simple allocation. 14 | */ 15 | class StepAllocator : public Allocator { 16 | public: 17 | StepAllocator(PhysAddr start); 18 | 19 | virtual PhysAddr GetLastAddress(); 20 | 21 | // anarch::Allocator 22 | virtual bool Alloc(PhysAddr & addr, PhysSize size, PhysSize align); 23 | virtual void Free(PhysAddr); // unsupported 24 | virtual bool Owns(PhysAddr); // unsupported 25 | virtual PhysSize Used(); // unsupported 26 | virtual PhysSize Available(); // unsupported 27 | virtual PhysSize Total(); // unsupported 28 | 29 | private: 30 | PhysAddr lastAddr; 31 | }; 32 | 33 | } 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/arch/x64/timer/lapic-timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_LAPIC_TIMER_HPP__ 2 | #define __ANARCH_X64_LAPIC_TIMER_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class TimerModule; 12 | 13 | class LapicTimer : public anarch::Timer { 14 | public: 15 | LapicTimer(); // zero initialize ticksPerMicro 16 | 17 | // anarch::Timer 18 | virtual ansa::Rational GetTicksPerMicro(); 19 | virtual void SetTimeout(uint64_t ticks, void (* func)()); 20 | virtual void SetTimeout(uint64_t, void (*)(void *), void *); 21 | virtual void ClearTimeout(); 22 | virtual void WaitTimeout() ANSA_NORETURN; 23 | 24 | protected: 25 | ansa::Rational ticksPerMicro; 26 | ansa::Atomic calibrated; 27 | 28 | static void GeneralTimerCallback(); 29 | 30 | friend class TimerModule; 31 | 32 | private: 33 | bool isExpecting = false; 34 | void (* callbackFunction)(void *); 35 | void * callbackArg; 36 | }; 37 | 38 | } 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/idt.cpp: -------------------------------------------------------------------------------- 1 | #include "idt.hpp" 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | namespace { 10 | 11 | Idt gIdt; 12 | 13 | } 14 | 15 | void Idt::InitGlobal() { 16 | new(&gIdt) Idt(); 17 | } 18 | 19 | Idt & Idt::GetGlobal() { 20 | return gIdt; 21 | } 22 | 23 | void Idt::SetEntry(int idx, void * fn, uint8_t flags) { 24 | handlers[idx].function = (uint64_t)fn; 25 | handlers[idx].argument = (uint64_t)idx; 26 | entries[idx].SetOffset((uint64_t)&handlers[idx]); 27 | entries[idx].flags = flags; 28 | } 29 | 30 | void Idt::SetIst(int idx, uint8_t ist) { 31 | entries[idx].ist = ist; 32 | } 33 | 34 | void Idt::Set() { 35 | idtPtr.limit = 0xfff; // TODO: see what the real maximum should be 36 | idtPtr.virtualAddress = (uint64_t)entries; 37 | assert(!((uint64_t)&idtPtr & 0x7)); 38 | assert(!((uint64_t)entries & 0x7)); 39 | __asm__ __volatile__("lidt (%0)" : : "r" (&idtPtr)); 40 | } 41 | 42 | ansa::DepList Idt::GetDependencies() { 43 | return ansa::DepList(); 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/arch/x64/domains/domain-list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_X64_DOMAIN_LIST_HPP__ 2 | #define __ARCH_X64_DOMAIN_LIST_HPP__ 3 | 4 | #include "domain.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | /** 13 | * Since the x86-64 anarch APIs do not yet support NUMA, the DomainList simply 14 | * initializes every CPU on the system and throws it into one Domain. 15 | */ 16 | class DomainList : public anarch::DomainList { 17 | public: 18 | static void InitGlobal(); 19 | static DomainList & GetGlobal(); 20 | 21 | virtual int GetCount(); 22 | virtual Domain & operator[](int idx); 23 | 24 | protected: 25 | virtual ansa::DepList GetDependencies(); 26 | virtual ansa::DepList GetSuperDependencies(); 27 | virtual void Initialize(); 28 | 29 | private: 30 | Domain * mainDomain; 31 | CriticalLock initLock; 32 | bool initFlag; 33 | 34 | void StartCpus(); 35 | void BootstrapCpu(uint32_t apicId); 36 | static void CpuEntrance(); 37 | static void CpuStall(); 38 | }; 39 | 40 | } 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/x2apic.cpp: -------------------------------------------------------------------------------- 1 | #include "x2apic.hpp" 2 | #include "../../common.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | uint64_t X2Apic::ReadReg(uint16_t reg) { 10 | AssertCritical(); 11 | return ReadMsr((uint32_t)reg + 0x800); 12 | } 13 | 14 | void X2Apic::WriteReg(uint16_t reg, uint64_t value) { 15 | AssertCritical(); 16 | WriteMsr((uint32_t)reg + 0x800, value); 17 | } 18 | 19 | void X2Apic::Enable() { 20 | AssertCritical(); 21 | uint64_t flags = ReadMsr(0x1b) & 0xf00; 22 | flags |= 3 << 10; 23 | WriteMsr(0x1b, flags); 24 | } 25 | 26 | uint32_t X2Apic::GetId() { 27 | AssertCritical(); 28 | return ReadReg(RegApicId); 29 | } 30 | 31 | void X2Apic::SendIpi(uint32_t cpu, uint8_t vector, uint8_t mode, uint8_t level, 32 | uint8_t trigger) { 33 | AssertCritical(); 34 | uint64_t value = 0; 35 | value = (uint64_t)vector | ((uint64_t)mode << 8); 36 | value |= ((uint64_t)level << 0xe) | ((uint64_t)trigger << 0xf); 37 | value |= ((uint64_t)cpu << 0x20); 38 | WriteReg(RegIcr, value); 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/arch/x64/public/region-list.cpp: -------------------------------------------------------------------------------- 1 | #include "region-list.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | const ANAlloc::Region * RegionList::FindRegion(PhysAddr addr) const { 8 | for (int i = 0; i < GetLowerRegions().GetCount(); i++) { 9 | if (GetLowerRegions()[i].Contains((ANAlloc::UInt)addr)) { 10 | return &GetLowerRegions()[i]; 11 | } 12 | } 13 | for (int i = 0; i < GetUpperRegions().GetCount(); i++) { 14 | if (GetUpperRegions()[i].Contains((ANAlloc::UInt)addr)) { 15 | return &GetUpperRegions()[i]; 16 | } 17 | } 18 | return NULL; 19 | } 20 | 21 | const ANAlloc::Region * RegionList::NextRegion(const ANAlloc::Region * reg) 22 | const { 23 | for (int i = 0; i < GetLowerRegions().GetCount(); i++) { 24 | if (GetLowerRegions()[i].GetStart() > reg->GetStart()) { 25 | return &GetLowerRegions()[i]; 26 | } 27 | } 28 | for (int i = 0; i < GetUpperRegions().GetCount(); i++) { 29 | if (GetUpperRegions()[i].GetStart() > reg->GetStart()) { 30 | return &GetUpperRegions()[i]; 31 | } 32 | } 33 | return NULL; 34 | } 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/args.cpp: -------------------------------------------------------------------------------- 1 | #include "args.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | SyscallArgs::SyscallArgs(uint64_t arg1, uint64_t arg2, uint64_t arg3, 9 | uint64_t arg4, uint64_t arg5) { 10 | arguments[0] = arg1; 11 | arguments[1] = arg2; 12 | arguments[2] = arg3; 13 | arguments[3] = arg4; 14 | arguments[4] = arg5; 15 | } 16 | 17 | bool SyscallArgs::PopBool() { 18 | return PopUInt64() != 0; 19 | } 20 | 21 | int SyscallArgs::PopInt() { 22 | return (int)PopUInt64(); 23 | } 24 | 25 | uint32_t SyscallArgs::PopUInt32() { 26 | return (uint32_t)PopUInt64(); 27 | } 28 | 29 | uint64_t SyscallArgs::PopUInt64() { 30 | assert(idx < 5); 31 | return arguments[idx++]; 32 | } 33 | 34 | PhysAddr SyscallArgs::PopPhysAddr() { 35 | return PopUInt64(); 36 | } 37 | 38 | VirtAddr SyscallArgs::PopVirtAddr() { 39 | return PopUInt64(); 40 | } 41 | 42 | PhysSize SyscallArgs::PopPhysSize() { 43 | return PopUInt64(); 44 | } 45 | 46 | size_t SyscallArgs::PopVirtSize() { 47 | return (size_t)PopUInt64(); 48 | } 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/arch/x64/critical/module.cpp: -------------------------------------------------------------------------------- 1 | #include "module.hpp" 2 | #include "../interrupts/pic.hpp" 3 | #include "../interrupts/irt.hpp" 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | namespace { 12 | 13 | CriticalModule gCriticalModule; 14 | 15 | } 16 | 17 | void CriticalModule::InitGlobal() { 18 | new(&gCriticalModule) CriticalModule(); 19 | } 20 | 21 | CriticalModule & CriticalModule::GetGlobal() { 22 | return gCriticalModule; 23 | } 24 | 25 | ansa::DepList CriticalModule::GetDependencies() { 26 | return ansa::DepList(&Irt::GetGlobal(), &Pic::GetGlobal(), 27 | &StreamModule::GetGlobal()); 28 | } 29 | 30 | void CriticalModule::Initialize() { 31 | cout << "Initializing criticality subsystem..."; 32 | 33 | Irt::GetGlobal().ConfigurePicEoi(); 34 | __asm__ __volatile__("sti\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" 35 | "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\ncli"); 36 | Irt::GetGlobal().Configure(); 37 | 38 | __asm__ __volatile__("sti"); 39 | cout << " [OK]" << endl; 40 | } 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/arch/x64/clock/hpet.cpp: -------------------------------------------------------------------------------- 1 | #include "hpet.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | namespace { 9 | 10 | uint64_t ExtractTicksPerMin(EasyMap & map) { 11 | volatile uint64_t * regs = (volatile uint64_t *)map.GetStart(); 12 | return 60000000000000000L / (regs[0] >> 0x20); 13 | } 14 | 15 | } 16 | 17 | Hpet::Hpet(const HpetTable & info) 18 | : map(info.address.address, 0x1000), 19 | microsPerTick(60000000, ExtractTicksPerMin(map)) { 20 | } 21 | 22 | void Hpet::Start() { 23 | AssertNoncritical(); 24 | ScopedCritical critical; 25 | volatile uint64_t * regs = (volatile uint64_t *)map.GetStart(); 26 | regs[2] |= 1; 27 | } 28 | 29 | void Hpet::Stop() { 30 | AssertNoncritical(); 31 | ScopedCritical critical; 32 | volatile uint64_t * regs = (volatile uint64_t *)map.GetStart(); 33 | regs[2] &= ~(uint64_t)1; 34 | } 35 | 36 | uint64_t Hpet::GetTicks() { 37 | volatile uint64_t * regs = (volatile uint64_t *)map.GetStart(); 38 | return regs[0x1e]; 39 | } 40 | 41 | ansa::Rational Hpet::GetMicrosPerTick() { 42 | return microsPerTick; 43 | } 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/arch/x64/segments/gdt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_GDT_HPP__ 2 | #define __ANARCH_X64_GDT_HPP__ 3 | 4 | #include "tss.hpp" 5 | #include "short-descriptor.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | namespace x64 { 13 | 14 | class Gdt : public ansa::Module { 15 | public: 16 | struct Pointer { 17 | uint16_t limit; 18 | uint64_t start; 19 | 20 | static Pointer GetCurrent(); // @critical 21 | } ANSA_PACKED; 22 | 23 | static void InitGlobal(); 24 | static Gdt & GetGlobal(); 25 | 26 | uint16_t PushShortDescriptor(const ShortDescriptor & desc); 27 | uint16_t PushTssDescriptor(const TssDescriptor & desc); 28 | 29 | /** 30 | * Load this GDT on the current CPU. 31 | * @critical 32 | */ 33 | void Set(); 34 | 35 | /** 36 | * Get the GDT Pointer for this GDT. 37 | */ 38 | Pointer GetPointer(); 39 | 40 | protected: 41 | virtual ansa::DepList GetDependencies(); 42 | virtual void Initialize(); 43 | 44 | private: 45 | void * buffer; 46 | size_t amountUsed; 47 | }; 48 | 49 | } 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/map-setup.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_MAP_SETUP_HPP__ 2 | #define __ANARCH_X64_MAP_SETUP_HPP__ 3 | 4 | #include "free-finder.hpp" 5 | #include "../page-table.hpp" 6 | #include "../../pmm/buddy-allocator.hpp" 7 | #include "../../pmm/step-allocator.hpp" 8 | #include 9 | 10 | namespace anarch { 11 | 12 | namespace x64 { 13 | 14 | /** 15 | * Configure the GlobalMap nice and easy 16 | */ 17 | class MapSetup : public ansa::NoCopy { 18 | public: 19 | MapSetup(); 20 | 21 | void GenerateMap(); 22 | void GeneratePageTable(); 23 | void GenerateFreeFinder(); 24 | void GenerateBuddyAllocator(); 25 | 26 | PageTable * GetPageTable(); 27 | FreeFinder * GetFreeFinder(); 28 | BuddyAllocator * GetBuddyAllocator(); 29 | 30 | PhysAddr GetPdpt(); 31 | 32 | private: 33 | PhysAddr kernelEnd; 34 | PhysAddr reservedEnd; 35 | StepAllocator stepAllocator; 36 | 37 | PhysAddr pdpt, pml4; 38 | int pdtOffset = 0; 39 | int pdptOffset = 0; 40 | PhysAddr currentPDT = 0; 41 | VirtAddr firstUnmapped = 0; 42 | 43 | void MapNext(size_t & linearSize); 44 | }; 45 | 46 | } 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/arch/api/clock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_CLOCK_HPP__ 2 | #define __ANARCH_API_CLOCK_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | class Clock : public ansa::NoCopy { 11 | public: 12 | /** 13 | * Returns the time in "ticks" 14 | * @ambicritical 15 | */ 16 | virtual uint64_t GetTicks() = 0; 17 | 18 | /** 19 | * Returns a ratio: micros/tick 20 | * @ambicritical 21 | */ 22 | virtual ansa::Rational GetMicrosPerTick() = 0; 23 | 24 | /** 25 | * Uses the ratio from GetMicrosPerTick() with GetTicks(). 26 | * @ambicritical 27 | */ 28 | virtual uint64_t GetMicros(); 29 | 30 | /** 31 | * Sleep until GetTicks() returns at least a certain value. 32 | * @noncritical 33 | */ 34 | virtual void WaitUntil(uint64_t ticks); 35 | 36 | /** 37 | * Sleep for a certain number of ticks. 38 | * @noncritical 39 | */ 40 | virtual void Sleep(uint64_t ticks); 41 | 42 | /** 43 | * Sleep for a certain number of microseconds. 44 | * @noncritical 45 | */ 46 | virtual void MicroSleep(uint64_t micros); 47 | 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/module.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_SYSCALL_MODULE_HPP__ 2 | #define __ANARCH_X64_SYSCALL_MODULE_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | anarch::SyscallRet AnarchSyscallMainEntry(uint64_t, uint64_t, uint64_t, 9 | uint64_t, uint64_t, uint64_t) 10 | __asm__("AnarchSyscallMainEntry"); 11 | 12 | namespace anarch { 13 | 14 | namespace x64 { 15 | 16 | class SyscallModule : public anarch::SyscallModule { 17 | public: 18 | static const uint32_t MsrSTAR = 0xC0000081; 19 | static const uint32_t MsrLSTAR = 0xC0000082; 20 | static const uint32_t MsrSFMask = 0xC0000084; 21 | 22 | static void InitGlobal(); 23 | static SyscallModule & GetGlobal(); 24 | 25 | virtual void SetHandler(SyscallHandler handler); 26 | SyscallHandler GetHandler(); 27 | 28 | protected: 29 | virtual ansa::DepList GetDependencies(); 30 | virtual void Initialize(); 31 | 32 | private: 33 | SyscallHandler handler = NULL; 34 | ansa::Atomic initCount; 35 | 36 | static void SetCpuRegisters(); 37 | }; 38 | 39 | } 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/util/stream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_UTIL_STREAM_HPP__ 2 | #define __ANARCH_UTIL_STREAM_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | class StreamModule : public ansa::Module { 9 | public: 10 | static void InitGlobal(); 11 | static StreamModule & GetGlobal(); 12 | 13 | protected: 14 | ansa::DepList GetDependencies(); 15 | virtual void Initialize(); 16 | }; 17 | 18 | class OutStream { 19 | public: 20 | virtual void Puts(const char * string) = 0; 21 | }; 22 | 23 | class ConsoleOutStream : public OutStream { 24 | public: 25 | virtual void Puts(const char * string); 26 | }; 27 | 28 | class ConsoleErrorStream : public OutStream { 29 | public: 30 | virtual void Puts(const char * string); 31 | }; 32 | 33 | OutStream & operator<<(OutStream &, unsigned char); 34 | OutStream & operator<<(OutStream &, unsigned short); 35 | OutStream & operator<<(OutStream &, unsigned int); 36 | OutStream & operator<<(OutStream &, unsigned long); 37 | OutStream & operator<<(OutStream &, unsigned long long); 38 | OutStream & operator<<(OutStream &, const char *); 39 | 40 | extern ConsoleOutStream cout; 41 | extern ConsoleErrorStream cerr; 42 | extern const char * endl; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/arch/api/user-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_USER_MAP_HPP__ 2 | #define __ANARCH_API_USER_MAP_HPP__ 3 | 4 | #include "memory-map.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | class UserMap : public MemoryMap { 10 | public: 11 | // both @noncritical 12 | static UserMap & New(); 13 | virtual void Delete() = 0; 14 | 15 | // all @ambicritical 16 | static int GetPageSizeCount(); 17 | static size_t GetPageSize(int); 18 | static size_t GetPageSizeAlign(int); 19 | static Capabilities GetCapabilities(); 20 | 21 | /** 22 | * Copy user memory to kernel memory. A normal memcpy() cannot be used 23 | * because a task's kernel thread can access memory that the normal thread 24 | * cannot (namely, kernel memory). This method should generate an artificial 25 | * page fault if it detects any sort of illegal access. 26 | * @noncritical 27 | */ 28 | virtual void CopyToKernel(void * dest, VirtAddr start, size_t size) = 0; 29 | 30 | /** 31 | * Like CopyToKernel(), but copies the other way. 32 | * @noncritical 33 | */ 34 | virtual void CopyFromKernel(VirtAddr dest, void * start, size_t size) = 0; 35 | 36 | protected: 37 | virtual ~UserMap() {} 38 | }; 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/memory/malloc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_MALLOC_HPP__ 2 | #define __ANARCH_MALLOC_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | /** 12 | * This class provides VirtualAllocator functionality using analloc2 and 13 | * wrapping a physical allocator. An architecture may choose to use this, or an 14 | * operating system kernel itself. 15 | */ 16 | class Malloc : public VirtualAllocator { 17 | public: 18 | Malloc(size_t poolSize, Allocator & allocator, bool bigPages = true); 19 | virtual ~Malloc(); // @noncritical 20 | 21 | virtual bool Alloc(void *& addr, size_t size); // @noncritical 22 | virtual void Free(void * addr); // @noncritical 23 | virtual bool Owns(void * ptr); // @noncritical 24 | 25 | protected: 26 | size_t poolSize; 27 | bool bigPages; 28 | 29 | struct Segment { 30 | ANAlloc::Malloc * allocator; 31 | Segment * next; 32 | NoncriticalLock lock; 33 | }; 34 | 35 | Allocator & allocator; 36 | Segment * firstSegment = NULL; 37 | NoncriticalLock firstLock; 38 | 39 | bool AllocNoNewSegment(void *& addr, size_t size); 40 | bool CreateSegment(); 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/tlb.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_Tlb_HPP__ 2 | #define __ANARCH_X64_Tlb_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class Tlb : public ansa::Module { 13 | public: 14 | static void Invlpg(VirtAddr addr); // @critical 15 | static void Invlpgs(VirtAddr, size_t); // @critical 16 | 17 | static void InitGlobal(); 18 | static Tlb & GetGlobal(); 19 | 20 | /** 21 | * Call this with `NULL` to indicate the global map. 22 | * @critical 23 | */ 24 | virtual void WillSetAddressSpace(MemoryMap * map); 25 | 26 | /** 27 | * Distribute a TLB flush for the current map. If the memory is in the 28 | * kernel's address space (< 0x8000000000), it will be distributed to every 29 | * CPU. 30 | * @noncritical 31 | */ 32 | virtual void DistributeInvlpg(VirtAddr start, size_t size); 33 | 34 | protected: 35 | ansa::DepList GetDependencies(); 36 | virtual void Initialize(); 37 | 38 | private: 39 | NoncriticalLock lock; 40 | static void HandleNotification(); 41 | void DistributeKernel(VirtAddr, size_t); // @critical 42 | void DistributeUser(VirtAddr, size_t); // @critical 43 | }; 44 | 45 | } 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/arch/x64/console/text-console.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_TEXT_CONSOLE_HPP__ 2 | #define __ANARCH_X64_TEXT_CONSOLE_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | /** 12 | * Simple, temporary implementation of the text-mode console. I will use this 13 | * until I come up with a better set of abstractions to support graphics modes. 14 | */ 15 | class TextConsole : public Console { 16 | public: 17 | static void InitGlobal(); 18 | static TextConsole & GetGlobal(); 19 | 20 | int GetWidth(); 21 | int GetHeight(); 22 | uint16_t * GetBuffer(); 23 | 24 | virtual void PrintString(const char * string); 25 | virtual void SetColor(Color color, bool bright); 26 | 27 | protected: 28 | virtual ansa::DepList GetDependencies(); 29 | virtual void Initialize(); 30 | 31 | private: 32 | uint8_t color = 0xa; 33 | int x = 0; 34 | int y = 0; 35 | CriticalLock lock; 36 | 37 | void PrintNewline(); 38 | void PrintCarriageReturn(); 39 | void PrintBackspace(); 40 | void PrintCharacter(unsigned char theChar); 41 | uint16_t GetBufferIndex(); 42 | uint16_t & CurrentCharacter(); 43 | 44 | void PositionCursor(); 45 | void ScrollUp(); 46 | }; 47 | 48 | } 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/arch/x64/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | void OutB(uint16_t port, uint8_t byte) { 9 | AssertCritical(); 10 | __asm__("outb %%al, %%dx" : : "a" (byte), "d" (port)); 11 | } 12 | 13 | void CpuID(uint32_t eax, uint32_t * ebx, uint32_t * edx, uint32_t * ecx) { 14 | AssertCritical(); 15 | uint32_t ebxIn = ebx ? *ebx : 0; 16 | uint32_t ecxIn = ecx ? *ecx : 0; 17 | uint32_t edxIn = edx ? *edx : 0; 18 | uint64_t rbxOut, rcxOut, rdxOut; 19 | __asm__("cpuid" 20 | : "=b" (rbxOut), "=c" (rcxOut), "=d" (rdxOut) 21 | : "b" (ebxIn), "c" (ecxIn), "d" (edxIn), "a" (eax)); 22 | if (ebx) *ebx = (uint32_t)rbxOut; 23 | if (ecx) *ecx = (uint32_t)rcxOut; 24 | if (edx) *edx = (uint32_t)rdxOut; 25 | } 26 | 27 | uint64_t ReadMsr(uint32_t cell) { 28 | AssertCritical(); 29 | uint64_t higher; 30 | uint64_t lower; 31 | __asm__("rdmsr" 32 | : "=d" (higher), "=a" (lower) 33 | : "c" (cell)); 34 | return (higher << 0x20) | lower; 35 | } 36 | 37 | void WriteMsr(uint32_t cell, uint64_t value) { 38 | AssertCritical(); 39 | uint64_t lower = value & 0xffffffff; 40 | uint64_t higher = value >> 0x20; 41 | __asm__("wrmsr" : : "c" (cell), "d" (higher), "a" (lower)); 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/arch/api/timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_TIMER_HPP__ 2 | #define __ANARCH_API_TIMER_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | class Timer : public ansa::NoCopy { 12 | public: 13 | /** 14 | * @ambicritical 15 | */ 16 | virtual ansa::Rational GetTicksPerMicro() = 0; 17 | 18 | /** 19 | * Set a timeout on this timer WHICH MUST BE THE CURRENT TIMER. 20 | * @critical 21 | */ 22 | virtual void SetTimeout(uint64_t ticks, void (* func)()) = 0; 23 | 24 | /** 25 | * Like the above SetTimeout() definition, but with an argument passed to 26 | * the function. 27 | * @critical 28 | */ 29 | virtual void SetTimeout(uint64_t, void (*)(void *), void *) = 0; 30 | 31 | /** 32 | * Cancel this timer WHICH MUST BE THE CURRENT TIMER. 33 | * @discussion If a timeout has already fired but has not yet been handled, 34 | * calling this method will suppress the call to the handler. 35 | * @critical 36 | */ 37 | virtual void ClearTimeout() = 0; 38 | 39 | /** 40 | * Wait for the timer to fire or for a platform-specific interrupt to occur. 41 | * @critical -> @noncritical (no return) 42 | */ 43 | virtual void WaitTimeout() ANSA_NORETURN = 0; 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /test/util/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-Wall -Wextra -std=c++11 2 | TEST_INCLUDES=-I../../include -I../dependencies/ansa/include -I../stdlib-api/include 3 | TEST_SOURCES=../../src/util/*.cpp ../stdlib-api/build/*.o dummy-api/*.cpp build/ansa/*.o 4 | ARCH_FLAG ?= -D__ANARCH_TARGET_X64__ 5 | 6 | all: build/assert build/stream build/critical 7 | 8 | build/assert: ../dependencies build/ansa ../stdlib-api/build 9 | $(CXX) $(ARCH_FLAG) $(CPPFLAGS) $(TEST_INCLUDES) $(TEST_SOURCES) test-assert.cpp -o build/assert 10 | 11 | build/stream: ../dependencies build/ansa ../stdlib-api/build 12 | $(CXX) $(ARCH_FLAG) $(CPPFLAGS) $(TEST_INCLUDES) $(TEST_SOURCES) test-stream.cpp -o build/stream 13 | 14 | build/critical: ../dependencies build/ansa ../stdlib-api/build 15 | $(CXX) $(ARCH_FLAG) $(CPPFLAGS) $(TEST_INCLUDES) $(TEST_SOURCES) test-critical.cpp -o build/critical 16 | 17 | build/ansa: ../dependencies build 18 | mkdir build/ansa 19 | ../build-objects $(CXX) $(CPPFLAGS) -I../dependencies/ansa/include -c ../dependencies/ansa/src/*.cpp -o build/ansa 20 | 21 | ../stdlib-api/build: 22 | $(MAKE) -C ../stdlib-api 23 | 24 | ../dependencies: 25 | mkdir ../dependencies 26 | git clone https://github.com/unixpickle/ansa.git ../dependencies/ansa; 27 | 28 | build: 29 | mkdir build 30 | 31 | clean: 32 | rm -rf build 33 | 34 | clean-all: 35 | rm -rf build 36 | rm -rf dependencies 37 | -------------------------------------------------------------------------------- /test/util/dummy-api/console.cpp: -------------------------------------------------------------------------------- 1 | #include "console.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | Console & Console::GetGlobal() { 7 | return dummy::LogConsole::GetGlobal(); 8 | } 9 | 10 | namespace dummy { 11 | 12 | namespace { 13 | 14 | LogConsole gConsole; 15 | 16 | } 17 | 18 | LogConsole & LogConsole::GetGlobal() { 19 | return gConsole; 20 | } 21 | 22 | void LogConsole::PrintString(const char * str) { 23 | size_t length = ansa::Strlen(str); 24 | size_t remaining = Capacity - backlogSize; 25 | if (length <= remaining) { 26 | // perfect 27 | ansa::Memcpy(&backlog[backlogSize], str, length); 28 | backlogSize += length; 29 | } else if (length <= Capacity) { 30 | // we just need to make room 31 | size_t subtractSize = length - remaining; 32 | for (size_t i = 0; i < backlogSize - subtractSize; i++) { 33 | backlog[i] = backlog[i + subtractSize]; 34 | } 35 | backlogSize -= subtractSize; 36 | PrintString(str); 37 | } else { 38 | // just copy the end of the string to the buffer 39 | size_t offset = length - Capacity; 40 | for (size_t i = 0; i < Capacity; i++) { 41 | backlog[i] = str[i + offset]; 42 | } 43 | backlogSize = Capacity; 44 | } 45 | } 46 | 47 | void LogConsole::Initialize() { 48 | ansa::Bzero(backlog, 80 * 25); 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/raw-isr.s: -------------------------------------------------------------------------------- 1 | section .text 2 | 3 | extern InterruptCoded, InterruptNonCoded, InterruptPicEoi 4 | 5 | ; push all registers that are not preserved by a function in the System V ABI 6 | %macro pushunpres 0 7 | push rdi 8 | push rsi 9 | push rdx 10 | push rcx 11 | push r8 12 | push r9 13 | push r10 14 | push r11 15 | push rax 16 | %endmacro 17 | 18 | ; pop all registers pushunpres pushes 19 | %macro popunpres 0 20 | pop rax 21 | pop r11 22 | pop r10 23 | pop r9 24 | pop r8 25 | pop rcx 26 | pop rdx 27 | pop rsi 28 | pop rdi 29 | %endmacro 30 | 31 | global RawNonCodedIsr 32 | RawNonCodedIsr: 33 | pushunpres 34 | 35 | mov rdi, [rsp + 0x48] ; vector number 36 | lea rsi, [rsp + 0x50] ; ISR stack 37 | call InterruptNonCoded 38 | 39 | popunpres 40 | add rsp, 0x8 41 | iretq 42 | 43 | global RawCodedIsr 44 | RawCodedIsr: 45 | pushunpres 46 | 47 | mov rdi, [rsp + 0x48] ; vector number 48 | lea rsi, [rsp + 0x58] ; ISR stack 49 | mov rdx, [rsp + 0x50] ; exception code 50 | call InterruptCoded 51 | 52 | popunpres 53 | add rsp, 0x10 54 | iretq 55 | 56 | global RawPicEoiIsr 57 | RawPicEoiIsr: 58 | pushunpres 59 | 60 | mov rdi, [rsp + 0x48] ; vector number 61 | lea rsi, [rsp + 0x50] ; ISR stack 62 | call InterruptPicEoi 63 | 64 | popunpres 65 | add rsp, 0x8 66 | iretq 67 | -------------------------------------------------------------------------------- /src/memory/easy-map.cpp: -------------------------------------------------------------------------------- 1 | #include "easy-map.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace anarch { 7 | 8 | EasyMap::EasyMap(PhysAddr _start, size_t _size) { 9 | AssertNoncritical(); 10 | 11 | // TODO: here, attempt to use larger page sizes and then fall back 12 | 13 | pageAlign = GlobalMap::GetPageSizeAlign(0); 14 | pageSize = GlobalMap::GetPageSize(0); 15 | 16 | // this is a jumble of variables that some day will get cleaned up 17 | PhysAddr aligned = _start; 18 | size_t endSize = _size; 19 | size_t alignOffset = 0; 20 | if (aligned % pageAlign) { 21 | alignOffset = aligned % pageAlign; 22 | aligned -= alignOffset; 23 | endSize += alignOffset; 24 | } 25 | 26 | pageCount = endSize / pageSize + (endSize % pageSize ? 1 : 0); 27 | 28 | GlobalMap::Attributes attributes; 29 | GlobalMap::Size size(pageSize, pageCount); 30 | if (!GlobalMap::GetGlobal().Map(mapStart, aligned, size, attributes)) { 31 | Panic("EasyMap() - failed to map memory"); 32 | } 33 | start = mapStart + alignOffset; 34 | } 35 | 36 | EasyMap::~EasyMap() { 37 | AssertNoncritical(); 38 | GlobalMap::Size size(pageSize, pageCount); 39 | GlobalMap::GetGlobal().Unmap(mapStart, size); 40 | } 41 | 42 | VirtAddr EasyMap::GetStart() const { 43 | return start; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-pointer.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi-pointer.hpp" 2 | #include "rsdt.hpp" 3 | #include "xsdt.hpp" 4 | #include "../vmm/global/global-malloc.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | namespace { 12 | 13 | uint8_t MemChecksum(uint8_t * ptr, int len) { 14 | uint8_t sum = 0; 15 | while (len-- > 0) { 16 | sum += (*ptr); 17 | ptr++; 18 | } 19 | return sum; 20 | } 21 | 22 | } 23 | 24 | AcpiRoot * AcpiPointer::GenerateRoot() { 25 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 26 | if (revision == 0) { 27 | return allocator.New((PhysAddr)ptrRSDT); 28 | } else { 29 | return allocator.New((PhysAddr)ptrXSDT); 30 | } 31 | } 32 | 33 | AcpiPointer * AcpiPointer::Find() { 34 | // find the RSDP in the BIOS areas. 35 | const char * signature = "RSD PTR "; 36 | uintptr_t ptr; 37 | 38 | // the whole potential EBDA 39 | for (ptr = 0x80000; ptr < 0x9fc00; ptr++) { 40 | if (ansa::Memcmp(signature, (void *)ptr, 8) == 0) { 41 | if (MemChecksum((uint8_t *)ptr, 0x14) != 0) continue; 42 | return (AcpiPointer *)ptr; 43 | } 44 | } 45 | for (ptr = 0xe0000; ptr < 0x100000; ptr++) { 46 | if (ansa::Memcmp(signature, (void *)ptr, 8) == 0) { 47 | if (MemChecksum((uint8_t *)ptr, 0x14) != 0) continue; 48 | return (AcpiPointer *)ptr; 49 | } 50 | } 51 | 52 | return NULL; 53 | } 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/arch/x64/smp/proc-entry.s: -------------------------------------------------------------------------------- 1 | section .text 2 | 3 | ; program loaded at 0x5000, stack starting at 0x5000 (top), pml4 data resides 4 | ; at 0x3000 5 | 6 | PROC_ADDR_BASE equ 0x5000 7 | PROC_TEMP_CR3 equ 0x3000 8 | PROC_GDT_PTR equ 0x4000 9 | 10 | bits 16 11 | 12 | global anarch_proc_entry 13 | anarch_proc_entry: 14 | jmp 0:(.start - anarch_proc_entry + PROC_ADDR_BASE) 15 | .start: 16 | ; stack setup before call: 17 | ; push qword RETURN_ADDR 18 | ; push qword REAL_CR3 19 | cli 20 | mov sp, PROC_ADDR_BASE - 0x10 21 | 22 | ; set PAE and PGE bits 23 | mov eax, 10100000b 24 | mov cr4, eax 25 | 26 | ; set CR3 to temporary page table 27 | mov eax, PROC_TEMP_CR3 28 | mov cr3, eax 29 | 30 | ; set LME, SCE, NXE bits of EFER MSR 31 | mov ecx, 0xC0000080 32 | rdmsr 33 | or eax, 0x901 34 | wrmsr 35 | 36 | ; enable paging and protection simultaneously 37 | mov ebx, cr0 38 | or ebx, 0x80000001 39 | mov cr0, ebx 40 | 41 | ; pop GDT base off the stack 42 | mov ebx, PROC_GDT_PTR 43 | lgdt [ebx] 44 | jmp 0x8:((.entry_64 - anarch_proc_entry) + PROC_ADDR_BASE) 45 | 46 | bits 64 47 | .entry_64: 48 | ; setup segment registers 49 | mov ax, 0x10 50 | mov ds, ax 51 | mov es, ax 52 | mov fs, ax 53 | mov gs, ax 54 | xor ax, ax 55 | mov ss, ax 56 | ; pop real CR3 off stack 57 | pop rax 58 | mov cr3, rax 59 | ; jump to 64-bit CPU entry function 60 | ret 61 | 62 | global anarch_proc_entry_end 63 | anarch_proc_entry_end: -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/lapic-module.cpp: -------------------------------------------------------------------------------- 1 | #include "lapic-module.hpp" 2 | #include "../../vmm/global/global-map.hpp" 3 | #include "../../acpi/acpi-module.hpp" 4 | #include "../../common.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | namespace x64 { 12 | 13 | namespace { 14 | 15 | LapicModule gLapicModule; 16 | 17 | } 18 | 19 | void LapicModule::InitGlobal() { 20 | new(&gLapicModule) LapicModule(); 21 | } 22 | 23 | LapicModule & LapicModule::GetGlobal() { 24 | return gLapicModule; 25 | } 26 | 27 | Lapic & LapicModule::GetLapic() { 28 | AssertCritical(); 29 | 30 | uint32_t ecx; 31 | CpuID(1, NULL, &ecx, NULL); 32 | if (ecx & (1 << 21)) { 33 | return *((X2Apic *)x2apicData); 34 | } else { 35 | return *((XApic *)xapicData); 36 | } 37 | } 38 | 39 | ansa::DepList LapicModule::GetDependencies() { 40 | return ansa::DepList(&GlobalMap::GetGlobal(), &StreamModule::GetGlobal()); 41 | } 42 | 43 | void LapicModule::Initialize() { 44 | cout << "Initializing LAPIC module..."; 45 | 46 | ApicTable * table = AcpiModule::GetGlobal().GetApicTable(); 47 | assert(table != NULL); 48 | 49 | new(xapicData) XApic((PhysAddr)table->GetHeader().lapicAddr); 50 | new(x2apicData) X2Apic(); 51 | 52 | SetCritical(true); 53 | GetLapic().Enable(); 54 | GetLapic().SetDefaults(); 55 | SetCritical(false); 56 | 57 | cout << " [OK]" << endl; 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/user/user-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_USER_MAP_HPP__ 2 | #define __ANARCH_X64_USER_MAP_HPP__ 3 | 4 | #include "../page-table.hpp" 5 | #include "free-list.hpp" 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | namespace x64 { 12 | 13 | class UserMap : public anarch::UserMap { 14 | public: 15 | UserMap(); // @noncritical 16 | virtual ~UserMap(); // @noncritical 17 | 18 | PageTable & GetPageTable(); 19 | 20 | // anarch::MemoryMap 21 | virtual void Set(); 22 | virtual bool Read(PhysAddr *, Attributes *, size_t *, VirtAddr); 23 | virtual bool Map(VirtAddr &, PhysAddr, Size, const Attributes &); 24 | virtual void MapAt(VirtAddr, PhysAddr, Size, const Attributes &); 25 | virtual void Unmap(VirtAddr, Size); 26 | virtual void UnmapAndReserve(VirtAddr, Size); 27 | virtual bool Reserve(VirtAddr &, Size); 28 | virtual void ReserveAt(VirtAddr, Size); 29 | virtual void Unreserve(VirtAddr, Size); 30 | virtual void Rereserve(VirtAddr, Size oldSize, size_t newPageSize); 31 | 32 | // anarch::UserMap 33 | virtual void Delete(); 34 | virtual void CopyToKernel(void * dest, VirtAddr start, size_t size); 35 | virtual void CopyFromKernel(VirtAddr dest, void * start, size_t size); 36 | 37 | protected: 38 | void DistInvlpg(VirtAddr start, size_t size); 39 | 40 | NoncriticalLock lock; 41 | 42 | PageTable table; 43 | FreeList freeList; 44 | }; 45 | 46 | } 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/irt.cpp: -------------------------------------------------------------------------------- 1 | #include "irt.hpp" 2 | #include "raw-isr.hpp" 3 | #include "idt.hpp" 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | namespace { 12 | 13 | Irt gIrt; 14 | 15 | } 16 | 17 | void Irt::InitGlobal() { 18 | new(&gIrt) Irt(); 19 | } 20 | 21 | Irt & Irt::GetGlobal() { 22 | return gIrt; 23 | } 24 | 25 | void * Irt::Get(uint8_t idx) { 26 | return (void *)((uint64_t)routines[idx]); 27 | } 28 | 29 | void Irt::Set(uint8_t idx, void * r) { 30 | routines[idx] = (uint64_t)r; 31 | } 32 | 33 | void Irt::Unset(uint8_t idx) { 34 | routines[idx] = 0; 35 | } 36 | 37 | void Irt::ConfigurePicEoi() { 38 | Idt & globalIdt = Idt::GetGlobal(); 39 | for (int i = 0; i < 0x100; i++) { 40 | globalIdt.SetEntry(i, (void *)RawPicEoiIsr, 0x8e); 41 | } 42 | } 43 | 44 | void Irt::Configure() { 45 | Idt & globalIdt = Idt::GetGlobal(); 46 | for (int i = 0; i < 0x100; i++) { 47 | bool hasCode = (i == 0x8 || i == 0x11 || (i >= 0xa && i <= 0xe)); 48 | if (hasCode) { 49 | globalIdt.SetEntry(i, (void *)RawCodedIsr, 0x8e); 50 | } else { 51 | globalIdt.SetEntry(i, (void *)RawNonCodedIsr, 0x8e); 52 | } 53 | } 54 | } 55 | 56 | ansa::DepList Irt::GetDependencies() { 57 | return ansa::DepList(&Idt::GetGlobal(), &StreamModule::GetGlobal()); 58 | } 59 | 60 | void Irt::Initialize() { 61 | cout << "Initializing Interrupt Routine Table..."; 62 | Idt::GetGlobal().Set(); 63 | cout << " [OK]" << endl; 64 | } 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/global-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_GLOBAL_MAP_HPP__ 2 | #define __ANARCH_X64_GLOBAL_MAP_HPP__ 3 | 4 | #include "../page-table.hpp" 5 | #include "free-finder.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | namespace x64 { 13 | 14 | class GlobalMap : public anarch::GlobalMap { 15 | public: 16 | static void InitGlobal(); 17 | static GlobalMap & GetGlobal(); 18 | 19 | virtual PageTable & GetPageTable(); 20 | virtual FreeFinder & GetFreeFinder(); 21 | virtual Allocator & GetPageAllocator(); 22 | virtual PhysAddr GetPdpt(); 23 | 24 | // anarch::MemoryMap 25 | virtual void Set(); 26 | virtual bool Read(PhysAddr *, Attributes *, size_t *, VirtAddr); 27 | virtual bool Map(VirtAddr &, PhysAddr, Size, const Attributes &); 28 | virtual void MapAt(VirtAddr, PhysAddr, Size, const Attributes &); 29 | virtual void Unmap(VirtAddr, Size); 30 | virtual void UnmapAndReserve(VirtAddr, Size); 31 | virtual bool Reserve(VirtAddr &, Size); 32 | virtual void ReserveAt(VirtAddr, Size); 33 | virtual void Unreserve(VirtAddr, Size); 34 | virtual void Rereserve(VirtAddr, Size, size_t); 35 | 36 | protected: 37 | // anarch::Module 38 | virtual ansa::DepList GetDependencies(); 39 | virtual void Initialize(); 40 | 41 | private: 42 | PageTable * pageTable; 43 | FreeFinder * freeFinder; 44 | Allocator * pageAllocator; 45 | PhysAddr pdpt; 46 | 47 | NoncriticalLock lock; 48 | }; 49 | 50 | } 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/user/free-list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_FREE_LIST_HPP__ 2 | #define __ANARCH_X64_FREE_LIST_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | class FreeList { 12 | public: 13 | struct Region { 14 | VirtAddr start; 15 | size_t size; 16 | Region * next = NULL; 17 | 18 | Region(VirtAddr, size_t); 19 | VirtAddr End(); 20 | bool CanHold(size_t pageSize, size_t pageCount); 21 | bool IsAdjacentBehind(VirtAddr addr); 22 | bool Contains(Region & reg); 23 | bool IsBehind(VirtAddr addr); 24 | bool IsFilledBy(Region & reg); 25 | bool IsEndedBy(Region & reg); 26 | bool IsStartedBy(Region & reg); 27 | }; 28 | 29 | ~FreeList(); // @noncritical 30 | 31 | /** 32 | * Allocate a contiguous, aligned region at a specified address. 33 | * @noncritical 34 | */ 35 | bool AllocAt(VirtAddr start, size_t pageSize, size_t pageCount); 36 | 37 | /** 38 | * Allocate a contiguous, aligned region of virtual memory. 39 | * @noncritical 40 | */ 41 | VirtAddr Alloc(size_t pageSize, size_t pageCount); 42 | 43 | /** 44 | * Free a contiguous region of virtual memory. 45 | * @noncritical 46 | */ 47 | void Free(VirtAddr addr, size_t pageSize, size_t pageCount); 48 | 49 | protected: 50 | Region * first = NULL; 51 | 52 | static Region * AllocRegion(VirtAddr, size_t); 53 | static void FreeRegion(Region * reg); 54 | 55 | void AllocInRegion(Region * reg, Region * last, Region & requested); 56 | }; 57 | 58 | } 59 | 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /test/build-objects.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env coffee -- 2 | # 3 | # This tool exists because I hate the way clang handles wildcards with the `-c` 4 | # flag. Specifically, this script allows you to compile multiple source files 5 | # to multiple object files WITH A SPECIFIED OUTPUT DIRECTORY. 6 | # 7 | 8 | path = require 'path' 9 | {spawn} = require 'child_process' 10 | 11 | if process.argv.length < 4 12 | console.error 'Usage: build-objects [flags ...]' + 13 | ' [sources ...] [-o output dir]' 14 | process.exit 1 15 | 16 | class CompilerCommand 17 | constructor: (@arguments) -> 18 | @outputDir = '.' 19 | @files = [] 20 | if @arguments[@arguments.length - 2] is '-o' 21 | @outputDir = @arguments.pop() 22 | @arguments.pop() 23 | for x, i in @arguments 24 | continue if i is 0 25 | if x[0] isnt '-' 26 | @files = @arguments[i..] 27 | @arguments = @arguments[...i] 28 | break 29 | 30 | objectPath: (source) -> 31 | bn = path.basename source 32 | objName = bn[0...bn.length - path.extname(bn).length] + '.o' 33 | return path.join @outputDir, objName 34 | 35 | compileNext: -> 36 | return if @files.length is 0 37 | file = @files.pop() 38 | flags = @arguments[1..].concat [file, '-o', @objectPath file] 39 | console.log @arguments[0] + ' ' + flags.join ' ' 40 | task = spawn @arguments[0], flags, stdio: 'inherit' 41 | task.on 'close', (code) => 42 | process.exit code if code isnt 0 43 | @compileNext() 44 | 45 | compiler = new CompilerCommand process.argv[2..] 46 | compiler.compileNext() 47 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/idt-types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_IDT_TYPES_HPP__ 2 | #define __ANARCH_X64_IDT_TYPES_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | /** 12 | * Represents this x86-64 machine code: 13 | * 14 | * pushq %rax 15 | * pushq %rax 16 | * movabsq $argument, %rax 17 | * movq %rax, 0x8(%rsp) 18 | * movabsq $function, %rax 19 | * xchgq %rax, (%rsp) 20 | * ret 21 | */ 22 | struct IdtHandler { 23 | unsigned char code1[4] {0x50, 0x50, 0x48, 0xB8}; 24 | uint64_t argument = 0; 25 | unsigned char code2[7] {0x48, 0x89, 0x44, 0x24, 0x08, 0x48, 0xB8}; 26 | uint64_t function = 0; 27 | unsigned char code3[5] {0x48, 0x87, 0x04, 0x24, 0xc3}; 28 | } ANSA_PACKED; 29 | 30 | static_assert(sizeof(IdtHandler) == 0x20, "IdtHandler size == 0x20"); 31 | 32 | struct IdtEntry { 33 | uint16_t lowOffset = 0; 34 | uint16_t codeSegment = 8; 35 | uint8_t ist : 3; 36 | uint8_t reserved1 : 5; 37 | uint8_t flags = 0; 38 | uint16_t midOffset = 0; 39 | uint32_t highOffset = 0; 40 | uint32_t reserved2 = 0; 41 | 42 | IdtEntry() : ist(0), reserved1(0) {} 43 | 44 | void SetOffset(uint64_t exc) { 45 | lowOffset = exc & 0xffff; 46 | midOffset = (exc >> 16) & 0xffff; 47 | highOffset = exc >> 32; 48 | } 49 | } ANSA_PACKED; 50 | 51 | static_assert(sizeof(IdtEntry) == 0x10, "IdtEntry size == 0x10"); 52 | 53 | struct IdtPointer { 54 | uint16_t limit; 55 | uint64_t virtualAddress; 56 | } ANSA_PACKED; 57 | 58 | static_assert(sizeof(IdtPointer) == 0x0a, "IdtPointer size == 0x0a"); 59 | 60 | } 61 | 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/arch/x64/pmm/buddy-allocator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_BUDDY_ALLOCATOR_HPP__ 2 | #define __ANARCH_X64_BUDDY_ALLOCATOR_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | /** 13 | * This allocator is meant for use throughout the lifecycle of the operating 14 | * system's execution. It provides efficient allocation and deallocation. 15 | */ 16 | class BuddyAllocator : public Allocator { 17 | public: 18 | BuddyAllocator(const RegionList & regions, Allocator & tempAllocator); 19 | 20 | virtual void Reserve(PhysAddr lastAddr); 21 | 22 | virtual bool AllocLower(PhysAddr & addr, PhysSize size, PhysSize align); 23 | 24 | // anarch::Allocator 25 | virtual bool Alloc(PhysAddr & result, PhysSize size, PhysSize align); 26 | virtual void Free(PhysAddr address); 27 | virtual bool Owns(PhysAddr address); 28 | virtual PhysSize Used(); 29 | virtual PhysSize Available(); 30 | virtual PhysSize Total(); 31 | 32 | private: 33 | static const int MaxAllocators = 0x10; 34 | 35 | ANAlloc::FixedCluster lower; 36 | ANAlloc::FixedCluster upper; 37 | bool hasUpper = false; 38 | bool hasLower = false; 39 | 40 | NoncriticalLock upperLock; 41 | NoncriticalLock lowerLock; 42 | 43 | PhysSize totalSpace = 0; 44 | 45 | static void InitializeCluster(ANAlloc::MutableCluster & cluster, 46 | const ANAlloc::RegionList & regs, 47 | Allocator & tempAllocator); 48 | }; 49 | 50 | } 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/arch/x64/domains/domain.cpp: -------------------------------------------------------------------------------- 1 | #include "domain.hpp" 2 | #include "domain-list.hpp" 3 | #include "../vmm/global/global-map.hpp" 4 | #include "../vmm/global/global-malloc.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | Domain & Domain::GetCurrent() { 11 | return DomainList::GetGlobal()[0]; 12 | } 13 | 14 | namespace x64 { 15 | 16 | Domain::Domain(int _capacity) 17 | : allocator(GlobalMap::GetGlobal().GetPageAllocator()), 18 | virtualAllocator(GlobalMalloc::GetGlobal().GetAllocator()), 19 | capacity(_capacity) { 20 | void * data; 21 | if (!GetVirtualAllocator().Alloc(data, sizeof(Cpu) * capacity)) { 22 | Panic("Domain::Domain() - failed to allocate CPUs"); 23 | } 24 | cpuData = (char *)data; 25 | } 26 | 27 | Domain::~Domain() { 28 | GetVirtualAllocator().Free((void *)cpuData); 29 | } 30 | 31 | Cpu & Domain::GetCpu(int idx) { 32 | Cpu * cpuPtr = (Cpu *)cpuData; 33 | return cpuPtr[idx]; 34 | } 35 | 36 | int Domain::InitNewCpu() { 37 | AssertNoncritical(); 38 | 39 | assert(count < capacity); 40 | Cpu * cpuPtr = (Cpu *)cpuData + count; 41 | new(cpuPtr) Cpu(); 42 | return count++; 43 | } 44 | 45 | anarch::Domain & Domain::GetSibling(int) { 46 | Panic("Domain::GetSibling() - not supported by x64"); 47 | return *((anarch::Domain *)NULL); 48 | } 49 | 50 | int Domain::GetThreadCount() { 51 | return count; 52 | } 53 | 54 | Thread & Domain::GetThread(int idx) { 55 | return GetCpu(idx); 56 | } 57 | 58 | Allocator & Domain::GetAllocator() { 59 | return allocator; 60 | } 61 | 62 | VirtualAllocator & Domain::GetVirtualAllocator() { 63 | return virtualAllocator; 64 | } 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/lapic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_LAPIC_HPP__ 2 | #define __ANARCH_X64_LAPIC_HPP__ 3 | 4 | #include 5 | 6 | namespace anarch { 7 | 8 | namespace x64 { 9 | 10 | class Lapic { 11 | public: 12 | static const int PreferredDivide = 0x3; 13 | 14 | virtual void SetDefaults(); // @critical 15 | virtual void Enable() = 0; // @critical 16 | virtual uint32_t GetId() = 0; // @critical 17 | virtual void ClearErrors(); // @critical 18 | 19 | virtual void SendEoi(); // @critical 20 | virtual void SetPriority(uint8_t vector); 21 | virtual bool IsRequested(uint8_t vector); // @critical 22 | virtual bool IsInService(uint8_t vector); // @critical 23 | 24 | virtual void SetTimeout(uint8_t vector, uint32_t ticks); // @critical 25 | virtual void ClearTimeout(); 26 | virtual bool IsTimerRunning(); 27 | 28 | /** 29 | * @critical 30 | */ 31 | virtual void SendIpi(uint32_t cpu, uint8_t vector, 32 | uint8_t mode = 0, uint8_t level = 1, 33 | uint8_t trigger = 0) = 0; 34 | 35 | virtual uint64_t ReadReg(uint16_t reg) = 0; // @critical 36 | virtual void WriteReg(uint16_t reg, uint64_t value) = 0; // @critical 37 | 38 | enum Regs { 39 | RegApicId = 0x2, 40 | RegApicVer = 0x3, 41 | RegTaskPriority = 0x8, 42 | RegEoi = 0xb, 43 | RegSpurious = 0xf, 44 | RegEsr = 0x28, 45 | RegIcr = 0x30, 46 | RegLvtTimer = 0x32, 47 | RegLvtPerf = 0x34, 48 | RegLvtLint0 = 0x35, 49 | RegLvtLint1 = 0x36, 50 | RegLvtError = 0x37, 51 | RegTimerInitCount = 0x38, 52 | RegTimerCurrCount = 0x39, 53 | RegTimerDiv = 0x3e 54 | }; 55 | }; 56 | 57 | } 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/xapic.cpp: -------------------------------------------------------------------------------- 1 | #include "xapic.hpp" 2 | #include "../../common.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | XApic::XApic(PhysAddr _base) : map(_base, 0x1000), base(_base) { 10 | } 11 | 12 | uint64_t XApic::ReadReg(uint16_t reg) { 13 | AssertCritical(); 14 | volatile uint32_t * regs = (volatile uint32_t *)map.GetStart(); 15 | if (reg != RegIcr) { 16 | return (uint64_t)regs[reg * 4]; 17 | } else { 18 | uint32_t lower = regs[reg * 4]; 19 | uint32_t higher = regs[(reg + 1) * 4]; 20 | return (uint64_t)lower | ((uint64_t)higher << 0x20); 21 | } 22 | } 23 | 24 | void XApic::WriteReg(uint16_t reg, uint64_t value) { 25 | AssertCritical(); 26 | volatile uint32_t * regs = (volatile uint32_t *)map.GetStart(); 27 | if (reg != RegIcr) { 28 | assert(!(value & 0xFFFFFFFF00000000UL)); 29 | regs[reg * 4] = value; 30 | } else { 31 | regs[(reg + 1) * 4] = value >> 0x20; 32 | regs[reg * 4] = value & 0xFFFFFFFF; 33 | } 34 | } 35 | 36 | void XApic::Enable() { 37 | AssertCritical(); 38 | uint64_t flags = ReadMsr(0x1b) & 0xf00; 39 | flags |= 1 << 11; 40 | WriteMsr(0x1b, (uint64_t)base | flags); 41 | } 42 | 43 | uint32_t XApic::GetId() { 44 | AssertCritical(); 45 | return ReadReg(RegApicId) >> 0x18; 46 | } 47 | 48 | void XApic::SendIpi(uint32_t cpu, uint8_t vector, uint8_t mode, uint8_t level, 49 | uint8_t trigger) { 50 | AssertCritical(); 51 | uint64_t value = 0; 52 | value = (uint64_t)vector | ((uint64_t)mode << 8); 53 | value |= ((uint64_t)level << 0xe) | ((uint64_t)trigger << 0xf); 54 | value |= ((uint64_t)cpu << 0x38); 55 | WriteReg(RegIcr, value); 56 | } 57 | 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/arch/api/memory-map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_MEMORY_MAP_HPP__ 2 | #define __ANARCH_API_MEMORY_MAP_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | class MemoryMap : public ansa::NoCopy { 11 | public: 12 | struct Attributes { 13 | bool executable = true; 14 | bool writable = true; 15 | bool cachable = true; 16 | }; 17 | 18 | struct Capabilities { 19 | /** 20 | * This is true when ReserveAt() is available. 21 | */ 22 | bool placementReserve; 23 | 24 | /** 25 | * This is true when MapAt(), UnmapAndReserve(), Reserve(), and Rereserve() 26 | * are available. 27 | */ 28 | bool placementMap; 29 | 30 | bool executableFlag; 31 | bool writableFlag; 32 | bool cachableFlag; 33 | }; 34 | 35 | struct Size { 36 | size_t pageSize; 37 | size_t pageCount; 38 | 39 | Size(size_t s, size_t c) : pageSize(s), pageCount(c) { 40 | } 41 | 42 | inline size_t Bytes() const { 43 | return pageSize * pageCount; 44 | } 45 | }; 46 | 47 | // @critical 48 | virtual void Set() = 0; 49 | 50 | // all @noncritical 51 | virtual bool Read(PhysAddr *, Attributes *, size_t *, VirtAddr) = 0; 52 | virtual bool Map(VirtAddr &, PhysAddr, Size, const Attributes &) = 0; 53 | virtual void MapAt(VirtAddr, PhysAddr, Size, const Attributes &) = 0; 54 | virtual void Unmap(VirtAddr, Size) = 0; 55 | virtual void UnmapAndReserve(VirtAddr, Size) = 0; 56 | virtual bool Reserve(VirtAddr &, Size) = 0; 57 | virtual void ReserveAt(VirtAddr, Size) = 0; 58 | virtual void Unreserve(VirtAddr, Size) = 0; 59 | virtual void Rereserve(VirtAddr, Size oldSize, size_t newPageSize) = 0; 60 | }; 61 | 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/arch/x64/public/init.cpp: -------------------------------------------------------------------------------- 1 | #include "init.hpp" 2 | #include "../vmm/tlb.hpp" 3 | #include "../vmm/global/global-malloc.hpp" 4 | #include "../vmm/global/global-map.hpp" 5 | #include "../interrupts/idt.hpp" 6 | #include "../interrupts/irt.hpp" 7 | #include "../interrupts/pic.hpp" 8 | #include "../interrupts/apic/ioapic-module.hpp" 9 | #include "../interrupts/apic/lapic-module.hpp" 10 | #include "../console/text-console.hpp" 11 | #include "../domains/domain-list.hpp" 12 | #include "../acpi/acpi-module.hpp" 13 | #include "../critical/module.hpp" 14 | #include "../syscall/module.hpp" 15 | #include "../segments/gdt.hpp" 16 | #include "../timer/module.hpp" 17 | #include "../clock/module.hpp" 18 | #include "../panic/panic.hpp" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace anarch { 24 | 25 | namespace x64 { 26 | 27 | namespace { 28 | 29 | const BootInfo * bootInfo = NULL; 30 | 31 | } 32 | 33 | void InitializeSingletons() { 34 | bootInfo = NULL; 35 | CriticalModule::InitGlobal(); 36 | SyscallModule::InitGlobal(); 37 | GlobalMalloc::InitGlobal(); 38 | IOApicModule::InitGlobal(); 39 | TextConsole::InitGlobal(); 40 | PanicModule::InitGlobal(); 41 | LapicModule::InitGlobal(); 42 | TimerModule::InitGlobal(); 43 | ClockModule::InitGlobal(); 44 | DomainList::InitGlobal(); 45 | AcpiModule::InitGlobal(); 46 | GlobalMap::InitGlobal(); 47 | Tlb::InitGlobal(); 48 | Idt::InitGlobal(); 49 | Irt::InitGlobal(); 50 | Pic::InitGlobal(); 51 | Gdt::InitGlobal(); 52 | 53 | StreamModule::InitGlobal(); 54 | } 55 | 56 | void SetBootInfo(const BootInfo * info) { 57 | assert(info != NULL); 58 | assert(!bootInfo); 59 | bootInfo = info; 60 | } 61 | 62 | const BootInfo * GetBootInfo() { 63 | return bootInfo; 64 | } 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/acpi-module.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi-module.hpp" 2 | #include "acpi-pointer.hpp" 3 | #include "../vmm/global/global-malloc.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | namespace { 13 | 14 | AcpiModule gAcpiModule; 15 | 16 | } 17 | 18 | void AcpiModule::InitGlobal() { 19 | new(&gAcpiModule) AcpiModule(); 20 | } 21 | 22 | AcpiModule & AcpiModule::GetGlobal() { 23 | return gAcpiModule; 24 | } 25 | 26 | AcpiRoot & AcpiModule::GetRoot() { 27 | return *root; 28 | } 29 | 30 | ApicTable * AcpiModule::GetApicTable() { 31 | return apicTable; 32 | } 33 | 34 | HpetTable * AcpiModule::GetHpetTable() { 35 | return hpetTable; 36 | } 37 | 38 | ansa::DepList AcpiModule::GetDependencies() { 39 | return ansa::DepList(&GlobalMalloc::GetGlobal(), 40 | &StreamModule::GetGlobal()); 41 | } 42 | 43 | void AcpiModule::Initialize() { 44 | cout << "Initializing ACPI subsystem..."; 45 | AcpiPointer * pointer = AcpiPointer::Find(); 46 | assert(pointer != NULL); 47 | 48 | root = pointer->GenerateRoot(); 49 | assert(root != NULL); 50 | 51 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 52 | 53 | // find the APIC table 54 | int apicIndex = GetRoot().FindTable("APIC"); 55 | if (apicIndex >= 0) { 56 | apicTable = allocator.New(GetRoot().GetTable(apicIndex)); 57 | assert(apicTable != NULL); 58 | } 59 | 60 | // find the HPET table 61 | int hpetIndex = GetRoot().FindTable("HPET"); 62 | if (hpetIndex >= 0) { 63 | hpetTable = allocator.New(); 64 | PhysCopy((void *)hpetTable, GetRoot().GetTable(hpetIndex), 65 | sizeof(HpetTable)); 66 | } 67 | 68 | cout << " [OK]" << endl; 69 | } 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /test/util/test-critical.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "dummy-api/critical.hpp" 6 | #include 7 | 8 | using namespace anarch; 9 | using dummy::SetIgnoreCriticality; 10 | 11 | void TestScopedCritical(); 12 | void TestAssertCriticality(); 13 | 14 | int main() { 15 | TestScopedCritical(); 16 | TestAssertCriticality(); 17 | return 0; 18 | } 19 | 20 | void TestScopedCritical() { 21 | ScopedPass pass("ScopedCritical"); 22 | 23 | SetIgnoreCriticality(false); 24 | SetCritical(false); 25 | 26 | Assert(!GetCritical()); 27 | { 28 | ScopedCritical critical; 29 | Assert(GetCritical()); 30 | } 31 | Assert(!GetCritical()); 32 | } 33 | 34 | void TestAssertCriticality() { 35 | ScopedPass pass("[AssertNoncritical/AssertCritical]()"); 36 | 37 | SetIgnoreCriticality(true); 38 | try { 39 | SetCritical(true); 40 | AssertCritical(); 41 | AssertNoncritical(); 42 | SetCritical(false); 43 | AssertCritical(); 44 | AssertNoncritical(); 45 | } catch (const char * exc) { 46 | PrintError("unexpected panic: "); 47 | Die(exc); 48 | } 49 | 50 | SetIgnoreCriticality(false); 51 | SetCritical(true); 52 | try { 53 | AssertCritical(); 54 | } catch (const char * exc) { 55 | PrintError("unexpected panic: "); 56 | Die(exc); 57 | } 58 | try { 59 | AssertNoncritical(); 60 | Die("expected panic after AssertNoncritical()"); 61 | } catch (const char * exc) { 62 | } 63 | 64 | SetCritical(false); 65 | try { 66 | AssertNoncritical(); 67 | } catch (const char * exc) { 68 | PrintError("unexpected panic: "); 69 | Die(exc); 70 | } 71 | try { 72 | AssertCritical(); 73 | Die("expected panic after AssertCritical()"); 74 | } catch (const char * exc) { 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/arch/x64/clock/module.cpp: -------------------------------------------------------------------------------- 1 | #include "module.hpp" 2 | #include "hpet.hpp" 3 | #include "pit.hpp" 4 | #include "../acpi/acpi-module.hpp" 5 | #include "../interrupts/irt.hpp" 6 | #include "../interrupts/apic/ioapic-module.hpp" 7 | #include "../interrupts/apic/lapic-module.hpp" 8 | #include "../vmm/global/global-malloc.hpp" 9 | #include 10 | #include 11 | #include 12 | 13 | namespace anarch { 14 | 15 | ClockModule & ClockModule::GetGlobal() { 16 | return x64::ClockModule::GetGlobal(); 17 | } 18 | 19 | namespace x64 { 20 | 21 | namespace { 22 | 23 | ClockModule gClockModule; 24 | 25 | } 26 | 27 | void ClockModule::InitGlobal() { 28 | new(&gClockModule) ClockModule(); 29 | } 30 | 31 | ClockModule & ClockModule::GetGlobal() { 32 | return gClockModule; 33 | } 34 | 35 | void ClockModule::TryTsc() { 36 | AssertNoncritical(); 37 | } 38 | 39 | bool ClockModule::IsUsingTsc() { 40 | return isTsc; 41 | } 42 | 43 | Clock & ClockModule::GetClock() { 44 | assert(clock != NULL); 45 | return *clock; 46 | } 47 | 48 | ansa::DepList ClockModule::GetDependencies() { 49 | return ansa::DepList(&Irt::GetGlobal(), &IOApicModule::GetGlobal(), 50 | &LapicModule::GetGlobal(), &GlobalMalloc::GetGlobal(), 51 | &AcpiModule::GetGlobal(), &StreamModule::GetGlobal()); 52 | } 53 | 54 | void ClockModule::Initialize() { 55 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 56 | HpetTable * hpetInfo = AcpiModule::GetGlobal().GetHpetTable(); 57 | 58 | if (hpetInfo) { 59 | clock = allocator.New(*hpetInfo); 60 | cout << "HPET clock initialized" << endl; 61 | } else { 62 | clock = allocator.New(1193); // ~1000Hz 63 | cout << "PIT clock initialized" << endl; 64 | } 65 | clock->Start(); 66 | } 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/lapic.cpp: -------------------------------------------------------------------------------- 1 | #include "lapic.hpp" 2 | #include 3 | 4 | namespace anarch { 5 | 6 | namespace x64 { 7 | 8 | void Lapic::SetDefaults() { 9 | AssertCritical(); 10 | WriteReg(RegTaskPriority, 0x0); 11 | WriteReg(RegLvtTimer, 0x10000); 12 | WriteReg(RegLvtPerf, 0x10000); 13 | WriteReg(RegLvtLint0, 0x8700); 14 | WriteReg(RegLvtLint1, 0x400); 15 | WriteReg(RegLvtError, 0x10000); 16 | WriteReg(RegSpurious, 0x1ff); 17 | 18 | // reset might have shut them off 19 | WriteReg(RegLvtLint0, 0x8700); 20 | WriteReg(RegLvtLint1, 0x400); 21 | 22 | WriteReg(RegTimerDiv, PreferredDivide); 23 | } 24 | 25 | void Lapic::ClearErrors() { 26 | AssertCritical(); 27 | WriteReg(RegEsr, 0); 28 | } 29 | 30 | void Lapic::SendEoi() { 31 | AssertCritical(); 32 | WriteReg(RegEoi, 0); 33 | } 34 | 35 | void Lapic::SetPriority(uint8_t vector) { 36 | AssertCritical(); 37 | WriteReg(RegTaskPriority, vector); 38 | } 39 | 40 | bool Lapic::IsRequested(uint8_t vector) { 41 | AssertCritical(); 42 | uint64_t regIndex = 0x20 + (vector >> 5); 43 | uint32_t mask = (1 << (vector & 0x1f)); 44 | return 0 != (ReadReg(regIndex) & mask); 45 | } 46 | 47 | bool Lapic::IsInService(uint8_t vector) { 48 | AssertCritical(); 49 | uint64_t regIndex = 0x10 + (vector >> 5); 50 | uint32_t mask = (1 << (vector & 0x1f)); 51 | return 0 != (ReadReg(regIndex) & mask); 52 | } 53 | 54 | void Lapic::SetTimeout(uint8_t vector, uint32_t ticks) { 55 | uint32_t timerField = vector;// | (2 << 17); // mode is bit 17 56 | WriteReg(RegLvtTimer, timerField); 57 | WriteReg(RegTimerInitCount, ticks); 58 | } 59 | 60 | void Lapic::ClearTimeout() { 61 | WriteReg(RegLvtTimer, 0x10000); 62 | } 63 | 64 | bool Lapic::IsTimerRunning() { 65 | if (ReadReg(RegLvtTimer) & 0x10000) return false; 66 | return ReadReg(RegTimerCurrCount) != 0; 67 | } 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/arch/x64/pmm/step-allocator.cpp: -------------------------------------------------------------------------------- 1 | #include "step-allocator.hpp" 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | StepAllocator::StepAllocator(PhysAddr start) : lastAddr(start) { 10 | } 11 | 12 | PhysAddr StepAllocator::GetLastAddress() { 13 | return lastAddr; 14 | } 15 | 16 | bool StepAllocator::Alloc(PhysAddr & addr, PhysSize size, PhysSize align) { 17 | const RegionList & regions = GetBootInfo()->GetRegions(); 18 | 19 | const ANAlloc::Region * reg = regions.FindRegion(lastAddr); 20 | if (!reg) { 21 | if (!(reg = regions.FindRegion(lastAddr - 1))) { 22 | return false; 23 | } 24 | } 25 | 26 | if (lastAddr % align) { 27 | lastAddr += align - (lastAddr % align); 28 | } 29 | 30 | if (lastAddr > (PhysAddr)reg->GetEnd()) { 31 | lastAddr = (PhysAddr)reg->GetEnd() - 1; 32 | } 33 | 34 | while (lastAddr + size > (PhysAddr)reg->GetEnd()) { 35 | reg = regions.NextRegion(reg); 36 | if (!reg) return false; 37 | 38 | lastAddr = (PhysAddr)reg->GetStart(); 39 | if (lastAddr % align) { 40 | lastAddr += align - (lastAddr % align); 41 | } 42 | if (lastAddr > (PhysAddr)reg->GetEnd()) { 43 | lastAddr = (PhysAddr)reg->GetEnd() - 1; 44 | } 45 | } 46 | 47 | addr = lastAddr; 48 | lastAddr += size; 49 | return true; 50 | } 51 | 52 | void StepAllocator::Free(PhysAddr) { 53 | Panic("StepAllocator::Free() - unsupported"); 54 | } 55 | 56 | bool StepAllocator::Owns(PhysAddr) { 57 | Panic("StepAllocator::Owns() - unsupported"); 58 | } 59 | 60 | PhysSize StepAllocator::Used() { 61 | Panic("StepAllocator::Used() - unsupported"); 62 | } 63 | 64 | PhysSize StepAllocator::Available() { 65 | Panic("StepAllocator::Available() - unsupported"); 66 | } 67 | 68 | PhysSize StepAllocator::Total() { 69 | Panic("StepAllocator::Total() - unsupported"); 70 | } 71 | 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/pic.cpp: -------------------------------------------------------------------------------- 1 | #include "pic.hpp" 2 | #include "../common.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | namespace { 12 | 13 | Pic gPic; 14 | 15 | void IOWait() { 16 | OutB(0x80, 0); 17 | } 18 | 19 | const uint16_t PIC1_COMMAND = 0x20; 20 | const uint16_t PIC1_DATA = 0x21; 21 | const uint16_t PIC2_COMMAND = 0xa0; 22 | const uint16_t PIC2_DATA = 0xa1; 23 | 24 | const uint8_t ICW1_ICW4 = 0x01; /* ICW4 (not) needed */ 25 | const uint8_t ICW1_INIT = 0x10; /* Initialization - required! */ 26 | const uint8_t ICW4_8086 = 0x01; /* 8086/88 (MCS-80/85) mode */ 27 | 28 | } 29 | 30 | void Pic::InitGlobal() { 31 | new(&gPic) Pic(); 32 | } 33 | 34 | Pic & Pic::GetGlobal() { 35 | return gPic; 36 | } 37 | 38 | void Pic::Remap(uint8_t masterBase, uint8_t slaveBase, uint8_t masterMask, 39 | uint8_t slaveMask) { 40 | OutB(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4); 41 | IOWait(); 42 | OutB(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4); 43 | IOWait(); 44 | OutB(PIC1_DATA, masterBase); // ICW2: Master PIC vector offset 45 | IOWait(); 46 | OutB(PIC2_DATA, slaveBase); // ICW2: Slave PIC vector offset 47 | IOWait(); 48 | OutB(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) 49 | IOWait(); 50 | OutB(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) 51 | IOWait(); 52 | 53 | OutB(PIC1_DATA, ICW4_8086); 54 | IOWait(); 55 | OutB(PIC2_DATA, ICW4_8086); 56 | IOWait(); 57 | 58 | OutB(PIC1_DATA, masterMask); 59 | OutB(PIC2_DATA, slaveMask); 60 | } 61 | 62 | ansa::DepList Pic::GetDependencies() { 63 | return ansa::DepList(&StreamModule::GetGlobal()); 64 | } 65 | 66 | void Pic::Initialize() { 67 | cout << "Initializing legacy PIC..."; 68 | Remap(0xf0, 0xf8, 0xff, 0xff); 69 | cout << " [OK]" << endl; 70 | } 71 | 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/arch/api/domain.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_DOMAIN_HPP__ 2 | #define __ANARCH_API_DOMAIN_HPP__ 3 | 4 | #include "thread.hpp" 5 | #include "allocator.hpp" 6 | #include "virtual-allocator.hpp" 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | class Domain : public ansa::NoCopy { 13 | public: 14 | /** 15 | * Get the current domain of the current hardware thread. 16 | * @critical 17 | */ 18 | static Domain & GetCurrent(); 19 | 20 | /** 21 | * This is another way to access the list of Domains. This approach returns 22 | * Domains in order of "closeness" to this Domain. If every Domain is the 23 | * same "distance" away, the order is irrelevant. 24 | * @ambicritical 25 | */ 26 | virtual Domain & GetSibling(int idx) = 0; 27 | 28 | virtual int GetThreadCount() = 0; // @ambicritical 29 | virtual Thread & GetThread(int idx) = 0; // @ambicritical 30 | 31 | virtual Allocator & GetAllocator() = 0; // @ambicritical 32 | virtual VirtualAllocator & GetVirtualAllocator() = 0; // @ambicritical 33 | 34 | virtual bool Alloc(void *&, size_t); // @noncritical 35 | virtual void Free(void *); // @noncritical 36 | 37 | virtual bool AllocPhys(PhysAddr &, PhysSize, PhysSize align); // @noncritical 38 | virtual void FreePhys(PhysAddr); // @noncritical 39 | 40 | /** 41 | * Allocate an object, preferably from this Domain's allocator. 42 | * @noncritical 43 | */ 44 | template 45 | T * New(Args... args) { 46 | void * buf; 47 | if (!Alloc(buf, sizeof(T))) return NULL; 48 | return new(buf) T(args...); 49 | } 50 | 51 | /** 52 | * Delete an object which was most likely allocated on this Domain's 53 | * allocator. 54 | * @noncritical 55 | */ 56 | template 57 | void Delete(T * ptr) { 58 | ptr->~T(); 59 | Free((void *)ptr); 60 | } 61 | }; 62 | 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/arch/x64/smp/cpu.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_CPU_HPP__ 2 | #define __ANARCH_X64_CPU_HPP__ 3 | 4 | #include "../segments/tss.hpp" 5 | #include "../timer/lapic-timer.hpp" 6 | #include "../interrupts/apic/lapic.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace anarch { 14 | 15 | namespace x64 { 16 | 17 | class Cpu : public Thread { 18 | public: 19 | static Cpu & GetCurrent(); 20 | static void HandleWakeup(); 21 | 22 | Cpu(); // @noncritical 23 | ~Cpu(); // @panic 24 | 25 | /** 26 | * Set a stack pointer in the TSS and the CPU data area so that it is used to 27 | * handle syscalls and interrupts from a user-space task. 28 | * @critical 29 | */ 30 | void SetAsyncKernelTop(void * stack); 31 | 32 | void * GetStackTop(); // @ambicritical 33 | uint32_t GetApicId(); // @ambicritical 34 | LapicTimer & GetLapicTimer(); // @ambicritical 35 | Lapic & GetLapic(); // @ambicritical 36 | 37 | virtual anarch::Domain & GetDomain(); // @ambicritical 38 | virtual anarch::Timer & GetTimer(); // @critical 39 | virtual int GetPriority(); // @ambicritical 40 | virtual void RunAsync(void (*)()); // @critical 41 | virtual void RunAsync(void (*)(void *), void *); // @critical 42 | 43 | protected: 44 | MemoryMap * currentMap = NULL; 45 | friend class Tlb; 46 | 47 | private: 48 | static const size_t StackSize = 0x10000; 49 | 50 | struct LocalData { 51 | Cpu * thisCpu; 52 | void * syscallStack; 53 | void * userData = NULL; 54 | } ANSA_PACKED; 55 | 56 | anarch::CriticalLock wakeupLock; 57 | void (* wakeupFunction)(void *); 58 | void * wakeupArg; 59 | 60 | Lapic & lapic; 61 | LapicTimer lapicTimer; 62 | LocalData localData; 63 | Tss taskSegment; 64 | uint32_t apicId; 65 | void * stackTop; 66 | }; 67 | 68 | } 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/ioapic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_IOAPIC_HPP__ 2 | #define __ANARCH_X64_IOAPIC_HPP__ 3 | 4 | #include "../../acpi/apic-table.hpp" 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | class IOApic : public ansa::NoCopy { 13 | public: 14 | struct Entry; 15 | static const int RegVersion = 1; 16 | 17 | IOApic(ApicTable & table, ApicTable::IOApic * info); // @noncritical 18 | 19 | // destructor is implicit, but is still @noncritical 20 | 21 | void WriteReg(uint8_t reg, uint32_t val); // @ambicritical 22 | uint32_t ReadReg(uint8_t reg); // @ambicritical 23 | 24 | uint32_t GetVersion(); // @ambicritical 25 | uint32_t GetPinCount(); // @ambicritical 26 | uint32_t GetInterruptBase(); // @ambicritical 27 | 28 | void SetEntry(uint8_t idx, const Entry & entry); // @ambicritical 29 | void MapIrq(uint8_t irq, uint8_t vector); // @ambicritical 30 | void MaskIrq(uint8_t irq); // @ambicritical 31 | void MaskPin(uint8_t irq); // @ambicritical 32 | 33 | struct Entry { 34 | unsigned vector : 8; // RW - processor register 35 | unsigned delmode : 3; // RW 36 | unsigned destmode : 1; // RW - determines type for destfield 37 | unsigned delstatus : 1; // RO 38 | unsigned intpol : 1; // RW - 0 = high active, 1 = low active 39 | unsigned remirr : 1; // RO 40 | unsigned triggermode : 1; // 1 = level sensitive, 0 = edge sensitive 41 | unsigned imask : 1; // 1 = prevent this interrupt 42 | unsigned long long reserved : 39; // set this to 0 43 | unsigned destfield : 8; // RW - APIC ID or "set of processors" 44 | } ANSA_PACKED; 45 | 46 | static_assert(sizeof(Entry) == 8, "invalid IOApic::Entry size"); 47 | 48 | private: 49 | ApicTable & table; 50 | ApicTable::IOApic info; 51 | EasyMap map; 52 | 53 | CriticalLock lock; 54 | CriticalLock tableLock; 55 | }; 56 | 57 | } 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/arch/x64/smp/startup-code.cpp: -------------------------------------------------------------------------------- 1 | #include "startup-code.hpp" 2 | #include "../segments/gdt.hpp" 3 | #include "../vmm/global/global-malloc.hpp" 4 | #include "../vmm/global/global-map.hpp" 5 | #include 6 | #include 7 | 8 | extern "C" { 9 | 10 | extern void anarch_proc_entry() __asm__("anarch_proc_entry"); 11 | extern void anarch_proc_entry_end() __asm__("anarch_proc_entry_end"); 12 | 13 | } 14 | 15 | namespace anarch { 16 | 17 | namespace x64 { 18 | 19 | StartupCode::StartupCode(void (*_cb)()) : callbackFunc((uint64_t)_cb) { 20 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 21 | if (!allocator.Alloc(dataBackup, 0x3000)) { 22 | Panic("StartupCode::StartupCode() - failed to allocate backup"); 23 | } 24 | ansa::Memcpy(dataBackup, (void *)PageTableBase, 0x3000); 25 | 26 | // set the PDPT in the dummy PML4 27 | PhysAddr pdpt = GlobalMap::GetGlobal().GetPdpt(); 28 | *((uint64_t *)PageTableBase) = pdpt | 3; 29 | 30 | // copy the GDT pointer 31 | Gdt::Pointer ptr = Gdt::GetGlobal().GetPointer(); 32 | ansa::Memcpy((void *)(PageTableBase + 0x1000), &ptr, sizeof(ptr)); 33 | 34 | // copy the bootstrap code 35 | void * bootstrapCode = (void *)&anarch_proc_entry; 36 | void * bootstrapEnd = (void *)&anarch_proc_entry_end; 37 | uint64_t codeLen = (uint64_t)bootstrapEnd - (uint64_t)bootstrapCode; 38 | assert(codeLen < 0x1000); 39 | ansa::Memcpy((void *)CodeBase, bootstrapCode, codeLen); 40 | } 41 | 42 | StartupCode::~StartupCode() { 43 | ansa::Memcpy((void *)PageTableBase, dataBackup, 0x3000); 44 | 45 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 46 | allocator.Free(dataBackup); 47 | } 48 | 49 | void StartupCode::ResetStartupStack() { 50 | uint64_t * bootstrapStack = (uint64_t *)CodeBase - 2; 51 | PhysAddr pml4 = GlobalMap::GetGlobal().GetPageTable().GetPml4(); 52 | bootstrapStack[0] = (uint64_t)pml4; 53 | bootstrapStack[1] = callbackFunc; 54 | } 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/arch/api/domain.cpp: -------------------------------------------------------------------------------- 1 | #include "domain.hpp" 2 | #include "domain-list.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | bool Domain::Alloc(void *& ptr, size_t size) { 8 | if (GetVirtualAllocator().Alloc(ptr, size)) { 9 | return true; 10 | } 11 | 12 | int siblingCount = DomainList::GetGlobal().GetCount() - 1; 13 | for (int i = 0; i < siblingCount; i++) { 14 | if (GetSibling(i).GetVirtualAllocator().Alloc(ptr, size)) { 15 | return true; 16 | } 17 | } 18 | return false; 19 | } 20 | 21 | void Domain::Free(void * ptr) { 22 | if (GetVirtualAllocator().Owns(ptr)) { 23 | GetVirtualAllocator().Free(ptr); 24 | return; 25 | } 26 | 27 | int siblingCount = DomainList::GetGlobal().GetCount() - 1; 28 | for (int i = 0; i < siblingCount; i++) { 29 | VirtualAllocator & a = GetSibling(i).GetVirtualAllocator(); 30 | if (a.Owns(ptr)) { 31 | a.Free(ptr); 32 | return; 33 | } 34 | } 35 | 36 | Panic("Domain::Free() - no Domain owns the specified memory"); 37 | } 38 | 39 | bool Domain::AllocPhys(PhysAddr & addrOut, PhysSize size, PhysSize align) { 40 | if (GetAllocator().Alloc(addrOut, size, align)) { 41 | return true; 42 | } 43 | 44 | int siblingCount = DomainList::GetGlobal().GetCount() - 1; 45 | for (int i = 0; i < siblingCount; ++i) { 46 | Allocator & a = GetSibling(i).GetAllocator(); 47 | if (a.Alloc(addrOut, size, align)) { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | void Domain::FreePhys(PhysAddr addr) { 56 | if (GetAllocator().Owns(addr)) { 57 | GetAllocator().Free(addr); 58 | return; 59 | } 60 | 61 | int siblingCount = DomainList::GetGlobal().GetCount() - 1; 62 | for (int i = 0; i < siblingCount; ++i) { 63 | Allocator & a = GetSibling(i).GetAllocator(); 64 | if (a.Owns(addr)) { 65 | a.Free(addr); 66 | return; 67 | } 68 | } 69 | 70 | Panic("Domain::FreePhys() - no Domain owns the physical address"); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/arch/x64/timer/lapic-timer.cpp: -------------------------------------------------------------------------------- 1 | #include "lapic-timer.hpp" 2 | #include "../smp/cpu.hpp" 3 | #include "../interrupts/apic/lapic-module.hpp" 4 | #include "../interrupts/vectors.hpp" 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | void LapicTimer::GeneralTimerCallback() { 12 | AssertCritical(); 13 | Cpu & thisCpu = Cpu::GetCurrent(); 14 | LapicTimer & timer = thisCpu.GetLapicTimer(); 15 | Lapic & lapic = thisCpu.GetLapic(); 16 | if (!timer.isExpecting) { 17 | lapic.SendEoi(); 18 | return; 19 | } 20 | 21 | // prevent race conditions with a reset 22 | if (lapic.IsTimerRunning()) { 23 | lapic.SendEoi(); 24 | if (lapic.IsInService(IntVectors::LapicTimer) 25 | || lapic.IsRequested(IntVectors::LapicTimer)) { 26 | return; 27 | } 28 | } else { 29 | lapic.SendEoi(); 30 | } 31 | 32 | timer.isExpecting = false; 33 | timer.callbackFunction(timer.callbackArg); 34 | } 35 | 36 | LapicTimer::LapicTimer() : ticksPerMicro(1, 0), calibrated(false) { 37 | } 38 | 39 | ansa::Rational LapicTimer::GetTicksPerMicro() { 40 | return ticksPerMicro; 41 | } 42 | 43 | void LapicTimer::SetTimeout(uint64_t ticks, void (* func)()) { 44 | SetTimeout(ticks, (void (*)(void *))func, NULL); 45 | } 46 | 47 | void LapicTimer::SetTimeout(uint64_t ticks, void (* fn)(void *), void * arg) { 48 | AssertCritical(); 49 | assert(ticks < 0x100000000); // TODO: support bigger times 50 | Lapic & lapic = Cpu::GetCurrent().GetLapic(); 51 | lapic.SetTimeout(IntVectors::LapicTimer, (uint32_t)ticks); 52 | isExpecting = true; 53 | callbackFunction = fn; 54 | callbackArg = arg; 55 | } 56 | 57 | void LapicTimer::ClearTimeout() { 58 | AssertCritical(); 59 | Lapic & lapic = Cpu::GetCurrent().GetLapic(); 60 | lapic.ClearTimeout(); 61 | isExpecting = false; 62 | } 63 | 64 | void LapicTimer::WaitTimeout() { 65 | AssertCritical(); 66 | SetCritical(false); 67 | while (1) { 68 | __asm__ __volatile__("hlt"); 69 | } 70 | } 71 | 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/arch/api/syscall-ret.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_SYSCALL_RET_HPP__ 2 | #define __ANARCH_API_SYSCALL_RET_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace anarch { 10 | 11 | /** 12 | * The return value for a system call. This may be an error value. 13 | */ 14 | struct SyscallRet { 15 | union { 16 | bool boolean; 17 | int integer; 18 | uint32_t integer32; 19 | uint64_t integer64; 20 | PhysAddr phys; 21 | VirtAddr virt; 22 | PhysSize pSize; 23 | size_t vSize; 24 | } value; 25 | 26 | int errorValue = 0; 27 | 28 | static inline SyscallRet Error(int code) { 29 | assert(code != 0); 30 | SyscallRet r; 31 | r.errorValue = code; 32 | return r; 33 | } 34 | 35 | static inline SyscallRet Empty() { 36 | SyscallRet r; 37 | r.value.boolean = true; 38 | return r; 39 | } 40 | 41 | static inline SyscallRet Boolean(bool b) { 42 | SyscallRet r; 43 | r.value.boolean = b; 44 | return r; 45 | } 46 | 47 | static inline SyscallRet Integer(int i) { 48 | SyscallRet r; 49 | r.value.integer = i; 50 | return r; 51 | } 52 | 53 | static inline SyscallRet Integer32(uint32_t i) { 54 | SyscallRet r; 55 | r.value.integer32 = i; 56 | return r; 57 | } 58 | 59 | static inline SyscallRet Integer64(uint64_t i) { 60 | SyscallRet r; 61 | r.value.integer64 = i; 62 | return r; 63 | } 64 | 65 | static inline SyscallRet Phys(PhysAddr p) { 66 | SyscallRet r; 67 | r.value.phys = p; 68 | return r; 69 | } 70 | 71 | static inline SyscallRet Virt(VirtAddr v) { 72 | SyscallRet r; 73 | r.value.virt = v; 74 | return r; 75 | } 76 | 77 | static inline SyscallRet PhysSize(PhysSize p) { 78 | SyscallRet r; 79 | r.value.pSize = p; 80 | return r; 81 | } 82 | 83 | static inline SyscallRet VirtSize(size_t s) { 84 | SyscallRet r; 85 | r.value.vSize = s; 86 | return r; 87 | } 88 | }; 89 | 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/ioapic-module.cpp: -------------------------------------------------------------------------------- 1 | #include "ioapic-module.hpp" 2 | #include "../../common.hpp" 3 | #include "../../acpi/acpi-module.hpp" 4 | #include "../../critical/module.hpp" 5 | #include "../../vmm/global/global-malloc.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace anarch { 12 | 13 | namespace x64 { 14 | 15 | namespace { 16 | 17 | IOApicModule gIOApicModule; 18 | 19 | } 20 | 21 | void IOApicModule::InitGlobal() { 22 | new(&gIOApicModule) IOApicModule(); 23 | } 24 | 25 | IOApicModule & IOApicModule::GetGlobal() { 26 | return gIOApicModule; 27 | } 28 | 29 | IOApic & IOApicModule::GetBaseIOApic() { 30 | return *baseIOApic; 31 | } 32 | 33 | ansa::DepList IOApicModule::GetDependencies() { 34 | return ansa::DepList(&AcpiModule::GetGlobal(), &GlobalMalloc::GetGlobal(), 35 | &StreamModule::GetGlobal(), 36 | &CriticalModule::GetGlobal()); 37 | } 38 | 39 | void IOApicModule::Initialize() { 40 | cout << "Initializing I/O APIC..." << endl; 41 | 42 | if (!AcpiModule::GetGlobal().GetApicTable()) { 43 | Panic("IOApicModule::Initialize() - no APIC table in ACPI"); 44 | } 45 | ApicTable & table = *AcpiModule::GetGlobal().GetApicTable(); 46 | ApicTable::IOApic * info = table.LookupIOApic(0); 47 | if (!info) { 48 | Panic("IOApicModule::Initialize() - no base I/O APIC"); 49 | } 50 | 51 | VirtualAllocator & allocator = GlobalMalloc::GetGlobal().GetAllocator(); 52 | baseIOApic = allocator.New(table, info); 53 | assert(baseIOApic != NULL); 54 | 55 | // mask every pin before enabling I/O APIC 56 | for (uint32_t i = 0; i < GetBaseIOApic().GetPinCount(); i++) { 57 | GetBaseIOApic().MaskPin(i); 58 | } 59 | 60 | // enable I/O APIC on all motherboards 61 | SetCritical(true); 62 | OutB(0x22, 0x70); 63 | OutB(0x23, 0x01); 64 | SetCritical(false); 65 | 66 | cout << "Initialized I/O APIC; version=" << baseIOApic->GetVersion() << endl; 67 | } 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/isr.cpp: -------------------------------------------------------------------------------- 1 | #include "isr.hpp" 2 | #include "irt.hpp" 3 | #include "../common.hpp" 4 | #include "../segments/local-segment.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | typedef void (* RoutineCall)(anarch::x64::IsrStack * stack, uint64_t code); 10 | 11 | extern "C" { 12 | 13 | void InterruptCoded(uint64_t vector, anarch::x64::IsrStack * stack, 14 | uint64_t code) { 15 | anarch::x64::LocalSegment::SwapScope scope(vector, *stack); 16 | 17 | // special automatic delegate forwarding 18 | if (vector == 0xe) { 19 | uint64_t addr; 20 | __asm__("mov %%cr2, %0" : "=r" (addr)); 21 | // send the page fault to the delegate if it's set 22 | if (anarch::GetGlobalPageDelegate()) { 23 | anarch::GetGlobalPageDelegate()(addr, (code & 2) != 0); 24 | return; 25 | } 26 | } 27 | 28 | void * routine = anarch::x64::Irt::GetGlobal().Get((uint8_t)vector); 29 | if (routine) { 30 | ((RoutineCall)routine)(stack, code); 31 | } else if (vector < 0xf0) { 32 | anarch::cerr << "InterruptCoded(" << vector << ", " << (uint64_t)stack 33 | << ", " << code << ") - caller=" << stack->rip << anarch::endl; 34 | anarch::Panic("unhandled exception"); 35 | } 36 | } 37 | 38 | void InterruptNonCoded(uint64_t vector, anarch::x64::IsrStack * stack) { 39 | anarch::x64::LocalSegment::SwapScope scope(vector, *stack); 40 | 41 | void * routine = anarch::x64::Irt::GetGlobal().Get((uint8_t)vector); 42 | if (routine) { 43 | ((RoutineCall)routine)(stack, 0); 44 | } else if (vector < 0xf0) { 45 | anarch::cerr << "InterruptCoded(" << vector << ", " << (uint64_t)stack 46 | << ") - caller=" << stack->rip << anarch::endl; 47 | anarch::Panic("unhandled interrupt"); 48 | } 49 | } 50 | 51 | void InterruptPicEoi(uint64_t vector, anarch::x64::IsrStack *) { 52 | anarch::cout << " - Sending legacy PIC an EOI" << anarch::endl; 53 | if (vector > 0xf) { 54 | anarch::x64::OutB(0xa0, 0x20); 55 | } 56 | anarch::x64::OutB(0x20, 0x20); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/arch/api/thread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_THREAD_HPP__ 2 | #define __ANARCH_API_THREAD_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | class Domain; 10 | class Timer; 11 | 12 | /** 13 | * Represents a hardware thread, not a software thread! 14 | */ 15 | class Thread : public ansa::NoCopy { 16 | public: 17 | static void * GetUserInfo(); // @critical 18 | static void SetUserInfo(void *); // @critical 19 | 20 | /** 21 | * Run a method on this hardware thread on a CPU stack. You should only call 22 | * this method if no [State] is currently being run. 23 | * @critical 24 | */ 25 | static void RunSync(void (*)()) ANSA_NORETURN; 26 | 27 | /** 28 | * Like the other [RunSync], but with an argument for the routine. 29 | * @critical 30 | */ 31 | static void RunSync(void (*)(void *), void *) ANSA_NORETURN; 32 | 33 | static Thread & GetCurrent(); // @critical 34 | 35 | virtual Domain & GetDomain() = 0; // @ambicritical 36 | 37 | virtual Timer & GetTimer() = 0; // @critical 38 | 39 | /** 40 | * Return a domain-local priority for this thread. This way, you can make one 41 | * core for each physical CPU a higher priority than the next, etc., and 42 | * influence some sort of scheduler to avoid using hyperthreads unless it is 43 | * needed. 44 | * @ambicritical 45 | */ 46 | virtual int GetPriority() = 0; 47 | 48 | /** 49 | * Asynchronously send this Thread a message by causing it to run a function. 50 | * If this is called multiple times before the thread receives a message, the 51 | * thread may not receive every message, but it will receive at least one. 52 | * 53 | * The specified function will run in a critical section. 54 | * 55 | * @critical 56 | */ 57 | virtual void RunAsync(void (*)()) = 0; 58 | 59 | /** 60 | * Same as the other RunAsync, but allows you to pass an argument to the 61 | * specified function. 62 | * @critical 63 | */ 64 | virtual void RunAsync(void (*)(void *), void *) = 0; 65 | }; 66 | 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/arch/x64/clock/pit.cpp: -------------------------------------------------------------------------------- 1 | #include "pit.hpp" 2 | #include "../interrupts/irt.hpp" 3 | #include "../interrupts/vectors.hpp" 4 | #include "../interrupts/apic/ioapic-module.hpp" 5 | #include "../interrupts/apic/lapic-module.hpp" 6 | #include "../common.hpp" 7 | #include 8 | 9 | namespace anarch { 10 | 11 | namespace x64 { 12 | 13 | namespace { 14 | 15 | Pit * currentPit = NULL; 16 | 17 | } 18 | 19 | Pit::Pit(uint16_t _divisor) : divisor(_divisor) { 20 | } 21 | 22 | void Pit::Start() { 23 | AssertNoncritical(); 24 | // map Pit in the IOAPIC and the IRT 25 | assert(currentPit == NULL); 26 | 27 | counter = 0; 28 | 29 | // set the PIT frequency 30 | SetCritical(true); 31 | OutB(0x43, 0x34); // channel 0, lobyte/hibyte, rate generator 32 | OutB(0x40, (uint8_t)divisor); 33 | OutB(0x40, (uint8_t)(divisor >> 8)); 34 | SetCritical(false); 35 | 36 | currentPit = this; 37 | Irt::GetGlobal().Set(IntVectors::Pit, (void *)&InterruptHandler); 38 | IOApic & ioApic = IOApicModule::GetGlobal().GetBaseIOApic(); 39 | ioApic.MapIrq(0, IntVectors::Pit); 40 | } 41 | 42 | void Pit::Stop() { 43 | AssertNoncritical(); 44 | assert(currentPit == this); 45 | 46 | currentPit = NULL; 47 | 48 | // set the PIT to the highest divide just for kicks 49 | OutB(0x43, 0x34); // channel 0, lobyte/hibyte, rate generator 50 | OutB(0x40, 0xff); 51 | OutB(0x40, 0xff); 52 | 53 | IOApic & ioApic = IOApicModule::GetGlobal().GetBaseIOApic(); 54 | ioApic.MaskIrq(IntVectors::Pit); 55 | 56 | // don't unset the handler in the IRT because there may be another PIT 57 | // interrupt pending on some CPU which would cause a race condition 58 | } 59 | 60 | uint64_t Pit::GetTicks() { 61 | return counter; 62 | } 63 | 64 | ansa::Rational Pit::GetMicrosPerTick() { 65 | // return (micros / second) / (ticks / second) 66 | return ansa::Rational(1000000, 1193182UL / divisor); 67 | } 68 | 69 | void Pit::InterruptHandler() { 70 | AssertCritical(); 71 | if (currentPit) { 72 | ++currentPit->counter; 73 | } 74 | LapicModule::GetGlobal().GetLapic().SendEoi(); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/arch/api/allocator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_API_ALLOCATOR_HPP__ 2 | #define __ANARCH_API_ALLOCATOR_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | class Allocator : public ansa::NoCopy { 11 | public: 12 | /** 13 | * Allocate aligned physical memory. 14 | * @noncritical 15 | */ 16 | virtual bool Alloc(PhysAddr & result, PhysSize size, PhysSize align) = 0; 17 | 18 | /** 19 | * Free physical memory. 20 | * @noncritical 21 | */ 22 | virtual void Free(PhysAddr address) = 0; 23 | 24 | /** 25 | * Returns `false` if `address` could not have been allocated by this 26 | * physical allocator 27 | * @noncritical 28 | */ 29 | virtual bool Owns(PhysAddr address) = 0; 30 | 31 | /** 32 | * Get the amount of physical memory in use by the system. 33 | * @noncritical 34 | */ 35 | virtual PhysSize Used() = 0; 36 | 37 | /** 38 | * Get the amount of unused physical memory available to the system. 39 | * @noncritical 40 | */ 41 | virtual PhysSize Available() = 0; 42 | 43 | /** 44 | * Get the amount of total physical memory on the system. 45 | * @noncritical 46 | */ 47 | virtual PhysSize Total() = 0; 48 | 49 | /** 50 | * Allocate physical memory and map it into contiguous virtual memory. 51 | * @noncritical 52 | */ 53 | virtual bool AllocAndMap(VirtAddr &, size_t, bool bigPages = true); 54 | 55 | /** 56 | * Do the inverse of AllocAndMap(). This method looks up each page, unmaps 57 | * it, frees it, and moves on to the next one. 58 | * @noncritical 59 | */ 60 | virtual void FreeAndUnmap(VirtAddr addr, size_t size); 61 | 62 | /** 63 | * Attempt to allocate a contiguous buffer of pages and map it into the 64 | * global address space. 65 | * @noncritical 66 | */ 67 | virtual bool AllocAndMapContiguous(VirtAddr &, size_t, 68 | bool bigPages = true); 69 | 70 | /** 71 | * Attempt to free a contiguous buffer of pages and unmap it from the global 72 | * address space. 73 | * @noncritical 74 | */ 75 | virtual void FreeAndUnmapContiguous(VirtAddr, size_t); 76 | }; 77 | 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/arch/x64/segments/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include "gdt.hpp" 2 | #include "../vmm/global/global-malloc.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | namespace { 13 | 14 | Gdt gGdt; 15 | 16 | } 17 | 18 | Gdt::Pointer Gdt::Pointer::GetCurrent() { 19 | AssertCritical(); 20 | Pointer result; 21 | __asm__ __volatile__("sgdt (%0)" : : "r" (&result)); 22 | return result; 23 | } 24 | 25 | void Gdt::InitGlobal() { 26 | new(&gGdt) Gdt(); 27 | } 28 | 29 | Gdt & Gdt::GetGlobal() { 30 | return gGdt; 31 | } 32 | 33 | uint16_t Gdt::PushShortDescriptor(const ShortDescriptor & desc) { 34 | assert(amountUsed + 8 <= 0x10000); 35 | uint16_t sel = (uint16_t)amountUsed; 36 | ansa::Memcpy((void *)((uint64_t)buffer + amountUsed), (void *)&desc, 8); 37 | amountUsed += 8; 38 | return sel; 39 | } 40 | 41 | uint16_t Gdt::PushTssDescriptor(const TssDescriptor & desc) { 42 | assert(amountUsed + 0x10 <= 0x10000); 43 | uint16_t sel = (uint16_t)amountUsed; 44 | ansa::Memcpy((void *)((uint64_t)buffer + amountUsed), (void *)&desc, 0x10); 45 | amountUsed += 0x10; 46 | return sel; 47 | } 48 | 49 | void Gdt::Set() { 50 | AssertCritical(); 51 | Pointer ptr = GetPointer(); 52 | __asm__ __volatile__("lgdt (%0)" : : "r" (&ptr)); 53 | } 54 | 55 | Gdt::Pointer Gdt::GetPointer() { 56 | Pointer ptr = {0xffff, (uint64_t)buffer}; 57 | return ptr; 58 | } 59 | 60 | ansa::DepList Gdt::GetDependencies() { 61 | return ansa::DepList(&GlobalMalloc::GetGlobal()); 62 | } 63 | 64 | void Gdt::Initialize() { 65 | if (!GlobalMalloc::GetGlobal().GetAllocator().Alloc(buffer, 0x10000)) { 66 | Panic("Gdt::Initialize() - failed to allocate buffer"); 67 | } 68 | ansa::Bzero(buffer, 0x10000); 69 | 70 | amountUsed = 8; 71 | 72 | // code, data, user data, user code 73 | PushShortDescriptor(ShortDescriptor(true, true)); // kernel code 74 | PushShortDescriptor(ShortDescriptor(true, false)); // kernel data 75 | PushShortDescriptor(ShortDescriptor(false, false)); // user data 76 | PushShortDescriptor(ShortDescriptor(false, true)); // user code 77 | 78 | ScopedCritical critical; 79 | Set(); 80 | } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/arch/x64/interrupts/apic/ioapic.cpp: -------------------------------------------------------------------------------- 1 | #include "ioapic.hpp" 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | IOApic::IOApic(ApicTable & _table, ApicTable::IOApic * _info) 10 | : table(_table), info(*_info), map((PhysAddr)info.baseAddr, 20) { 11 | } 12 | 13 | void IOApic::WriteReg(uint8_t reg, uint32_t val) { 14 | ScopedCritical critical; 15 | ScopedLock scope(lock); 16 | 17 | volatile uint32_t * regs = (volatile uint32_t *)map.GetStart(); 18 | regs[0] = reg; 19 | regs[4] = val; 20 | } 21 | 22 | uint32_t IOApic::ReadReg(uint8_t reg) { 23 | ScopedCritical critical; 24 | ScopedLock scope(lock); 25 | 26 | volatile uint32_t * regs = (volatile uint32_t *)map.GetStart(); 27 | regs[0] = reg; 28 | return regs[4]; 29 | } 30 | 31 | uint32_t IOApic::GetVersion() { 32 | return ReadReg(RegVersion) & 0xff; 33 | } 34 | 35 | uint32_t IOApic::GetPinCount() { 36 | return 1 + ((ReadReg(RegVersion) >> 0x10) & 0xff); 37 | } 38 | 39 | uint32_t IOApic::GetInterruptBase() { 40 | return info.interruptBase; 41 | } 42 | 43 | void IOApic::SetEntry(uint8_t idx, const Entry & entry) { 44 | ScopedCritical critical; 45 | ScopedLock scope(tableLock); 46 | 47 | const uint32_t * valPtr = (const uint32_t *)&entry; 48 | WriteReg(0x10 + (idx * 2) , 0x10000); // mask the entry 49 | WriteReg(0x11 + (idx * 2), valPtr[1]); 50 | WriteReg(0x10 + (idx * 2), valPtr[0]); 51 | } 52 | 53 | void IOApic::MapIrq(uint8_t irq, uint8_t vector) { 54 | Entry entry; 55 | ansa::Bzero(&entry, sizeof(entry)); 56 | entry.vector = vector; 57 | 58 | ApicTable::Iso * iso = table.LookupIso(irq); 59 | if (iso) { 60 | if (iso->flags & 0x3) entry.intpol = 1; 61 | if ((iso->flags >> 2) & 0x3) entry.triggermode = 1; 62 | SetEntry(iso->interrupt, entry); 63 | } else { 64 | SetEntry(irq, entry); 65 | } 66 | } 67 | 68 | void IOApic::MaskIrq(uint8_t irq) { 69 | ApicTable::Iso * iso = table.LookupIso(irq); 70 | if (iso) { 71 | MaskPin(iso->interrupt); 72 | } else { 73 | MaskPin(irq); 74 | } 75 | } 76 | 77 | void IOApic::MaskPin(uint8_t irq) { 78 | ScopedCritical critical; 79 | ScopedLock scope(tableLock); 80 | 81 | WriteReg(0x10 + (irq * 2), 0x10000); 82 | } 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/util/stream.cpp: -------------------------------------------------------------------------------- 1 | #include "stream.hpp" 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | static StreamModule gModule; 8 | ConsoleOutStream cout; 9 | ConsoleErrorStream cerr; 10 | const char * endl = "\n"; 11 | 12 | void StreamModule::InitGlobal() { 13 | new(&gModule) StreamModule(); 14 | } 15 | 16 | StreamModule & StreamModule::GetGlobal() { 17 | return gModule; 18 | } 19 | 20 | ansa::DepList StreamModule::GetDependencies() { 21 | return ansa::DepList(&Console::GetGlobal()); 22 | } 23 | 24 | void StreamModule::Initialize() { 25 | new(&cout) ConsoleOutStream(); 26 | new(&cerr) ConsoleErrorStream(); 27 | } 28 | 29 | void ConsoleOutStream::Puts(const char * str) { 30 | Console::GetGlobal().SetColor(Console::ColorLightGray, true); 31 | Console::GetGlobal().PrintString(str); 32 | } 33 | 34 | void ConsoleErrorStream::Puts(const char * str) { 35 | Console::GetGlobal().SetColor(Console::ColorRed, true); 36 | Console::GetGlobal().PrintString(str); 37 | } 38 | 39 | OutStream & operator<<(OutStream & stream, unsigned char num) { 40 | return stream << (unsigned long long)num; 41 | } 42 | 43 | OutStream & operator<<(OutStream & stream, unsigned short num) { 44 | return stream << (unsigned long long)num; 45 | } 46 | 47 | OutStream & operator<<(OutStream & stream, unsigned int num) { 48 | return stream << (unsigned long long)num; 49 | } 50 | 51 | OutStream & operator<<(OutStream & stream, unsigned long num) { 52 | return stream << (unsigned long long)num; 53 | } 54 | 55 | OutStream & operator<<(OutStream & stream, unsigned long long number) { 56 | const char * chars = "0123456789abcdef"; 57 | unsigned char _buf[32] = {0}; 58 | _buf[0] = '0'; 59 | _buf[1] = 'x'; 60 | unsigned char * buf = _buf + 2; 61 | unsigned char len = 2, i; 62 | do { 63 | unsigned char nextDig = (unsigned char)(number & 0xf); 64 | buf[len++] = chars[nextDig]; 65 | number >>= 4; 66 | } while (number > 0); 67 | for (i = 0; i < len / 2; i++) { 68 | unsigned char a = buf[len - i - 1]; 69 | buf[len - i - 1] = buf[i]; 70 | buf[i] = a; 71 | } 72 | stream.Puts((const char *)_buf); 73 | return stream; 74 | } 75 | 76 | OutStream & operator<<(OutStream & stream, const char * str) { 77 | stream.Puts(str); 78 | return stream; 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /test/build-objects: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Generated by CoffeeScript 1.7.1 4 | (function() { 5 | var CompilerCommand, compiler, path, spawn; 6 | 7 | path = require('path'); 8 | 9 | spawn = require('child_process').spawn; 10 | 11 | if (process.argv.length < 4) { 12 | console.error('Usage: build-objects [flags ...]' + ' [sources ...] [-o output dir]'); 13 | process.exit(1); 14 | } 15 | 16 | CompilerCommand = (function() { 17 | function CompilerCommand(_arguments) { 18 | var i, x, _i, _len, _ref; 19 | this["arguments"] = _arguments; 20 | this.outputDir = '.'; 21 | this.files = []; 22 | if (this["arguments"][this["arguments"].length - 2] === '-o') { 23 | this.outputDir = this["arguments"].pop(); 24 | this["arguments"].pop(); 25 | } 26 | _ref = this["arguments"]; 27 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 28 | x = _ref[i]; 29 | if (i === 0) { 30 | continue; 31 | } 32 | if (x[0] !== '-') { 33 | this.files = this["arguments"].slice(i); 34 | this["arguments"] = this["arguments"].slice(0, i); 35 | break; 36 | } 37 | } 38 | } 39 | 40 | CompilerCommand.prototype.objectPath = function(source) { 41 | var bn, objName; 42 | bn = path.basename(source); 43 | objName = bn.slice(0, bn.length - path.extname(bn).length) + '.o'; 44 | return path.join(this.outputDir, objName); 45 | }; 46 | 47 | CompilerCommand.prototype.compileNext = function() { 48 | var file, flags, task; 49 | if (this.files.length === 0) { 50 | return; 51 | } 52 | file = this.files.pop(); 53 | flags = this["arguments"].slice(1).concat([file, '-o', this.objectPath(file)]); 54 | console.log(this["arguments"][0] + ' ' + flags.join(' ')); 55 | task = spawn(this["arguments"][0], flags, { 56 | stdio: 'inherit' 57 | }); 58 | return task.on('close', (function(_this) { 59 | return function(code) { 60 | if (code !== 0) { 61 | process.exit(code); 62 | } 63 | return _this.compileNext(); 64 | }; 65 | })(this)); 66 | }; 67 | 68 | return CompilerCommand; 69 | 70 | })(); 71 | 72 | compiler = new CompilerCommand(process.argv.slice(2)); 73 | 74 | compiler.compileNext(); 75 | 76 | }).call(this); 77 | -------------------------------------------------------------------------------- /src/arch/x64/syscall/module.cpp: -------------------------------------------------------------------------------- 1 | #include "module.hpp" 2 | #include "args.hpp" 3 | #include "handler.hpp" 4 | #include "../common.hpp" 5 | #include "../interrupts/idt.hpp" 6 | #include "../domains/domain-list.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace anarch { 12 | 13 | SyscallModule & SyscallModule::GetGlobal() { 14 | return x64::SyscallModule::GetGlobal(); 15 | } 16 | 17 | namespace x64 { 18 | 19 | namespace { 20 | 21 | SyscallModule gModule; 22 | 23 | } 24 | 25 | void SyscallModule::InitGlobal() { 26 | new(&gModule) SyscallModule(); 27 | } 28 | 29 | SyscallModule & SyscallModule::GetGlobal() { 30 | return gModule; 31 | } 32 | 33 | void SyscallModule::SetHandler(SyscallHandler h) { 34 | assert(!handler); 35 | handler = h; 36 | } 37 | 38 | SyscallModule::SyscallHandler SyscallModule::GetHandler() { 39 | return handler; 40 | } 41 | 42 | ansa::DepList SyscallModule::GetDependencies() { 43 | return ansa::DepList(&DomainList::GetGlobal()); 44 | } 45 | 46 | void SyscallModule::Initialize() { 47 | anarch::ScopedCritical critical; 48 | 49 | // send an IPI to each CPU to setup the syscall registers 50 | DomainList & domains = DomainList::GetGlobal(); 51 | for (int i = 0; i < domains.GetCount(); ++i) { 52 | Domain & domain = domains[i]; 53 | for (int j = 0; j < domain.GetThreadCount(); ++j) { 54 | Thread & th = domain.GetThread(j); 55 | if (&th == &Thread::GetCurrent()) continue; 56 | th.RunAsync(&SetCpuRegisters); 57 | ++initCount; 58 | } 59 | } 60 | ++initCount; 61 | SetCpuRegisters(); 62 | while (initCount); 63 | } 64 | 65 | void SyscallModule::SetCpuRegisters() { 66 | // these are important because a SYSCALL handler sets the user-stack back 67 | // before returning and enabling interrupts. 68 | Idt::GetGlobal().SetIst(0x2, 1); // NMI 69 | Idt::GetGlobal().SetIst(0x12, 1); // MCE 70 | 71 | ScopedCritical critical; 72 | --(SyscallModule::GetGlobal().initCount); 73 | uint64_t star = (8L << 0x20) | (0x13L << 0x30); 74 | WriteMsr(MsrSTAR, star); 75 | WriteMsr(MsrSFMask, 0x200); // disable interrupts 76 | WriteMsr(MsrLSTAR, (uint64_t)AnarchRawSyscallHandler); 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | anarch::SyscallRet AnarchSyscallMainEntry(uint64_t a, uint64_t b, uint64_t c, 84 | uint64_t d, uint64_t e, uint64_t f) { 85 | AssertCritical(); 86 | auto & module = anarch::x64::SyscallModule::GetGlobal(); 87 | auto handler = module.GetHandler(); 88 | assert(handler != NULL); 89 | anarch::x64::SyscallArgs args(b, c, d, e, f); 90 | return handler((uint16_t)a, args); 91 | } 92 | -------------------------------------------------------------------------------- /src/arch/x64/timer/module.cpp: -------------------------------------------------------------------------------- 1 | #include "module.hpp" 2 | #include "../domains/domain-list.hpp" 3 | #include "../clock/module.hpp" 4 | #include "../interrupts/vectors.hpp" 5 | #include "../interrupts/irt.hpp" 6 | #include "../interrupts/apic/lapic-module.hpp" 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | namespace x64 { 13 | 14 | namespace { 15 | 16 | TimerModule gTimerModule; 17 | 18 | } 19 | 20 | void TimerModule::InitGlobal() { 21 | new(&gTimerModule) TimerModule(); 22 | } 23 | 24 | TimerModule & TimerModule::GetGlobal() { 25 | return gTimerModule; 26 | } 27 | 28 | ansa::DepList TimerModule::GetDependencies() { 29 | return ansa::DepList(&DomainList::GetGlobal()); 30 | } 31 | 32 | void TimerModule::Initialize() { 33 | ScopedCritical critical; 34 | 35 | cout << "Initializing LAPIC timer subsystem..."; 36 | 37 | DomainList & domains = DomainList::GetGlobal(); 38 | for (int i = 0; i < domains.GetCount(); i++) { 39 | Domain & domain = domains[i]; 40 | for (int i = 0; i < domain.GetThreadCount(); i++) { 41 | Thread & thread = domain.GetThread(i); 42 | if (&thread == &Thread::GetCurrent()) continue; 43 | thread.RunAsync(CalibrateMethod); 44 | } 45 | } 46 | 47 | CalibrateMethod(); 48 | 49 | // wait until every CPU is calibrated 50 | for (int i = 0; i < domains.GetCount(); i++) { 51 | Domain & domain = domains[i]; 52 | for (int i = 0; i < domain.GetThreadCount(); i++) { 53 | LapicTimer & timer = domain.GetCpu(i).GetLapicTimer(); 54 | // we must leave our critical section while we poll because the PIT timer 55 | // may require interrupts on the boot CPU. 56 | SetCritical(false); 57 | while (!timer.calibrated) { 58 | __asm__ __volatile__("pause"); 59 | } 60 | SetCritical(true); 61 | } 62 | } 63 | 64 | Irt::GetGlobal().Set(IntVectors::LapicTimer, 65 | (void *)&LapicTimer::GeneralTimerCallback); 66 | 67 | cout << " [OK]" << endl; 68 | } 69 | 70 | void TimerModule::CalibrateMethod() { 71 | AssertCritical(); 72 | LapicTimer & timer = Cpu::GetCurrent().GetLapicTimer(); 73 | 74 | Lapic & lapic = LapicModule::GetGlobal().GetLapic(); 75 | lapic.WriteReg(Lapic::RegLvtTimer, 0xff); 76 | lapic.WriteReg(Lapic::RegTimerInitCount, 0xffffffff); 77 | 78 | SetCritical(false); 79 | ClockModule::GetGlobal().GetClock().MicroSleep(500000); 80 | SetCritical(true); 81 | 82 | uint64_t value = lapic.ReadReg(Lapic::RegTimerCurrCount); 83 | lapic.ClearTimeout(); 84 | 85 | assert(value > 0); 86 | 87 | uint64_t ticksPerSec = (uint64_t)(0xffffffff - value) * 2; 88 | timer.ticksPerMicro = ansa::Rational(ticksPerSec, 1000000); 89 | timer.calibrated = true; 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/arch/x64/include/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_STDINT_H__ 2 | #define __ANARCH_X64_STDINT_H__ 3 | 4 | typedef unsigned char uint8_t; 5 | typedef unsigned short uint16_t; 6 | typedef unsigned int uint32_t; 7 | 8 | #ifdef __LP64 9 | typedef unsigned long uint64_t; 10 | #else 11 | typedef unsigned long long uint64_t; 12 | #endif 13 | 14 | typedef char int8_t; 15 | typedef short int16_t; 16 | typedef int int32_t; 17 | 18 | #ifdef __LP64 19 | typedef long int64_t; 20 | #else 21 | typedef long long int64_t; 22 | #endif 23 | 24 | typedef int64_t intptr_t; 25 | typedef uint64_t uintptr_t; 26 | typedef int64_t intmax_t; 27 | typedef uint64_t uintmax_t; 28 | 29 | typedef int8_t int_fast8_t; 30 | typedef int16_t int_fast16_t; 31 | typedef int32_t int_fast32_t; 32 | typedef int64_t int_fast64_t; 33 | 34 | typedef uint8_t uint_fast8_t; 35 | typedef uint16_t uint_fast16_t; 36 | typedef uint32_t uint_fast32_t; 37 | typedef uint64_t uint_fast64_t; 38 | 39 | typedef uint8_t uint_least8_t; 40 | typedef uint16_t uint_least16_t; 41 | typedef uint32_t uint_least32_t; 42 | typedef uint64_t uint_least64_t; 43 | 44 | typedef int8_t int_least8_t; 45 | typedef int16_t int_least16_t; 46 | typedef int32_t int_least32_t; 47 | typedef int64_t int_least64_t; 48 | 49 | #define UINT8_MAX 0xff 50 | #define UINT16_MAX 0xffff 51 | #define UINT32_MAX 0xffffffff 52 | #define UINT64_MAX 0xffffffffffffffff 53 | 54 | #define INT8_MIN -0x80 55 | #define INT8_MAX 0x7f 56 | #define INT16_MIN -0x8000 57 | #define INT16_MAX 0x7fff 58 | #define INT32_MIN -0x80000000 59 | #define INT32_MAX 0x7fffffff 60 | #define INT64_MIN -0x8000000000000000L 61 | #define INT64_MAX 0x7fffffffffffffffL 62 | 63 | #define INT_FAST8_MIN INT8_MIN 64 | #define INT_FAST16_MIN INT16_MIN 65 | #define INT_FAST32_MIN INT32_MIN 66 | #define INT_FAST64_MIN INT64_MIN 67 | #define INT_LEAST8_MIN INT8_MIN 68 | #define INT_LEAST16_MIN INT16_MIN 69 | #define INT_LEAST32_MIN INT32_MIN 70 | #define INT_LEAST64_MIN INT64_MIN 71 | 72 | #define INT_FAST8_MAX INT8_MAX 73 | #define INT_FAST16_MAX INT16_MAX 74 | #define INT_FAST32_MAX INT32_MAX 75 | #define INT_FAST64_MAX INT64_MAX 76 | #define INT_LEAST8_MAX INT8_MAX 77 | #define INT_LEAST16_MAX INT16_MAX 78 | #define INT_LEAST32_MAX INT32_MAX 79 | #define INT_LEAST64_MAX INT64_MAX 80 | 81 | #define UINT_FAST8_MAX UINT8_MAX 82 | #define UINT_FAST16_MAX UINT16_MAX 83 | #define UINT_FAST32_MAX UINT32_MAX 84 | #define UINT_FAST64_MAX UINT64_MAX 85 | #define UINT_LEAST8_MAX UINT8_MAX 86 | #define UINT_LEAST16_MAX UINT16_MAX 87 | #define UINT_LEAST32_MAX UINT32_MAX 88 | #define UINT_LEAST64_MAX UINT64_MAX 89 | 90 | #define INTMAX_MIN INT64_MIN 91 | #define INTMAX_MAX INT64_MAX 92 | #define INTPTR_MAX INT64_MAX 93 | #define INTPTR_MIN INT64_MIN 94 | #define UINTMAX_MAX UINT64_MAX 95 | #define UINTPTR_MAX UINT64_MAX 96 | 97 | #endif /* __ANARCH_X64_STDINT_H__ */ 98 | -------------------------------------------------------------------------------- /src/memory/malloc.cpp: -------------------------------------------------------------------------------- 1 | #include "malloc.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace anarch { 7 | 8 | Malloc::Malloc(size_t pool, Allocator & _allocator, bool _bigPages) 9 | : poolSize(pool), bigPages(_bigPages), allocator(_allocator) { 10 | } 11 | 12 | Malloc::~Malloc() { 13 | AssertNoncritical(); 14 | while (firstSegment) { 15 | Segment * next = firstSegment->next; 16 | allocator.FreeAndUnmap((PhysAddr)next, poolSize); 17 | firstSegment = next; 18 | } 19 | } 20 | 21 | bool Malloc::Alloc(void *& addr, size_t size) { 22 | if (size >= poolSize / 2) return false; 23 | 24 | if (!AllocNoNewSegment(addr, size)) { 25 | if (!CreateSegment()) return false; 26 | return AllocNoNewSegment(addr, size); 27 | } 28 | return true; 29 | } 30 | 31 | void Malloc::Free(void * addr) { 32 | AssertNoncritical(); 33 | firstLock.Seize(); 34 | Segment * segment = firstSegment; 35 | firstLock.Release(); 36 | 37 | while (segment) { 38 | ScopedLock scope(segment->lock); 39 | if (segment->allocator->OwnsPointer(addr)) { 40 | segment->allocator->Free(addr); 41 | return; 42 | } 43 | } 44 | 45 | Panic("Malloc::Free() - unowned memory region"); 46 | } 47 | 48 | bool Malloc::Owns(void * ptr) { 49 | AssertNoncritical(); 50 | firstLock.Seize(); 51 | Segment * segment = firstSegment; 52 | firstLock.Release(); 53 | 54 | while (segment) { 55 | ScopedLock scope(segment->lock); 56 | if (segment->allocator->OwnsPointer(ptr)) { 57 | return true; 58 | } 59 | } 60 | 61 | return false; 62 | } 63 | 64 | // PRIVATE // 65 | 66 | bool Malloc::AllocNoNewSegment(void *& addr, size_t size) { 67 | AssertNoncritical(); 68 | firstLock.Seize(); 69 | Segment * segment = firstSegment; 70 | firstLock.Release(); 71 | 72 | while (segment) { 73 | ScopedLock scope(segment->lock); 74 | 75 | addr = segment->allocator->Alloc(size); 76 | if (addr) return true; 77 | segment = segment->next; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | bool Malloc::CreateSegment() { 84 | VirtAddr freshMemory; 85 | if (!allocator.AllocAndMap(freshMemory, poolSize, bigPages)) { 86 | return false; 87 | } 88 | 89 | assert(!(freshMemory % ANARCH_OBJECT_ALIGN)); 90 | 91 | Segment * segPtr = new((Segment *)freshMemory) Segment(); 92 | // I *hate* when function names get this big 93 | segPtr->allocator = ANAlloc::Malloc::WrapRegion 94 | ((uint8_t *)freshMemory, poolSize, 6, sizeof(Segment)); 95 | 96 | ScopedLock scope(firstLock); 97 | segPtr->next = firstSegment; 98 | firstSegment = segPtr; 99 | 100 | return true; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/arch/x64/panic/panic.cpp: -------------------------------------------------------------------------------- 1 | #include "panic.hpp" 2 | #include "../interrupts/irt.hpp" 3 | #include "../interrupts/vectors.hpp" 4 | #include "../interrupts/apic/lapic-module.hpp" 5 | #include "../domains/domain-list.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | void Panic(const char * msg) { 13 | x64::PanicModule::GetGlobal().Panic(msg); 14 | } 15 | 16 | namespace x64 { 17 | 18 | namespace { 19 | 20 | PanicModule gPanicModule; 21 | 22 | } 23 | 24 | void PanicModule::InitGlobal() { 25 | new(&gPanicModule) PanicModule(); 26 | } 27 | 28 | PanicModule & PanicModule::GetGlobal() { 29 | return gPanicModule; 30 | } 31 | 32 | void PanicModule::Panic(const char * msg) { 33 | __asm__ __volatile__("cli"); 34 | if (panicCount++) { 35 | __asm__ __volatile__("hlt"); 36 | } 37 | 38 | // display the error now incase DistributeError() somehow fails 39 | WriteError(msg); 40 | DistributeError(); 41 | 42 | // display the error again incase other CPUs up to this point were messing 43 | // with the display buffer 44 | WriteError(msg); 45 | 46 | __asm__ __volatile__("hlt"); 47 | __builtin_unreachable(); 48 | } 49 | 50 | void PanicModule::Initialize() { 51 | Irt::GetGlobal().Set(IntVectors::Panic, (void *)HaltCpu); 52 | } 53 | 54 | ansa::DepList PanicModule::GetDependencies() { 55 | return ansa::DepList(&Irt::GetGlobal(), &LapicModule::GetGlobal(), 56 | &DomainList::GetGlobal()); 57 | } 58 | 59 | void PanicModule::DistributeError() { 60 | if (!IsInitialized()) return; 61 | Lapic & lapic = LapicModule::GetGlobal().GetLapic(); 62 | Cpu * current = &Cpu::GetCurrent(); 63 | DomainList & domains = DomainList::GetGlobal(); 64 | for (int i = 0; i < domains.GetCount(); i++) { 65 | Domain & domain = domains[i]; 66 | for (int j = 0; j < domain.GetThreadCount(); j++) { 67 | Cpu * cpu = &domain.GetCpu(j); 68 | if (cpu == current) continue; 69 | lapic.SendIpi(cpu->GetApicId(), IntVectors::Panic); 70 | } 71 | } 72 | } 73 | 74 | void PanicModule::WriteError(const char * msg) { 75 | // write the error to the screen 76 | uint16_t * buf = (uint16_t *)0xb8000; 77 | int i = 0; 78 | const char * prefix = "PANIC: "; 79 | while (*prefix) { 80 | buf[i++] = *prefix | 0xf200; 81 | prefix++; 82 | } 83 | while (*msg) { 84 | buf[i++] = *msg | 0xf900; 85 | msg++; 86 | } 87 | buf[i] = 0xf920; // space at the end for aesthetics 88 | } 89 | 90 | void PanicModule::HaltCpu() { 91 | // should I even bother sending an EOI, like really 92 | LapicModule::GetGlobal().GetLapic().SendEoi(); 93 | while (1) { 94 | __asm__ __volatile__("cli\nhlt"); 95 | } 96 | } 97 | 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/free-finder.cpp: -------------------------------------------------------------------------------- 1 | #include "free-finder.hpp" 2 | 3 | namespace anarch { 4 | 5 | namespace x64 { 6 | 7 | FreeFinder::FreeFinder(PageTable & pt) : pageTable(pt) { 8 | } 9 | 10 | bool FreeFinder::Alloc(VirtAddr & addr, size_t size, size_t align) { 11 | if (!CanAllocate(size, align)) { 12 | UpdateFreeRegion(); 13 | if (!CanAllocate(size, align)) { 14 | return false; 15 | } 16 | } 17 | 18 | if (freeStart % align) { 19 | freeSize -= align - freeStart % align; 20 | freeStart += align - freeStart % align; 21 | } 22 | 23 | addr = freeStart; 24 | 25 | freeSize -= size; 26 | freeStart += size; 27 | 28 | return true; 29 | } 30 | 31 | void FreeFinder::Free(VirtAddr addr, size_t size) { 32 | if (addr == freeStart + freeSize) { 33 | // the chunk is right after the free region 34 | freeSize += size; 35 | } else if (addr + size == freeStart) { 36 | // the chunk is right before the free region 37 | freeSize += size; 38 | freeStart -= size; 39 | } 40 | } 41 | 42 | void FreeFinder::Reserve(VirtAddr addr, size_t size) { 43 | if (addr > freeStart + freeSize || addr + size <= freeStart) { 44 | return; 45 | } 46 | size_t leftSize = 0; 47 | size_t rightSize = 0; 48 | if (addr > freeStart) { 49 | leftSize = addr - freeStart; 50 | } 51 | if (addr + size < freeStart + freeSize) { 52 | rightSize = freeStart + freeSize - (addr + size); 53 | } 54 | if (!leftSize && !rightSize) { 55 | freeSize = 0; 56 | return; 57 | } 58 | if (leftSize > rightSize) { 59 | freeSize = leftSize; 60 | } else { 61 | freeStart += freeSize - rightSize; 62 | freeSize = rightSize; 63 | } 64 | } 65 | 66 | // PROTECTED // 67 | 68 | void FreeFinder::UpdateFreeRegion() { 69 | VirtAddr addr = 0; 70 | while (addr < PageTable::KernelEnd) { 71 | VirtAddr nextStart = addr; 72 | size_t nextSize = 0; 73 | 74 | while (1) { 75 | size_t pageSize; 76 | uint64_t entry = 0; 77 | int result = pageTable.Walk(nextStart + nextSize, entry, &pageSize); 78 | addr += pageSize; 79 | if (result >= 0 && entry) break; 80 | nextSize += pageSize; 81 | if (nextStart + nextSize >= PageTable::KernelEnd) { 82 | nextSize = PageTable::KernelEnd - nextStart; 83 | break; 84 | } 85 | } 86 | 87 | if (nextSize > freeSize) { 88 | freeSize = nextSize; 89 | freeStart = nextStart; 90 | } 91 | } 92 | } 93 | 94 | bool FreeFinder::CanAllocate(size_t size, size_t align) { 95 | if (!size) return true; 96 | 97 | size_t slice = 0; 98 | if (freeStart % align) { 99 | slice = align - (freeStart % align); 100 | } 101 | if (slice >= freeSize) return false; 102 | return freeSize - slice >= size; 103 | } 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/global/map-setup.cpp: -------------------------------------------------------------------------------- 1 | #include "map-setup.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | namespace x64 { 10 | 11 | MapSetup::MapSetup() 12 | : kernelEnd(ansa::Align(GetBootInfo()->GetKernelEnd(), 0x1000)), 13 | reservedEnd(kernelEnd + ansa::Align(sizeof(BuddyAllocator) 14 | + sizeof(PageTable) + sizeof(FreeFinder), 0x1000)), 15 | stepAllocator(reservedEnd) { 16 | } 17 | 18 | void MapSetup::GenerateMap() { 19 | if (!stepAllocator.Alloc(pml4, 0x1000, 0x1000)) { 20 | Panic("MapSetup::Run() - failed to allocate PML4"); 21 | } 22 | if (!stepAllocator.Alloc(pdpt, 0x1000, 0x1000)) { 23 | Panic("MapSetup::Run() - failed to allocate PDPT"); 24 | } 25 | 26 | ansa::Bzero((void *)pml4, 0x1000); 27 | ansa::Bzero((void *)pdpt, 0x1000); 28 | 29 | uint64_t * pml4Buf = (uint64_t *)pml4; 30 | pml4Buf[0] = pdpt | 3; 31 | pml4Buf[0x1ff] = pml4 | 3; // fractal mapping 32 | 33 | pdtOffset = 0x200; 34 | pdptOffset = -1; 35 | 36 | size_t linearSize = (size_t)reservedEnd; 37 | while (linearSize) { 38 | MapNext(linearSize); 39 | } 40 | } 41 | 42 | void MapSetup::GeneratePageTable() { 43 | new(GetPageTable()) PageTable(stepAllocator, pml4); 44 | } 45 | 46 | void MapSetup::GenerateFreeFinder() { 47 | new(GetFreeFinder()) FreeFinder(*GetPageTable()); 48 | } 49 | 50 | void MapSetup::GenerateBuddyAllocator() { 51 | const RegionList & regions = GetBootInfo()->GetRegions(); 52 | new(GetBuddyAllocator()) BuddyAllocator(regions, stepAllocator); 53 | GetBuddyAllocator()->Reserve(stepAllocator.GetLastAddress()); 54 | GetPageTable()->SetAllocator(*GetBuddyAllocator()); 55 | } 56 | 57 | PageTable * MapSetup::GetPageTable() { 58 | return (PageTable *)kernelEnd; 59 | } 60 | 61 | FreeFinder * MapSetup::GetFreeFinder() { 62 | static_assert(sizeof(PageTable) % 8 == 0, "bad FreeFinder alignment"); 63 | return (FreeFinder *)(kernelEnd + sizeof(PageTable)); 64 | } 65 | 66 | BuddyAllocator * MapSetup::GetBuddyAllocator() { 67 | static_assert(sizeof(FreeFinder) % 8 == 0, "bad BuddyAllocator alignment"); 68 | return (BuddyAllocator *)(kernelEnd + sizeof(PageTable) 69 | + sizeof(FreeFinder)); 70 | } 71 | 72 | PhysAddr MapSetup::GetPdpt() { 73 | return (PhysAddr)pdpt; 74 | } 75 | 76 | // PRIVATE // 77 | 78 | void MapSetup::MapNext(size_t & linearSize) { 79 | if (pdtOffset == 0x200) { 80 | pdtOffset = 0; 81 | if (!stepAllocator.Alloc(currentPDT, 0x1000, 0x1000)) { 82 | Panic("MapSetup::MapNext() - failed to allocate PDT"); 83 | } 84 | ansa::Bzero((void *)currentPDT, 0x1000); 85 | ((uint64_t *)pdpt)[++pdptOffset] = currentPDT | 3; 86 | } 87 | ((uint64_t *)currentPDT)[pdtOffset++] = firstUnmapped | 0x183; 88 | firstUnmapped += 0x200000; // forgetting this line ruined my evening 89 | if (linearSize <= 0x200000) linearSize = 0; 90 | else linearSize -= 0x200000; 91 | } 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/apic-table.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_ACPI_Apic_TABLE_HPP__ 2 | #define __ANARCH_X64_ACPI_Apic_TABLE_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace anarch { 12 | 13 | namespace x64 { 14 | 15 | class ApicTable : public ansa::NoCopy { 16 | public: 17 | struct Header; 18 | struct Iso; 19 | struct LocalApic; 20 | struct LocalApic2; 21 | struct IOApic; 22 | class Iterator; 23 | 24 | static const uint8_t TypeLapic = 0; 25 | static const uint8_t TypeIOApic = 1; 26 | static const uint8_t TypeIso = 2; 27 | static const uint8_t TypeX2Apic = 9; 28 | 29 | ApicTable(PhysAddr baseAddr); // @noncritical 30 | 31 | // destructor is implicit, but is @noncritical 32 | 33 | bool CanIterate(); // @ambicritical 34 | Iterator GetIterator(); // @ambicritical 35 | 36 | Header & GetHeader(); 37 | 38 | bool SystemHas8259(); // @ambicritical 39 | int CountType(uint8_t type); // @ambicritical 40 | int CountIOApics(); // @ambicritical 41 | int CountLapics(bool checkUsable); // @ambicritical 42 | 43 | Iso * LookupIso(uint8_t physIRQ); // @ambicritical 44 | IOApic * LookupIOApic(uint32_t base); // @ambicritical 45 | 46 | struct Header { 47 | uint32_t signature; // Apic 48 | uint32_t length; 49 | uint8_t revision; 50 | uint8_t checksum; 51 | char oemid[6]; 52 | uint64_t oemTableId; 53 | uint32_t oemRevision; 54 | uint32_t creatorId; 55 | uint32_t creatorRevision; 56 | uint32_t lapicAddr; 57 | uint32_t flags; 58 | } ANSA_PACKED; 59 | 60 | struct Iso { 61 | uint8_t type; 62 | uint8_t length; 63 | uint8_t bus; 64 | uint8_t source; 65 | uint32_t interrupt; 66 | uint16_t flags; 67 | } ANSA_PACKED; 68 | 69 | struct LocalApic { 70 | uint8_t type; // should be 0 71 | uint8_t length; 72 | uint8_t apicpuId; 73 | uint8_t apicId; 74 | uint32_t flags; // bit 0 set = usable 75 | } ANSA_PACKED; 76 | 77 | struct LocalApic2 { 78 | uint8_t type; // should be 9 79 | uint8_t length; 80 | uint16_t reserved; 81 | uint32_t x2apicId; 82 | uint32_t flags; // bit 0 set = usable 83 | uint32_t x2apicpuId; 84 | } ANSA_PACKED; 85 | 86 | struct IOApic { 87 | uint8_t type; 88 | uint8_t length; 89 | uint8_t identifier; 90 | uint8_t reserved; 91 | uint32_t baseAddr; 92 | uint32_t interruptBase; 93 | } ANSA_PACKED; 94 | 95 | class Iterator { 96 | public: 97 | bool Next(); 98 | uint8_t GetType(); 99 | void * GetData(); 100 | size_t GetSize(); 101 | protected: 102 | friend class ApicTable; 103 | Iterator(void * baseAddr, size_t dataSize); 104 | 105 | private: 106 | uint8_t * address; 107 | size_t dataSize; 108 | }; 109 | 110 | protected: 111 | PhysSize dataSize; 112 | EasyMap map; 113 | 114 | void * GetData(); 115 | size_t GetDataSize(); 116 | }; 117 | 118 | } 119 | 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/arch/x64/public/multiboot-region-list.cpp: -------------------------------------------------------------------------------- 1 | #include "multiboot-region-list.hpp" 2 | #include "multiboot.hpp" 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | MultibootRegionList::MultibootRegionList(void * mbootPtr) { 10 | MultibootBootInfo * multibootPtr = (MultibootBootInfo *)mbootPtr; 11 | 12 | uint32_t mmapLen = multibootPtr->mmap_length; 13 | uint32_t mmapAddr = multibootPtr->mmap_addr; 14 | if (mmapAddr + mmapLen > 0x100000) { 15 | Panic("GRUB memory map is placed beyond 1MB -- might be destroyed!"); 16 | } 17 | 18 | // generate ANAlloc::Region objects in a loop 19 | uintptr_t longAddr = (uintptr_t)mmapAddr; 20 | MultibootMmapInfo * info = NULL; 21 | MultibootMmapInfo * next = (MultibootMmapInfo *)longAddr; 22 | while (mmapLen > 0) { 23 | info = next; 24 | next = (MultibootMmapInfo *)((uintptr_t)info + info->size + 4); 25 | mmapLen -= info->size + 4; 26 | 27 | if (info->type != 1) continue; 28 | 29 | // simplify the process by assuming that the first MB is contiguous (even) 30 | // though really it's not at all. 31 | if (info->base_addr + info->length <= 0x100000) continue; 32 | 33 | // get the range 34 | ANAlloc::UInt start = (ANAlloc::UInt)info->base_addr; 35 | ANAlloc::UInt len = (ANAlloc::UInt)info->length; 36 | 37 | // if this region is in the lower MB, we will stretch it out to the 38 | // beginning of the address space. 39 | if (start <= 0x100000) { 40 | len += start; 41 | start = 0; 42 | } 43 | 44 | ANAlloc::Region region(start, len); 45 | if (start < 0x100000000L && start + len > 0x100000000L) { 46 | // this will probably never happen, but if it does we need to split the 47 | // regions for ANAlloc to be able to differentiate between upper and 48 | // lower memory 49 | ANAlloc::UInt lowSize = (ANAlloc::UInt)(0x100000000L - start); 50 | ANAlloc::Region lowerRegion(start, lowSize); 51 | ANAlloc::Region upperRegion(0x100000000L, len - lowSize); 52 | AddRegion(lowerRegion); 53 | AddRegion(upperRegion); 54 | } else { 55 | AddRegion(region); 56 | } 57 | } 58 | if (!lowerRegions.GetCount()) { 59 | Panic("MultibootRegionList::Initialize() - no lower regions found"); 60 | } 61 | } 62 | 63 | const ANAlloc::RegionList & MultibootRegionList::GetLowerRegions() const { 64 | return lowerRegions; 65 | } 66 | 67 | const ANAlloc::RegionList & MultibootRegionList::GetUpperRegions() const { 68 | return upperRegions; 69 | } 70 | 71 | void MultibootRegionList::AddRegion(const ANAlloc::Region & region) { 72 | ANAlloc::FixedRegionList * list = NULL; 73 | 74 | if (region.GetStart() < 0x100000000L) { 75 | list = &lowerRegions; 76 | } else { 77 | list = &upperRegions; 78 | } 79 | 80 | int insertIndex = list->GetCount(); 81 | for (int i = 0; i < list->GetCount(); i++) { 82 | if ((*list)[i].GetStart() > region.GetStart()) { 83 | insertIndex = i; 84 | break; 85 | } 86 | } 87 | if (!list->Insert(region, insertIndex)) { 88 | Panic("MultibootRegionList::AddRegion() - region overflow"); 89 | } 90 | } 91 | 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ANArch 2 | 3 | This library will provide an interface for Operating System kernels to access architecture-specific/platform-specific features of the target system. 4 | 5 | It will provide these APIs by means of abstraction: 6 | 7 | * A set of types equivalent to <cstdint> with additional types for virtual and physical addresses. 8 | * An API for managing the global address space 9 | * An API for creating and managing address spaces for user applications 10 | * A clock interface for accurate timestamps and high-precision notifications 11 | * A console API for printing (colored) text to the screen 12 | * A set of functions, classes, and macros for "critical sections" 13 | * An API which returns a set of "domains"; each domain will include: 14 | * A physical allocator for allocating memory local to a domain 15 | * Virtual allocation functions for simple kernel allocations 16 | * A list of CPUs which run under the domain 17 | * A CPU-local storage facility 18 | * A simple function call for handling a panic 19 | * An API for saving and restoring the state of user-space and kernel-space programs 20 | * A means by which to sleep the CPU until an asynchronous event occurs. 21 | * An interface for receiving page faults. 22 | * An interface for handling system calls. 23 | 24 | Additionally, it will provide these tools to wrap the APIs above: 25 | 26 | * A method to easily copy memory from physical memory to virtual memory. 27 | * An object that maps memory on construction and unmaps it on destruction 28 | * A set of classes that lock and unlock locks on construction and destruction 29 | * A class that enters and leaves a critical section on construction and destruction 30 | * An implementation of the `assert()` function using the panic API 31 | * A very limited implementation of <iostream> 32 | 33 | Architecture-specific APIs will have to be initialized by the operating system's entry point. This means that you may use a custom bootloader, etc. and still use architecture-specific APIs. However, an architecture may provide helper classes/methods for tasks such as parsing multiboot tables. 34 | 35 | # Usage 36 | 37 | **anarch** is almost completely stand-alone. However, it does include one header that it does not provide. You may notice this line of code in [src/util/lock.hpp](src/util/lock.hpp). 38 | 39 | #include 40 | 41 | The API consumer is responsible for providing this header file. The header should define a class `anarch::NoncriticalLock` that is a subclass of `ansa::Lock`. This class will be used throughout anarch for locking various internal structures. 42 | 43 | Your operating system should provide an implementation of `anarch::NoncriticalLock` that yields to waiting tasks to prevent unnecessary CPU usage. 44 | 45 | # TODO 46 | 47 | Although anarch is up and running for x86-64, I would still like to rewrite it before I add more architectures. Here is my current wish-list for the rewrite: 48 | 49 | * Get rid of singletons and "Modules" -- replace with top-level functions 50 | * Remove most of the generic API base-classes; instead, architecture specific code will provide its own includes and classes. This will allow for better optimization. 51 | * ASID (address-space identifier) support for modern CPUs 52 | * Support non-uniform memory access for the x86-64 platform 53 | * Better scalable virtual memory management 54 | * Slabs 55 | * Per-CPU memory pools 56 | * Time stamp counter support for CPUs with invariant TSC 57 | * `Print()` and `Debug()` functions instead of `cout`. 58 | * Performance monitoring to detect how much work a hyperthread (on x86-64) is performing. 59 | -------------------------------------------------------------------------------- /src/arch/x64/acpi/apic-table.cpp: -------------------------------------------------------------------------------- 1 | #include "apic-table.hpp" 2 | #include 3 | #include 4 | 5 | namespace anarch { 6 | 7 | namespace x64 { 8 | 9 | namespace { 10 | 11 | uint32_t ReadLength(PhysAddr addr) { 12 | uint32_t value; 13 | PhysCopy(&value, addr, 4); 14 | return value; 15 | } 16 | 17 | } 18 | 19 | ApicTable::ApicTable(PhysAddr baseAddr) 20 | : dataSize((PhysSize)ReadLength(baseAddr + 4)), 21 | map(baseAddr, dataSize) { 22 | } 23 | 24 | bool ApicTable::CanIterate() { 25 | return GetDataSize() > 0; 26 | } 27 | 28 | ApicTable::Iterator ApicTable::GetIterator() { 29 | return Iterator((void *)GetData(), GetDataSize()); 30 | } 31 | 32 | ApicTable::Header & ApicTable::GetHeader() { 33 | return *((Header *)map.GetStart()); 34 | } 35 | 36 | bool ApicTable::SystemHas8259() { 37 | return (GetHeader().flags & 1) != 0; 38 | } 39 | 40 | int ApicTable::CountType(uint8_t type) { 41 | if (!CanIterate()) return 0; 42 | int count = 0; 43 | Iterator it = GetIterator(); 44 | do { 45 | if (it.GetType() == type) count++; 46 | } while (it.Next()); 47 | return count; 48 | } 49 | 50 | int ApicTable::CountIOApics() { 51 | return CountType(TypeIOApic); 52 | } 53 | 54 | int ApicTable::CountLapics(bool checkUsable) { 55 | if (!CanIterate()) return 0; 56 | 57 | int count = 0; 58 | Iterator it = GetIterator(); 59 | do { 60 | if (it.GetType() == TypeLapic) { 61 | if (!checkUsable) { 62 | count++; 63 | } else { 64 | LocalApic * apic = (LocalApic *)it.GetData(); 65 | if (apic->flags & 1) count++; 66 | } 67 | } else if (it.GetType() == TypeX2Apic) { 68 | if (!checkUsable) { 69 | count++; 70 | } else { 71 | LocalApic2 * apic = (LocalApic2 *)it.GetData(); 72 | if (apic->flags & 1) count++; 73 | } 74 | } 75 | } while (it.Next()); 76 | 77 | return count; 78 | } 79 | 80 | ApicTable::Iso * ApicTable::LookupIso(uint8_t physIRQ) { 81 | if (!CanIterate()) return NULL; 82 | Iterator it = GetIterator(); 83 | do { 84 | if (it.GetType() != TypeIso) continue; 85 | Iso * iso = (Iso *)it.GetData(); 86 | if (iso->source == physIRQ && iso->bus == 0) { 87 | return iso; 88 | } 89 | } while (it.Next()); 90 | return NULL; 91 | } 92 | 93 | ApicTable::IOApic * ApicTable::LookupIOApic(uint32_t base) { 94 | if (!CanIterate()) return NULL; 95 | Iterator it = GetIterator(); 96 | do { 97 | if (it.GetType() != TypeIOApic) continue; 98 | IOApic * info = (IOApic *)it.GetData(); 99 | if (info->interruptBase == base) return info; 100 | } while (it.Next()); 101 | return NULL; 102 | } 103 | 104 | void * ApicTable::GetData() { 105 | return (void *)(map.GetStart() + sizeof(Header)); 106 | } 107 | 108 | size_t ApicTable::GetDataSize() { 109 | return (size_t)(dataSize - sizeof(Header)); 110 | } 111 | 112 | // ITERATOR // 113 | 114 | bool ApicTable::Iterator::Next() { 115 | uint8_t thisSize = GetSize(); 116 | 117 | assert(thisSize <= dataSize); 118 | if (thisSize == dataSize) return false; 119 | 120 | dataSize -= thisSize; 121 | address += thisSize; 122 | 123 | return true; 124 | } 125 | 126 | uint8_t ApicTable::Iterator::GetType() { 127 | return *address; 128 | } 129 | 130 | void * ApicTable::Iterator::GetData() { 131 | return (void *)address; 132 | } 133 | 134 | size_t ApicTable::Iterator::GetSize() { 135 | return (size_t)address[1]; 136 | } 137 | 138 | ApicTable::Iterator::Iterator(void * baseAddr, size_t size) 139 | : address((uint8_t *)baseAddr), dataSize(size) { 140 | } 141 | 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/arch/x64/smp/cpu.cpp: -------------------------------------------------------------------------------- 1 | #include "cpu.hpp" 2 | #include "../segments/local-segment.hpp" 3 | #include "../segments/gdt.hpp" 4 | #include "../domains/domain-list.hpp" 5 | #include "../interrupts/apic/lapic-module.hpp" 6 | #include "../interrupts/vectors.hpp" 7 | #include 8 | #include 9 | 10 | namespace anarch { 11 | 12 | Thread & Thread::GetCurrent() { 13 | return x64::Cpu::GetCurrent(); 14 | } 15 | 16 | void * Thread::GetUserInfo() { 17 | void * res; 18 | __asm__("mov %%gs:(0x10), %0" : "=r" (res) : : "memory"); 19 | return res; 20 | } 21 | 22 | void Thread::SetUserInfo(void * info) { 23 | __asm__("mov %0, %%gs:(0x10)" : : "r" (info) : "memory"); 24 | } 25 | 26 | void Thread::RunSync(void (* func)()) { 27 | AssertCritical(); 28 | RunSync((void (*)(void *))func, NULL); 29 | } 30 | 31 | void Thread::RunSync(void (* func)(void *), void * arg) { 32 | AssertCritical(); 33 | __asm__("mov %%rax, %%rsp\n" 34 | "call *%%rsi" 35 | : : "a" (x64::Cpu::GetCurrent().GetStackTop()), 36 | "S" (func), "D" (arg)); 37 | __builtin_unreachable(); 38 | } 39 | 40 | namespace x64 { 41 | 42 | namespace { 43 | 44 | Lapic & GetLapicCritical() { 45 | ScopedCritical critical; 46 | return LapicModule::GetGlobal().GetLapic(); 47 | } 48 | 49 | } 50 | 51 | Cpu & Cpu::GetCurrent() { 52 | Cpu * ptr; 53 | __asm__("mov %%gs:(0x0), %0" : "=r" (ptr)); 54 | return *ptr; 55 | } 56 | 57 | void Cpu::HandleWakeup() { 58 | AssertCritical(); 59 | LapicModule::GetGlobal().GetLapic().SendEoi(); 60 | Cpu & cur = GetCurrent(); 61 | 62 | cur.wakeupLock.Seize(); 63 | auto func = cur.wakeupFunction; 64 | auto arg = cur.wakeupArg; 65 | cur.wakeupFunction = NULL; 66 | cur.wakeupLock.Release(); 67 | 68 | if (!func) return; 69 | func(arg); 70 | } 71 | 72 | Cpu::Cpu() : lapic(GetLapicCritical()) { 73 | localData.thisCpu = this; 74 | localData.userData = NULL; 75 | 76 | void * stack; 77 | if (!GetDomain().Alloc(stack, StackSize)) { 78 | Panic("Cpu::Cpu() - failed to allocate stack"); 79 | } 80 | stackTop = (void *)((uint64_t)stack + StackSize); 81 | 82 | ScopedCritical critical; 83 | LocalSegment::Write((uint64_t)&localData); 84 | 85 | for (int i = 0; i < 7; ++i) { 86 | taskSegment.ist[i] = (uint64_t)stackTop; 87 | } 88 | 89 | TssDescriptor desc(&taskSegment); 90 | uint16_t seg = Gdt::GetGlobal().PushTssDescriptor(desc); 91 | __asm__ __volatile__("ltr %%ax" : : "a" (seg)); 92 | 93 | apicId = GetLapic().GetId(); 94 | } 95 | 96 | Cpu::~Cpu() { 97 | Panic("Cpu::~Cpu() - CPU cannot be destroyed!"); 98 | } 99 | 100 | void Cpu::SetAsyncKernelTop(void * stack) { 101 | taskSegment.rsp[0] = (uint64_t)stack; 102 | localData.syscallStack = stack; 103 | } 104 | 105 | void * Cpu::GetStackTop() { 106 | return stackTop; 107 | } 108 | 109 | uint32_t Cpu::GetApicId() { 110 | return apicId; 111 | } 112 | 113 | LapicTimer & Cpu::GetLapicTimer() { 114 | return lapicTimer; 115 | } 116 | 117 | Lapic & Cpu::GetLapic() { 118 | return lapic; 119 | } 120 | 121 | anarch::Domain & Cpu::GetDomain() { 122 | return DomainList::GetGlobal()[0]; 123 | } 124 | 125 | anarch::Timer & Cpu::GetTimer() { 126 | return GetLapicTimer(); 127 | } 128 | 129 | int Cpu::GetPriority() { 130 | // TODO: return the index in the CPU core 131 | return 0; 132 | } 133 | 134 | void Cpu::RunAsync(void (* func)()) { 135 | RunAsync((void (*)(void *))func, NULL); 136 | } 137 | 138 | void Cpu::RunAsync(void (* func)(void *), void * arg) { 139 | AssertCritical(); 140 | wakeupLock.Seize(); 141 | wakeupFunction = func; 142 | wakeupArg = arg; 143 | wakeupLock.Release(); 144 | GetLapic().SendIpi(GetApicId(), IntVectors::Wakeup); 145 | } 146 | 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/arch/x64/vmm/page-table.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ANARCH_X64_PAGE_TABLE_HPP__ 2 | #define __ANARCH_X64_PAGE_TABLE_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace anarch { 9 | 10 | namespace x64 { 11 | 12 | /** 13 | * This class facilitates page table manipulation via fractal mapping. The 14 | * underlying memory map must be set while you manipulate the page table. 15 | */ 16 | class PageTable : public ansa::NoCopy { 17 | public: 18 | static const VirtAddr KernelEnd = 0x8000000000UL; 19 | static const VirtAddr UserEnd = 0xFFFFFF8000000000UL; 20 | 21 | static int CalcDepth(size_t size); 22 | static uint64_t CalcMask(size_t, bool kernel, 23 | const MemoryMap::Attributes &); 24 | 25 | PageTable(Allocator &, PhysAddr pml4); 26 | PageTable(Allocator &); 27 | 28 | void SetPml4(PhysAddr); 29 | PhysAddr GetPml4(); 30 | 31 | void SetAllocator(Allocator &); 32 | Allocator & GetAllocator(); 33 | 34 | /** 35 | * Returns `true` if the PML4 of this page table is CR3. 36 | * @noncritical 37 | */ 38 | bool IsSet(); 39 | 40 | /** 41 | * @return The depth of the entry found (0-3 inclusive) or -1 if not mapped. 42 | * This may return depth 3 with entry=0. 43 | * @noncritical -> @critical -> @noncritical 44 | */ 45 | int Walk(VirtAddr addr, uint64_t & entry, size_t * size); 46 | 47 | /** 48 | * Set a raw entry in the page table. 49 | * @param addr The start of the page 50 | * @param entry The entry to set, flags included 51 | * @param parentMask All parent table entries will be ORed with this 52 | * @param depth The depth of the entry to create; 0-3 inclusive. 53 | * @return true on success; false will only be returned in the case where a 54 | * large page has been mapped and you try to Set() a smaller piece of that 55 | * large page at a deeper point. 56 | * @noncritical -> @critical -> @noncritical 57 | */ 58 | bool Set(VirtAddr addr, uint64_t entry, uint64_t parentMask, int depth, 59 | bool * overwrote = NULL); 60 | 61 | /** 62 | * Unset the page table entry beginning at `addr`. 63 | * @return The only time Unset() can fail is if you try to unmap a piece of 64 | * a larger page (i.e. you try to allocate a 2MB region but passed an address 65 | * that is not 2MB aligned). 66 | * @noncritical -> @critical -> @noncritical 67 | */ 68 | bool Unset(VirtAddr addr); 69 | 70 | /** 71 | * Set a bunch of entries at once. 72 | * @noncritical 73 | */ 74 | void SetList(VirtAddr virt, uint64_t phys, MemoryMap::Size size, 75 | uint64_t parentMask, bool * overwrote = NULL); 76 | 77 | /** 78 | * Perform a memory map read operation. 79 | * @noncritical 80 | */ 81 | bool Read(PhysAddr *, MemoryMap::Attributes *, size_t *, VirtAddr); 82 | 83 | /** 84 | * Free all of the page table structures including the PML4. 85 | * @noncritical 86 | */ 87 | void FreeTable(int pdptStart); 88 | 89 | private: 90 | Allocator * allocator; 91 | PhysAddr pml4 = 0; 92 | 93 | /** 94 | * Perform a fractal-map lookup. 95 | * @ambicritical 96 | */ 97 | static uint64_t & GetTableEntry(VirtAddr address, int depth); 98 | 99 | /** 100 | * Perform a fractal-map lookup for the beginning of a given table. This is 101 | * useful for zeroing new page tables. 102 | * @ambicritical 103 | */ 104 | static uint64_t * GetTableStart(VirtAddr address, int depth); 105 | 106 | /** 107 | * Free the table at a certain [depth] that starts with [addr]. 108 | * @critical 109 | */ 110 | void FreeTableRecursive(PhysAddr table, int depth, int start = 0, 111 | int end = 0x200); 112 | }; 113 | 114 | } 115 | 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /src/arch/x64/state/state.cpp: -------------------------------------------------------------------------------- 1 | #include "state.hpp" 2 | #include "../smp/cpu.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | State & State::NewKernel(void (* fn)()) { 10 | return *Domain::GetCurrent().New((uint64_t)fn, 0, true); 11 | } 12 | 13 | State & State::NewKernel(void (* fn)(void *), void * arg) { 14 | return *Domain::GetCurrent().New((uint64_t)fn, (uint64_t)arg, 15 | true); 16 | } 17 | 18 | State & State::NewUser(void (* fn)()) { 19 | return *Domain::GetCurrent().New((uint64_t)fn, 0, false); 20 | } 21 | 22 | State & State::NewUser(void (* fn)(void *), void * arg) { 23 | return *Domain::GetCurrent().New((uint64_t)fn, (uint64_t)arg, 24 | false); 25 | } 26 | 27 | namespace x64 { 28 | 29 | State::State(uint64_t rip, uint64_t _rdi, bool kernel) : rdi(_rdi) { 30 | iretInfo.rip = rip; 31 | iretInfo.rflags = 0x200; 32 | 33 | if (!Domain::GetCurrent().Alloc(stackStart, StackSize)) { 34 | Panic("State::State() - failed to allocate stack"); 35 | } 36 | 37 | if (kernel) { 38 | iretInfo.rsp = (uint64_t)stackStart + StackSize; 39 | iretInfo.cs = 8; 40 | iretInfo.ss = 0; 41 | } else { 42 | iretInfo.cs = 0x23; 43 | iretInfo.ss = 0x1b; 44 | } 45 | } 46 | 47 | State::~State() { 48 | Domain::GetCurrent().Free(stackStart); 49 | } 50 | 51 | void * State::GetStackTop() { 52 | return (void *)((uint64_t)stackStart + StackSize); 53 | } 54 | 55 | void State::Delete() { 56 | Domain::GetCurrent().Delete(this); 57 | } 58 | 59 | void State::Resume() { 60 | AssertCritical(); 61 | Cpu::GetCurrent().SetAsyncKernelTop((void *)GetStackTop()); 62 | if (iretInfo.cs & 3) { 63 | __asm__ __volatile__("swapgs"); 64 | } 65 | 66 | __asm__ __volatile__( 67 | "sub $0x28, %%rsp\n" 68 | "mov $5, %%rcx\n" 69 | "mov %%rsp, %%rdi\n" 70 | "rep movsq\n" 71 | "mov %%rdx, %%rdi\n" 72 | "iretq" 73 | : : "S" (&iretInfo), "d" (rdi) 74 | ); 75 | 76 | __builtin_unreachable(); 77 | } 78 | 79 | void State::SuspendAndCall(void (* func)()) { 80 | AssertCritical(); 81 | Cpu & cpu = Cpu::GetCurrent(); 82 | // we must be in kernel space, so we know the CS and SS 83 | iretInfo.cs = 8; 84 | iretInfo.ss = 0; 85 | __asm__ __volatile__( 86 | "movabsq $_anarch_suspend_and_call_return, %%rax\n" 87 | "movq %%rax, (%%rdi)\n" // save RIP 88 | "pushfq\n" // save RFLAGS 89 | "pop %%rax\n" 90 | "mov %%rax, 0x10(%%rdi)\n" 91 | "mov %%rsp, 0x18(%%rdi)\n" // save RSP 92 | "mov %%rcx, %%rsp\n" // load new RSP 93 | "call *%%rbx\n" // call func() 94 | "_anarch_suspend_and_call_return:" 95 | : : "c" (cpu.GetStackTop()), "b" (func), "D" (&iretInfo) 96 | : "rax", "rdx", "rsi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", 97 | "r15", "memory"); 98 | } 99 | 100 | void State::SuspendAndCall(void (* func)(void *), void * arg) { 101 | AssertCritical(); 102 | Cpu & cpu = Cpu::GetCurrent(); 103 | // we must be in kernel space, so we know the CS and SS 104 | iretInfo.cs = 8; 105 | iretInfo.ss = 0; 106 | __asm__ __volatile__( 107 | "movabsq $_anarch_suspend_and_call_return2, %%rax\n" 108 | "movq %%rax, (%%rsi)\n" // save RIP 109 | "pushfq\n" // save RFLAGS 110 | "pop %%rax\n" 111 | "mov %%rax, 0x10(%%rsi)\n" 112 | "mov %%rsp, 0x18(%%rsi)\n" // save RSP 113 | "mov %%rcx, %%rsp\n" // load new RSP 114 | "call *%%rbx\n" // call func(arg) 115 | "_anarch_suspend_and_call_return2:" 116 | : : "c" (cpu.GetStackTop()), "b" (func), "S" (&iretInfo), "D" (arg) 117 | : "rdx", "rax", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 118 | "memory"); 119 | } 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/arch/x64/console/text-console.cpp: -------------------------------------------------------------------------------- 1 | #include "text-console.hpp" 2 | #include "../common.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace anarch { 8 | 9 | Console & Console::GetGlobal() { 10 | return x64::TextConsole::GetGlobal(); 11 | } 12 | 13 | namespace x64 { 14 | 15 | namespace { 16 | 17 | TextConsole gConsole; 18 | 19 | } 20 | 21 | void TextConsole::InitGlobal() { 22 | new(&gConsole) TextConsole(); 23 | } 24 | 25 | TextConsole & TextConsole::GetGlobal() { 26 | return gConsole; 27 | } 28 | 29 | int TextConsole::GetWidth() { 30 | return 80; 31 | } 32 | 33 | int TextConsole::GetHeight() { 34 | return 25; 35 | } 36 | 37 | uint16_t * TextConsole::GetBuffer() { 38 | return (uint16_t *)0xb8000; 39 | } 40 | 41 | void TextConsole::PrintString(const char * string) { 42 | ScopedCritical critical; 43 | ScopedLock scope(lock); 44 | 45 | // this is some ugly logic that could probably be simplified 46 | while (*string) { 47 | unsigned char theChar = *(string++); 48 | switch (theChar) { 49 | case '\n': 50 | PrintNewline(); 51 | break; 52 | case '\r': 53 | PrintCarriageReturn(); 54 | break; 55 | case '\b': 56 | PrintBackspace(); 57 | break; 58 | default: 59 | PrintCharacter(theChar); 60 | break; 61 | } 62 | } 63 | if (!(CurrentCharacter() & 0xff00)) { 64 | CurrentCharacter() = color << 8; 65 | } 66 | PositionCursor(); 67 | } 68 | 69 | void TextConsole::SetColor(Color _color, bool bright) { 70 | ScopedCritical critical; 71 | ScopedLock scope(lock); 72 | color = (uint8_t)_color | (bright ? 8 : 0); 73 | } 74 | 75 | ansa::DepList TextConsole::GetDependencies() { 76 | return ansa::DepList(); 77 | } 78 | 79 | void TextConsole::Initialize() { 80 | // zero out the buffer 81 | ansa::Bzero(GetBuffer(), GetWidth() * GetHeight() * 2); 82 | } 83 | 84 | void TextConsole::PrintNewline() { 85 | x = 0; 86 | ++y; 87 | if (y >= GetHeight()) { 88 | y = GetHeight() - 1; 89 | ScrollUp(); 90 | } 91 | } 92 | 93 | void TextConsole::PrintCarriageReturn() { 94 | x = 0; 95 | } 96 | 97 | void TextConsole::PrintBackspace() { 98 | if (x != 0) { 99 | --x; 100 | CurrentCharacter() = color << 8; 101 | return; 102 | } 103 | 104 | // go to the previous line and find the last ASCII character on it 105 | --y; 106 | for (x = 0; x < GetWidth(); ++x) { 107 | if (!(CurrentCharacter() & 0xff)) { 108 | break; 109 | } 110 | } 111 | if (x == GetWidth()) --x; 112 | CurrentCharacter() = color << 8; 113 | } 114 | 115 | void TextConsole::PrintCharacter(unsigned char theChar) { 116 | if (x == GetWidth()) { 117 | PrintNewline(); 118 | } 119 | CurrentCharacter() = (uint16_t)theChar | (color << 8); 120 | ++x; 121 | if (x == 80 && y == GetHeight() - 1) { 122 | ScrollUp(); 123 | --y; 124 | } 125 | } 126 | 127 | uint16_t TextConsole::GetBufferIndex() { 128 | uint16_t pos = (uint16_t)((y * GetWidth()) + x); 129 | if (pos >= GetWidth() * GetHeight()) { 130 | pos = GetWidth() * GetHeight() - 1; 131 | } 132 | return pos; 133 | } 134 | 135 | uint16_t & TextConsole::CurrentCharacter() { 136 | return GetBuffer()[GetBufferIndex()]; 137 | } 138 | 139 | void TextConsole::PositionCursor() { 140 | uint16_t position = GetBufferIndex(); 141 | 142 | // tell the VGA index register we are sending the `low` byte 143 | x64::OutB(0x3D4, 0x0f); 144 | x64::OutB(0x3D5, (unsigned char)(position & 0xff)); 145 | // and now send the `high` byte 146 | x64::OutB(0x3D4, 0x0e); 147 | x64::OutB(0x3D5, (unsigned char)((position >> 8) & 0xff)); 148 | } 149 | 150 | void TextConsole::ScrollUp() { 151 | uint16_t * buffer = GetBuffer(); 152 | 153 | // copy the buffer into itself, one line up 154 | int i; 155 | for (i = 0; i < GetWidth() * (GetHeight() - 1); i++) { 156 | buffer[i] = buffer[i + GetWidth()]; 157 | } 158 | 159 | // clear the bottom line 160 | for (; i < GetWidth() * GetHeight(); i++) { 161 | buffer[i] = 0; 162 | } 163 | } 164 | 165 | } 166 | 167 | } 168 | --------------------------------------------------------------------------------