├── libs ├── libcxx │ ├── src │ │ └── dummy.cpp │ ├── include │ │ ├── cassert │ │ ├── cstdlib │ │ ├── cstring │ │ ├── cstddef │ │ ├── cstdint │ │ ├── concepts │ │ ├── new │ │ ├── initializer_list │ │ ├── utility │ │ ├── bit │ │ ├── array │ │ └── memory │ └── CMakeLists.txt ├── common │ └── CMakeLists.txt ├── libnet │ ├── CMakeLists.txt │ └── include │ │ └── net │ │ ├── ip.hpp │ │ └── dns.hpp ├── libtext │ ├── CMakeLists.txt │ └── include │ │ └── libtext │ │ └── libtext.hpp ├── libui │ ├── include │ │ └── ui │ │ │ ├── keyboard.hpp │ │ │ ├── mouse.hpp │ │ │ ├── gui.hpp │ │ │ ├── button.hpp │ │ │ ├── text.hpp │ │ │ └── context.hpp │ ├── CMakeLists.txt │ └── src │ │ ├── button.cpp │ │ └── text.cpp ├── libwindower │ ├── CMakeLists.txt │ └── include │ │ └── windower │ │ ├── windower.h │ │ ├── protocol.hpp │ │ ├── windower.hpp │ │ └── protocol.h ├── libc │ ├── include │ │ ├── bits │ │ │ └── utils.h │ │ ├── string.h │ │ ├── assert.h │ │ ├── stdlib.h │ │ ├── stdio.h │ │ └── elf.h │ ├── src │ │ ├── assert.cpp │ │ ├── cxx.cpp │ │ └── stdlib.cpp │ └── CMakeLists.txt └── CMakeLists.txt ├── apps ├── console │ ├── src │ │ ├── CMakeLists.txt │ │ └── main.cpp │ └── CMakeLists.txt ├── desktop │ ├── src │ │ ├── CMakeLists.txt │ │ ├── event.hpp │ │ ├── desktop.hpp │ │ ├── taskbar.hpp │ │ ├── desktop.cpp │ │ └── window.hpp │ ├── CMakeLists.txt │ └── BUGS.md ├── evm │ ├── src │ │ ├── CMakeLists.txt │ │ ├── vga.hpp │ │ ├── chipset.hpp │ │ ├── vm.hpp │ │ ├── main.cpp │ │ └── pci.cpp │ └── CMakeLists.txt └── CMakeLists.txt ├── .gitignore ├── src ├── dev │ ├── usb │ │ ├── hcd │ │ │ ├── CMakeLists.txt │ │ │ └── xhci │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── xhci.hpp │ │ │ │ ├── transfer_ring.hpp │ │ │ │ └── xhci_pci.cpp │ │ ├── dev │ │ │ └── CMakeLists.txt │ │ ├── CMakeLists.txt │ │ └── device.hpp │ ├── fb │ │ ├── fb_dev.hpp │ │ ├── font.hpp │ │ ├── CMakeLists.txt │ │ ├── fb.hpp │ │ └── fb.cpp │ ├── sound │ │ ├── hda │ │ │ └── CMakeLists.txt │ │ ├── CMakeLists.txt │ │ └── sound_dev.hpp │ ├── bt │ │ ├── CMakeLists.txt │ │ └── bt_dev.hpp │ ├── date_time_provider.cpp │ ├── gpu │ │ ├── CMakeLists.txt │ │ ├── gpu_dev.hpp │ │ └── gpu.hpp │ ├── net │ │ ├── ip.hpp │ │ ├── dhcp.hpp │ │ ├── CMakeLists.txt │ │ ├── nic │ │ │ ├── CMakeLists.txt │ │ │ ├── nic.hpp │ │ │ ├── nic.cpp │ │ │ └── virtio.cpp │ │ ├── mac.hpp │ │ ├── tcp.hpp │ │ ├── ethernet.cpp │ │ ├── checksum.hpp │ │ ├── ethernet.hpp │ │ ├── udp.hpp │ │ ├── ipv4.hpp │ │ ├── arp.hpp │ │ ├── packet.hpp │ │ ├── ipv4.cpp │ │ └── packet.cpp │ ├── random.hpp │ ├── evm.cpp │ ├── qemu │ │ ├── fw_cfg_aarch64.hpp │ │ ├── fw_cfg_x86.hpp │ │ └── CMakeLists.txt │ ├── date_time_provider.hpp │ ├── dev.hpp │ ├── CMakeLists.txt │ ├── dev.cpp │ ├── evm.hpp │ ├── user_dev.hpp │ ├── event.hpp │ ├── clock.hpp │ └── user_dev.cpp ├── arch │ ├── x86 │ │ ├── smp.hpp │ │ ├── dev │ │ │ ├── rtc.hpp │ │ │ ├── hpet.hpp │ │ │ ├── vmx.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── lapic.hpp │ │ │ └── io_apic.hpp │ │ ├── loader │ │ │ ├── info.hpp │ │ │ └── start.S │ │ ├── interrupts │ │ │ ├── idt.hpp │ │ │ ├── gdt.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── gdt.S │ │ │ ├── tss.hpp │ │ │ ├── usermode.S │ │ │ └── gdt.cpp │ │ ├── include │ │ │ ├── x86 │ │ │ │ ├── irq.hpp │ │ │ │ └── io.hpp │ │ │ └── arch │ │ │ │ ├── arch_irq.hpp │ │ │ │ ├── arch_cpu.hpp │ │ │ │ ├── misc.hpp │ │ │ │ ├── arch_syscalls.hpp │ │ │ │ ├── arch_thread.hpp │ │ │ │ └── paging.hpp │ │ ├── mod.hpp │ │ ├── cpuid.hpp │ │ ├── CMakeLists.txt │ │ ├── mem │ │ │ └── std_mem.cpp │ │ ├── mod.cpp │ │ ├── simd_state.hpp │ │ ├── acpi │ │ │ └── madt.cpp │ │ └── start.cpp │ ├── aarch64 │ │ ├── dev │ │ │ ├── ramfb.hpp │ │ │ ├── gic_v3.hpp │ │ │ ├── discovery.hpp │ │ │ ├── CMakeLists.txt │ │ │ ├── gic.cpp │ │ │ ├── timer.hpp │ │ │ ├── psci.hpp │ │ │ ├── gic.hpp │ │ │ └── ramfb.cpp │ │ ├── cpu.cpp │ │ ├── interrupts │ │ │ ├── CMakeLists.txt │ │ │ ├── exceptions.hpp │ │ │ └── irq.cpp │ │ ├── smp.hpp │ │ ├── include │ │ │ └── arch │ │ │ │ ├── arch_irq.hpp │ │ │ │ ├── arch_cpu.hpp │ │ │ │ ├── arch_syscalls.hpp │ │ │ │ ├── misc.hpp │ │ │ │ ├── arch_thread.hpp │ │ │ │ └── paging.hpp │ │ ├── loader │ │ │ ├── constants.hpp │ │ │ └── early_paging.hpp │ │ ├── cpu.hpp │ │ ├── mem │ │ │ ├── aarch64_mem.hpp │ │ │ ├── std_mem.cpp │ │ │ └── mem.cpp │ │ └── CMakeLists.txt │ ├── random.hpp │ ├── user │ │ ├── include │ │ │ └── arch │ │ │ │ ├── arch_cpu.hpp │ │ │ │ ├── arch_thread.hpp │ │ │ │ ├── misc.hpp │ │ │ │ ├── arch_syscalls.hpp │ │ │ │ └── paging.hpp │ │ ├── CMakeLists.txt │ │ └── generic.cpp │ ├── sleep.hpp │ ├── irq.hpp │ └── cpu.hpp ├── mem │ ├── mem.cpp │ ├── CMakeLists.txt │ ├── mem.hpp │ ├── mmio.hpp │ ├── unique_phys.cpp │ ├── unique_phys.hpp │ ├── malloc.hpp │ ├── vspace.hpp │ ├── iospace.cpp │ ├── iospace.hpp │ ├── pmalloc.hpp │ ├── vmem.hpp │ └── mmio.cpp ├── utils │ ├── CMakeLists.txt │ ├── irq_guard.hpp │ ├── flags_enum.hpp │ └── cpu_var.hpp ├── exe │ ├── CMakeLists.txt │ ├── elf_loader.hpp │ └── elf.hpp ├── std │ ├── cstdint.hpp │ ├── cxx.cpp │ ├── cstddef.hpp │ ├── assert.hpp │ ├── memory.hpp │ ├── new.hpp │ ├── cmath.hpp │ ├── compare.hpp │ ├── concepts.hpp │ ├── cstring.hpp │ ├── new.cpp │ ├── inttypes.hpp │ ├── utility.hpp │ ├── initializer_list.hpp │ ├── manually_destroy.hpp │ ├── array.hpp │ ├── CMakeLists.txt │ ├── manually_init.hpp │ ├── format.hpp │ ├── span.hpp │ ├── cstring.cpp │ ├── tests.cpp │ ├── limits.hpp │ ├── expected.hpp │ └── unique_ptr.hpp ├── fs │ ├── CMakeLists.txt │ ├── tar.hpp │ ├── pipe.hpp │ ├── vfs.cpp │ ├── pipe.cpp │ └── vfs.hpp ├── sys │ ├── posix │ │ ├── CMakeLists.txt │ │ ├── posix_sys.hpp │ │ ├── signals.hpp │ │ └── all.cpp │ ├── syscalls.hpp │ ├── CMakeLists.txt │ ├── service.hpp │ ├── event_queue.hpp │ ├── event_queue.cpp │ ├── user_access.hpp │ ├── socket.hpp │ └── service.cpp ├── acpi │ ├── events.hpp │ ├── CMakeLists.txt │ ├── sleep.hpp │ ├── pci.hpp │ └── acpi.cpp ├── sched │ ├── CMakeLists.txt │ ├── shared_mem.hpp │ ├── deferred_work.hpp │ ├── sysv.hpp │ ├── shared_mem.cpp │ ├── cpu_set.hpp │ ├── signal_ctx.hpp │ ├── ipc.hpp │ ├── handle_table.hpp │ ├── sched.hpp │ ├── handle_table.cpp │ ├── mutex.hpp │ └── thread.cpp ├── types.hpp └── CMakeLists.txt ├── fonts └── Tamsyn8x16r.psf ├── images └── desktop_23_10_2024.png ├── cmake ├── image_user.cmake ├── image_aarch64.cmake ├── toolchain_msm_clang.cmake ├── toolchain_x86_64_clang.cmake └── toolchain_aarch64_clang.cmake ├── config.hpp.in ├── .gitmodules ├── limine.conf ├── include └── crescent │ ├── time.h │ ├── posix_syscalls.h │ └── socket.h ├── CMakeOptions.cmake ├── lds ├── x86_64.ld └── aarch64.ld └── .github └── workflows └── it-compiles-test.yml /libs/libcxx/src/dummy.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/console/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build* 2 | build 3 | -------------------------------------------------------------------------------- /src/dev/usb/hcd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(xhci) 2 | -------------------------------------------------------------------------------- /src/arch/x86/smp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void x86_smp_init(); 4 | -------------------------------------------------------------------------------- /src/arch/x86/dev/rtc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void x86_rtc_init(); 4 | -------------------------------------------------------------------------------- /src/mem/mem.cpp: -------------------------------------------------------------------------------- 1 | #include "mem.hpp" 2 | 3 | usize HHDM_START = 0; 4 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/ramfb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ramfb_init(); 4 | -------------------------------------------------------------------------------- /src/arch/aarch64/cpu.cpp: -------------------------------------------------------------------------------- 1 | #include "cpu.hpp" 2 | 3 | CpuFeatures CPU_FEATURES; 4 | -------------------------------------------------------------------------------- /src/dev/fb/fb_dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void fb_dev_register_boot_fb(); 4 | -------------------------------------------------------------------------------- /src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | ubsan.cpp 3 | ) 4 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/gic_v3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void gic_v3_init_on_cpu(); 4 | -------------------------------------------------------------------------------- /src/dev/sound/hda/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | hda.cpp 3 | ) 4 | -------------------------------------------------------------------------------- /src/exe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | elf_loader.cpp 3 | ) 4 | -------------------------------------------------------------------------------- /fonts/Tamsyn8x16r.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qwinci/crescent/HEAD/fonts/Tamsyn8x16r.psf -------------------------------------------------------------------------------- /src/arch/aarch64/dev/discovery.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void dtb_discover_devices(); 4 | -------------------------------------------------------------------------------- /src/std/cstdint.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // NOLINT(*-deprecated-headers) 3 | -------------------------------------------------------------------------------- /src/arch/random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | u64 arch_get_random_seed(); 5 | -------------------------------------------------------------------------------- /src/arch/user/include/arch/arch_cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct ArchCpu { 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /src/arch/x86/loader/info.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct BootInfo { 4 | void* rsdp; 5 | }; 6 | -------------------------------------------------------------------------------- /src/dev/bt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | bt_dev.cpp 3 | hci.cpp 4 | ) 5 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/idt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void x86_init_idt(); 4 | void x86_load_idt(); 5 | -------------------------------------------------------------------------------- /src/dev/fb/font.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | extern u8 font8x8_basic[128][8]; 5 | -------------------------------------------------------------------------------- /src/dev/usb/dev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | hid.cpp 3 | rndis.cpp 4 | ) 5 | -------------------------------------------------------------------------------- /src/fs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | tar.cpp 3 | vfs.cpp 4 | pipe.cpp 5 | ) 6 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/gdt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Tss; 4 | 5 | void x86_load_gdt(Tss* tss); 6 | -------------------------------------------------------------------------------- /images/desktop_23_10_2024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qwinci/crescent/HEAD/images/desktop_23_10_2024.png -------------------------------------------------------------------------------- /libs/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(common src/sys.cpp) 2 | 3 | target_include_directories(common PUBLIC include) 4 | -------------------------------------------------------------------------------- /src/dev/fb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | fb.cpp 3 | fb_dev.cpp 4 | font.cpp 5 | ) 6 | -------------------------------------------------------------------------------- /libs/libcxx/include/cassert: -------------------------------------------------------------------------------- 1 | #ifndef _CASSERT_H 2 | #define _CASSERT_H 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /libs/libcxx/include/cstdlib: -------------------------------------------------------------------------------- 1 | #ifndef _CSTDLIB_H 2 | #define _CSTDLIB_H 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /libs/libcxx/include/cstring: -------------------------------------------------------------------------------- 1 | #ifndef _CSTRING_H 2 | #define _CSTRING_H 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/arch/x86/dev/hpet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void hpet_init(); 4 | void hpet_suspend(); 5 | void hpet_resume(); 6 | -------------------------------------------------------------------------------- /apps/desktop/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(desktop PRIVATE 2 | desktop.cpp 3 | window.cpp 4 | taskbar.cpp 5 | ) 6 | -------------------------------------------------------------------------------- /apps/evm/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(evm PRIVATE 2 | vm.cpp 3 | vga.cpp 4 | pci.cpp 5 | chipset.cpp 6 | ) 7 | -------------------------------------------------------------------------------- /cmake/image_user.cmake: -------------------------------------------------------------------------------- 1 | add_custom_target(run 2 | COMMAND crescent 3 | DEPENDS crescent USES_TERMINAL VERBATIM 4 | ) 5 | -------------------------------------------------------------------------------- /src/dev/sound/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | sound_dev.cpp 3 | ) 4 | 5 | add_subdirectory(hda) 6 | -------------------------------------------------------------------------------- /src/fs/tar.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | void tar_initramfs_init(const void* data, usize size); 5 | -------------------------------------------------------------------------------- /src/dev/date_time_provider.cpp: -------------------------------------------------------------------------------- 1 | #include "date_time_provider.hpp" 2 | 3 | Mutex DATE_TIME_PROVIDER {}; 4 | -------------------------------------------------------------------------------- /src/sys/posix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | all.cpp 3 | fd.cpp 4 | mem.cpp 5 | signals.cpp 6 | ) 7 | -------------------------------------------------------------------------------- /libs/libcxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(libcxx 2 | src/dummy.cpp 3 | ) 4 | 5 | target_include_directories(libcxx SYSTEM PUBLIC include) 6 | -------------------------------------------------------------------------------- /src/dev/gpu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(ARCH STREQUAL "x86_64") 2 | target_sources(crescent PRIVATE 3 | bochs_vbe.cpp 4 | ) 5 | endif() 6 | -------------------------------------------------------------------------------- /src/dev/net/ip.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | enum class IpProtocol : u8 { 5 | Tcp = 6, 6 | Udp = 17 7 | }; 8 | -------------------------------------------------------------------------------- /apps/evm/src/vga.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vm.hpp" 3 | 4 | void vga_init(Vm* vm); 5 | void vga_print_text_mem(uint32_t* fb); 6 | -------------------------------------------------------------------------------- /src/arch/aarch64/interrupts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | exceptions.cpp 3 | exceptions.S 4 | irq.cpp 5 | ) 6 | -------------------------------------------------------------------------------- /src/sys/syscalls.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/arch_syscalls.hpp" 3 | 4 | extern "C" void syscall_handler(SyscallFrame* frame); 5 | -------------------------------------------------------------------------------- /src/arch/aarch64/smp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dtb.hpp" 3 | 4 | void aarch64_smp_init(dtb::Dtb& dtb); 5 | void aarch64_bsp_init(); 6 | -------------------------------------------------------------------------------- /src/dev/usb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | device.cpp 3 | ) 4 | 5 | add_subdirectory(hcd) 6 | add_subdirectory(dev) 7 | -------------------------------------------------------------------------------- /apps/evm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | APP(evm 2 | src/main.cpp 3 | ) 4 | target_link_libraries(evm PRIVATE windower common) 5 | 6 | add_subdirectory(src) 7 | -------------------------------------------------------------------------------- /src/arch/x86/dev/vmx.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/evm.hpp" 3 | 4 | bool vmx_supported(); 5 | kstd::shared_ptr vmx_create_vm(); 6 | -------------------------------------------------------------------------------- /libs/libnet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(net src/dns.cpp) 2 | 3 | target_include_directories(net PUBLIC include) 4 | target_link_libraries(net PRIVATE common) 5 | -------------------------------------------------------------------------------- /src/std/cxx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdio.hpp" 2 | 3 | extern "C" [[noreturn]] void __cxa_pure_virtual() { 4 | panic("Pure virtual function called"); 5 | } 6 | -------------------------------------------------------------------------------- /src/sys/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | syscalls.cpp 3 | event_queue.cpp 4 | service.cpp 5 | ) 6 | 7 | add_subdirectory(posix) 8 | -------------------------------------------------------------------------------- /libs/libtext/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(text src/main.cpp) 2 | 3 | target_include_directories(text PUBLIC include) 4 | target_link_libraries(text PRIVATE common) 5 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/arch_irq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/aarch64/interrupts/exceptions.hpp" 3 | 4 | using IrqFrame = ExceptionFrame; 5 | -------------------------------------------------------------------------------- /apps/console/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | APP(console 2 | src/main.cpp 3 | ) 4 | target_link_libraries(console PRIVATE windower net common) 5 | 6 | add_subdirectory(src) 7 | -------------------------------------------------------------------------------- /apps/desktop/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | APP(desktop 2 | src/main.cpp 3 | ) 4 | target_link_libraries(desktop PRIVATE windower ui common) 5 | 6 | add_subdirectory(src) 7 | -------------------------------------------------------------------------------- /src/std/cstddef.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // NOLINT(*-deprecated-headers) 3 | 4 | namespace kstd { 5 | using nullptr_t = decltype(nullptr); 6 | } 7 | -------------------------------------------------------------------------------- /config.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #cmakedefine CONFIG_MAX_CPUS @CONFIG_MAX_CPUS@ 4 | #cmakedefine01 CONFIG_TRACING 5 | #cmakedefine01 CONFIG_PCI 6 | #cmakedefine01 CONFIG_DTB 7 | -------------------------------------------------------------------------------- /src/acpi/events.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "functional.hpp" 4 | 5 | namespace acpi { 6 | void early_events_init(); 7 | void events_init(); 8 | } 9 | -------------------------------------------------------------------------------- /libs/libnet/include/net/ip.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct Ipv4 { 5 | uint32_t value; 6 | }; 7 | 8 | struct Ipv6 { 9 | uint16_t value[8]; 10 | }; 11 | -------------------------------------------------------------------------------- /src/arch/x86/include/x86/irq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | u32 x86_alloc_irq(u32 count, bool shared); 5 | void x86_dealloc_irq(u32 irq, u32 count, bool shared); 6 | -------------------------------------------------------------------------------- /src/dev/net/dhcp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Nic; 4 | struct ReceivedPacket; 5 | 6 | void dhcp_process_packet(Nic& nic, ReceivedPacket& packet); 7 | void dhcp_discover(Nic* nic); 8 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | discovery.cpp 3 | spmi.cpp 4 | gic.cpp 5 | gic_v3.cpp 6 | psci.cpp 7 | timer.cpp 8 | ramfb.cpp 9 | ) 10 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | gdt.cpp 3 | gdt.S 4 | idt.cpp 5 | stubs.S 6 | irq.cpp 7 | exceptions.cpp 8 | usermode.S 9 | ) 10 | -------------------------------------------------------------------------------- /src/dev/random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | void random_add_entropy(const u64* data, usize words, u32 credible_bits); 5 | void random_generate(void* data, usize size); 6 | -------------------------------------------------------------------------------- /libs/libui/include/ui/keyboard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace ui { 5 | struct KeyState { 6 | Scancode code; 7 | bool pressed; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/acpi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(ARCH STREQUAL "x86_64") 2 | target_sources(crescent PRIVATE 3 | acpi.cpp 4 | events.cpp 5 | qacpi.cpp 6 | sleep.cpp 7 | pci.cpp 8 | ) 9 | endif() 10 | -------------------------------------------------------------------------------- /apps/desktop/BUGS.md: -------------------------------------------------------------------------------- 1 | - hovering over eg. the close button and moving the mouse on top of an another 2 | partially overlapping window with the primary button down doesn't cause a mouse leave event 3 | -------------------------------------------------------------------------------- /src/arch/aarch64/loader/constants.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | inline constexpr usize KERNEL_OFFSET = 0xFFFFFFFF80000000; 5 | constexpr usize HHDM_OFFSET = 0xFFFF000000000000; 6 | -------------------------------------------------------------------------------- /src/arch/user/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_include_directories(crescent PRIVATE include) 2 | target_sources(crescent PRIVATE 3 | generic.cpp 4 | ../aarch64/kernel_dtb.cpp 5 | ../aarch64/dtb.cpp 6 | ) 7 | -------------------------------------------------------------------------------- /src/mem/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | mem.cpp 3 | pmalloc.cpp 4 | vmem.cpp 5 | malloc.cpp 6 | vspace.cpp 7 | iospace.cpp 8 | unique_phys.cpp 9 | mmio.cpp 10 | ) 11 | -------------------------------------------------------------------------------- /src/sched/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | handle_table.cpp 3 | process.cpp 4 | sched.cpp 5 | thread.cpp 6 | ipc.cpp 7 | shared_mem.cpp 8 | signal_ctx.cpp 9 | ) 10 | -------------------------------------------------------------------------------- /apps/evm/src/chipset.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vm.hpp" 3 | 4 | void chipset_init(Vm* vm, uint32_t* fb, uint32_t fb_size); 5 | void chipset_update_timers(uint64_t elapsed_tsc, const ArchInfo& info); 6 | -------------------------------------------------------------------------------- /src/sched/shared_mem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vector.hpp" 3 | 4 | struct SharedMemory { 5 | ~SharedMemory(); 6 | 7 | kstd::vector pages; 8 | Spinlock usage_count; 9 | }; 10 | -------------------------------------------------------------------------------- /libs/libnet/include/net/dns.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ip.hpp" 3 | #include 4 | #include 5 | 6 | namespace dns { 7 | std::optional resolve4(std::string_view domain); 8 | } 9 | -------------------------------------------------------------------------------- /libs/libwindower/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(windower 2 | src/windower.cpp 3 | src/windower_c.cpp 4 | ) 5 | 6 | target_include_directories(windower PUBLIC include) 7 | target_link_libraries(windower PRIVATE common) 8 | -------------------------------------------------------------------------------- /src/arch/x86/dev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | hpet.cpp 3 | io_apic.cpp 4 | lapic.cpp 5 | ps2.cpp 6 | ps2_keyboard.cpp 7 | ps2_mouse.cpp 8 | rtc.cpp 9 | vmx.cpp 10 | ) 11 | -------------------------------------------------------------------------------- /src/dev/net/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | ethernet.cpp 3 | ipv4.cpp 4 | udp.cpp 5 | tcp.cpp 6 | arp.cpp 7 | packet.cpp 8 | dhcp.cpp 9 | ) 10 | 11 | add_subdirectory(nic) 12 | -------------------------------------------------------------------------------- /src/sched/deferred_work.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "double_list.hpp" 3 | #include "functional.hpp" 4 | 5 | struct DeferredIrqWork { 6 | DoubleListHook hook {}; 7 | kstd::small_function fn; 8 | }; 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "qacpi"] 2 | path = qacpi 3 | url = https://github.com/Qwinci/qacpi.git 4 | [submodule "libs/libc/hzutils"] 5 | path = libs/libc/hzutils 6 | url = https://github.com/Qwinci/hzutils.git 7 | -------------------------------------------------------------------------------- /apps/desktop/src/event.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windower/protocol.hpp" 3 | 4 | namespace protocol = windower::protocol; 5 | 6 | void send_event_to_window(ui::Window* window, protocol::WindowEvent event); 7 | -------------------------------------------------------------------------------- /src/std/assert.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdio.hpp" 3 | 4 | #define assert(...) ((__VA_ARGS__) ? (void) 0 : panic(__FILE_NAME__, ":", __LINE__, ": (", __func__, ") assertion '", #__VA_ARGS__, "' failed\n")) 5 | -------------------------------------------------------------------------------- /src/arch/aarch64/cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct CpuFeatures { 5 | bool pan; 6 | }; 7 | static_assert(offsetof(CpuFeatures, pan) == 0); 8 | 9 | extern CpuFeatures CPU_FEATURES; 10 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/arch_cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/aarch64/dev/timer.hpp" 3 | 4 | struct ArchCpu { 5 | ArmTickSource arm_tick_source {}; 6 | u32 affinity {}; 7 | Ipi ipi_reason {}; 8 | }; 9 | -------------------------------------------------------------------------------- /src/dev/net/nic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | nic.cpp 3 | ) 4 | 5 | if(ARCH STREQUAL "x86_64") 6 | target_sources(crescent PRIVATE 7 | rtl8168.cpp 8 | virtio.cpp 9 | ) 10 | endif() 11 | -------------------------------------------------------------------------------- /src/dev/evm.cpp: -------------------------------------------------------------------------------- 1 | #include "evm.hpp" 2 | 3 | evm::Evm::~Evm() { 4 | for (auto& page : pages) { 5 | auto guard = page.lock.lock(); 6 | if (--page.ref_count == 0) { 7 | pfree(page.phys(), 1); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /limine.conf: -------------------------------------------------------------------------------- 1 | timeout: 0 2 | 3 | /crescent 4 | PROTOCOL: limine 5 | KERNEL_PATH: boot():/crescent 6 | KERNEL_CMDLINE: 7 | 8 | MODULE_PATH: boot():/initramfs_x86_64.tar 9 | MODULE_CMDLINE: initramfs.tar 10 | 11 | KASLR: no 12 | -------------------------------------------------------------------------------- /src/acpi/sleep.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace acpi { 4 | enum class SleepState { 5 | S3, 6 | S5 7 | }; 8 | 9 | void reboot(); 10 | void enter_sleep_state(SleepState state); 11 | void wake_from_sleep(); 12 | } 13 | -------------------------------------------------------------------------------- /src/arch/aarch64/interrupts/exceptions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct ExceptionFrame { 5 | u64 x[31]; 6 | u64 sp; 7 | u64 esr_el1; 8 | u64 far_el1; 9 | u64 elr_el1; 10 | u64 spsr_el1; 11 | }; 12 | -------------------------------------------------------------------------------- /src/arch/user/include/arch/arch_thread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Process; 4 | 5 | struct ArchThread { 6 | constexpr ArchThread() = default; 7 | constexpr ArchThread(void (*fn)(void*), void* arg, Process* process) {} 8 | }; 9 | -------------------------------------------------------------------------------- /src/dev/net/mac.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "array.hpp" 3 | #include "types.hpp" 4 | 5 | struct Mac { 6 | kstd::array data; 7 | }; 8 | 9 | static constexpr Mac BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 10 | -------------------------------------------------------------------------------- /cmake/image_aarch64.cmake: -------------------------------------------------------------------------------- 1 | add_custom_command(TARGET crescent POST_BUILD 2 | COMMAND ${CMAKE_OBJCOPY} -O binary bin/crescent crescent.bin 3 | ) 4 | 5 | install(FILES "${CMAKE_BINARY_DIR}/crescent.bin" 6 | DESTINATION "crescent" 7 | ) 8 | -------------------------------------------------------------------------------- /src/arch/x86/mod.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "string_view.hpp" 4 | 5 | struct Module { 6 | void* data; 7 | usize size; 8 | }; 9 | 10 | bool x86_get_module(Module& module, kstd::string_view name); 11 | -------------------------------------------------------------------------------- /libs/libui/include/ui/mouse.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "primitive.hpp" 3 | 4 | namespace ui { 5 | struct MouseState { 6 | Point pos; 7 | bool left_pressed; 8 | bool right_pressed; 9 | bool middle_pressed; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/gic.cpp: -------------------------------------------------------------------------------- 1 | #include "gic.hpp" 2 | #include "gic_v3.hpp" 3 | 4 | void gic_init_on_cpu() { 5 | if (GIC_VERSION == 3) { 6 | gic_v3_init_on_cpu(); 7 | } 8 | } 9 | 10 | Gic* GIC = nullptr; 11 | u32 GIC_VERSION = 0; 12 | -------------------------------------------------------------------------------- /src/dev/qemu/fw_cfg_aarch64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | 5 | kstd::optional qemu_fw_cfg_get_file(kstd::string_view name); 6 | bool qemu_fw_cfg_write(u16 selector, const void* data, u32 size); 7 | -------------------------------------------------------------------------------- /src/dev/qemu/fw_cfg_x86.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "optional.hpp" 3 | #include "vector.hpp" 4 | 5 | void qemu_fw_cfg_init(); 6 | bool qemu_fw_cfg_present(); 7 | kstd::optional> qemu_fw_cfg_get_file(kstd::string_view name); 8 | -------------------------------------------------------------------------------- /src/sched/sysv.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct SysvInfo { 5 | usize ld_entry; 6 | usize exe_entry; 7 | usize ld_base; 8 | usize exe_phdrs_addr; 9 | u16 exe_phdr_count; 10 | u16 exe_phdr_size; 11 | }; 12 | -------------------------------------------------------------------------------- /cmake/toolchain_msm_clang.cmake: -------------------------------------------------------------------------------- 1 | include(${CMAKE_CURRENT_LIST_DIR}/toolchain_aarch64_clang.cmake) 2 | 3 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8.2-a") 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8.2-a") 5 | 6 | set(BOARD "msm") 7 | -------------------------------------------------------------------------------- /libs/libc/include/bits/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _BITS_UTILS_H 2 | #define _BITS_UTILS_H 3 | 4 | #ifdef __cplusplus 5 | #define __begin extern "C" { 6 | #define __end } 7 | #else 8 | #define __begin 9 | #define __end 10 | #endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/dev/qemu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(ARCH STREQUAL "x86_64") 2 | target_sources(crescent PRIVATE 3 | fw_cfg_x86.cpp 4 | ) 5 | elseif(ARCH STREQUAL "aarch64") 6 | target_sources(crescent PRIVATE 7 | fw_cfg_aarch64.cpp 8 | ) 9 | endif() 10 | -------------------------------------------------------------------------------- /libs/libcxx/include/cstddef: -------------------------------------------------------------------------------- 1 | #ifndef _CSTDDEF_H 2 | #define _CSTDDEF_H 3 | 4 | #include 5 | 6 | namespace std { 7 | using ::size_t; 8 | using ::ptrdiff_t; 9 | 10 | using nullptr_t = decltype(nullptr); 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/utils/irq_guard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/misc.hpp" 3 | 4 | struct IrqGuard { 5 | IrqGuard() { 6 | old = arch_enable_irqs(false); 7 | } 8 | ~IrqGuard() { 9 | arch_enable_irqs(old); 10 | } 11 | 12 | private: 13 | bool old; 14 | }; 15 | -------------------------------------------------------------------------------- /src/arch/aarch64/mem/aarch64_mem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct MemReserve { 5 | usize base; 6 | usize len; 7 | }; 8 | 9 | void aarch64_mem_check_add_usable_range(usize base, usize len, MemReserve* reserve, u32 reserve_count); 10 | -------------------------------------------------------------------------------- /src/arch/x86/loader/start.S: -------------------------------------------------------------------------------- 1 | .globl BSP_STACK 2 | .comm BSP_STACK, 0x8000, 16 3 | 4 | .section .text 5 | .globl _start 6 | .type _start, @function 7 | _start: 8 | lea BSP_STACK + 0x8000 - 8(%rip), %rsp 9 | jmp early_start 10 | 11 | .section .note.GNU-stack 12 | -------------------------------------------------------------------------------- /src/dev/date_time_provider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/time.h" 3 | #include "sched/mutex.hpp" 4 | 5 | struct DateTimerProvider { 6 | virtual int get_date(CrescentDateTime& res) = 0; 7 | }; 8 | 9 | extern Mutex DATE_TIME_PROVIDER; 10 | -------------------------------------------------------------------------------- /src/std/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "new.hpp" 3 | 4 | namespace std { 5 | template 6 | constexpr T* construct_at(T* p, Args&&... args) { 7 | return new (static_cast(p)) T {static_cast(args)...}; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/arch/sleep.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace acpi { 4 | extern usize SMP_TRAMPOLINE_PHYS_ADDR; 5 | extern usize SMP_TRAMPLINE_PHYS_ENTRY16; 6 | extern usize SMP_TRAMPLINE_PHYS_ENTRY32; 7 | } 8 | 9 | void arch_sleep_init(); 10 | void arch_prepare_for_sleep(); 11 | -------------------------------------------------------------------------------- /src/dev/net/tcp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_ptr.hpp" 3 | #include "sys/socket.hpp" 4 | 5 | struct Nic; 6 | struct ReceivedPacket; 7 | 8 | void tcp_process_packet(Nic& nic, ReceivedPacket& packet); 9 | kstd::shared_ptr tcp_socket_create(int flags); 10 | -------------------------------------------------------------------------------- /src/sched/shared_mem.cpp: -------------------------------------------------------------------------------- 1 | #include "shared_mem.hpp" 2 | #include "mem/pmalloc.hpp" 3 | 4 | SharedMemory::~SharedMemory() { 5 | auto guard = usage_count.lock(); 6 | --*guard; 7 | if (!*guard) { 8 | for (auto page : pages) { 9 | pfree(page, 1); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/libui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(ui 2 | src/context.cpp 3 | src/gui.cpp 4 | src/window.cpp 5 | src/button.cpp 6 | src/text.cpp 7 | ) 8 | 9 | target_include_directories(ui PUBLIC include) 10 | target_link_libraries(ui PUBLIC text) 11 | target_link_libraries(ui PRIVATE common) 12 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/arch_irq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct IrqFrame { 5 | u64 r15, r14, r13, r12, r11, r10, r9, r8, rbp, rsi, rdi, rdx, rcx, rbx, rax; 6 | u64 error; 7 | u64 rip; 8 | u64 cs; 9 | u64 rflags; 10 | u64 rsp; 11 | u64 ss; 12 | }; 13 | -------------------------------------------------------------------------------- /src/std/new.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstddef.hpp" 3 | 4 | constexpr void* operator new(size_t, void* ptr) { 5 | return ptr; 6 | } 7 | 8 | namespace kstd { 9 | template 10 | [[nodiscard]] constexpr T* launder(T* ptr) { 11 | return __builtin_launder(ptr); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /include/crescent/time.h: -------------------------------------------------------------------------------- 1 | #ifndef CRESCENT_TIME_H 2 | #define CRESCENT_TIME_H 3 | 4 | #include 5 | 6 | typedef struct CrescentDateTime { 7 | uint16_t year; 8 | uint8_t month; 9 | uint8_t day; 10 | uint8_t hour; 11 | uint8_t minute; 12 | uint8_t second; 13 | } CrescentDateTime; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/arch/user/include/arch/misc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern bool IRQS_ENABLED; 5 | 6 | static inline bool arch_enable_irqs(bool enable) { 7 | auto old = IRQS_ENABLED; 8 | IRQS_ENABLED = enable; 9 | return old; 10 | } 11 | 12 | static inline void arch_hlt() { 13 | abort(); 14 | } 15 | -------------------------------------------------------------------------------- /libs/libc/src/assert.cpp: -------------------------------------------------------------------------------- 1 | #include "assert.h" 2 | #include "stdlib.h" 3 | #include "stdio.h" 4 | 5 | __attribute__((noreturn)) void __assert_fail(const char* expr, const char* file, unsigned int line, const char* func) { 6 | fprintf(stderr, "%s:%u: (%s): assertion '%s' failed\n", file, line, func, expr); 7 | abort(); 8 | } 9 | -------------------------------------------------------------------------------- /src/sys/service.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sched/process.hpp" 3 | #include "optional.hpp" 4 | 5 | void service_create(kstd::vector&& features, Process* process); 6 | void service_remove(Process* process); 7 | kstd::shared_ptr service_get(const kstd::vector& needed_features); 8 | -------------------------------------------------------------------------------- /src/arch/x86/cpuid.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct Cpuid { 5 | u32 eax; 6 | u32 ebx; 7 | u32 ecx; 8 | u32 edx; 9 | }; 10 | 11 | inline Cpuid cpuid(u32 eax, u32 ecx) { 12 | Cpuid id {}; 13 | asm("cpuid" : "=a"(id.eax), "=b"(id.ebx), "=c"(id.ecx), "=d"(id.edx) : "a"(eax), "c"(ecx)); 14 | return id; 15 | } 16 | -------------------------------------------------------------------------------- /libs/libc/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "bits/utils.h" 5 | #include 6 | 7 | __begin 8 | 9 | size_t strlen(const char* __str); 10 | void* memset(void* __dest, int __ch, size_t __size); 11 | void* memcpy(void* __dest, const void* __src, size_t __size); 12 | 13 | __end 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/acpi/pci.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | 5 | namespace acpi { 6 | struct LegacyPciIrq { 7 | u32 gsi; 8 | bool edge_triggered; 9 | bool active_high; 10 | }; 11 | 12 | void pci_init(); 13 | kstd::optional get_legacy_pci_irq(u16 seg, u8 bus, u8 device, u8 pci_pin); 14 | } 15 | -------------------------------------------------------------------------------- /src/arch/user/include/arch/arch_syscalls.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct SyscallFrame { 5 | u64 number; 6 | u64 a0; 7 | 8 | constexpr u64* num() { 9 | return &number; 10 | } 11 | 12 | constexpr u64* ret() { 13 | return &number; 14 | } 15 | 16 | constexpr u64* arg0() { 17 | return &a0; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/gdt.S: -------------------------------------------------------------------------------- 1 | .globl x86_load_gdt_asm 2 | .type x86_load_gdt_asm, @function 3 | 4 | x86_load_gdt_asm: 5 | lgdt (%rdi) 6 | mov $0x10, %ax 7 | mov %ax, %ds 8 | mov %ax, %ss 9 | mov %ax, %es 10 | mov %ax, %fs 11 | mov %ax, %gs 12 | pop %rdi 13 | push $0x8 14 | push %rdi 15 | lretq 16 | 17 | .section .note.GNU-stack 18 | -------------------------------------------------------------------------------- /src/dev/usb/hcd/xhci/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(CONFIG_USB_XHCI) 2 | target_sources(crescent PRIVATE 3 | xhci.cpp 4 | transfer_ring.cpp 5 | ) 6 | 7 | if(CONFIG_XHCI_PCI) 8 | target_sources(crescent PRIVATE xhci_pci.cpp) 9 | endif() 10 | 11 | if(CONFIG_XHCI_DTB) 12 | target_sources(crescent PRIVATE xhci_dwc3.cpp) 13 | endif() 14 | endif() 15 | -------------------------------------------------------------------------------- /src/std/cmath.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "bit.hpp" 3 | 4 | namespace kstd { 5 | template 6 | constexpr int log2(T value) { 7 | if (value == 0) { 8 | return 0; 9 | } 10 | return bit_width(value) - 1; 11 | } 12 | 13 | template 14 | constexpr T pow2(unsigned int power) { 15 | return T {1} << power; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/sys/posix/posix_sys.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "errno.hpp" 4 | #include "arch/arch_syscalls.hpp" 5 | 6 | using pid_t = i32; 7 | 8 | using off64_t = i64; 9 | using time64_t = i64; 10 | 11 | struct timespec64 { 12 | time64_t tv_sec; 13 | long tv_nsec; 14 | }; 15 | 16 | struct sigset_t { 17 | unsigned long value; 18 | }; 19 | -------------------------------------------------------------------------------- /libs/libc/include/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASSERT_H 2 | #define _ASSERT_H 3 | 4 | __attribute__((noreturn)) void __assert_fail(const char* __expr, const char* __file, unsigned int __line, const char* __func); 5 | 6 | #ifndef NDEBUG 7 | #define assert(expr) ((expr) ? (void) 0 : __assert_fail(#expr, __FILE__, __LINE__, __func__)) 8 | #else 9 | #define assert(...) 10 | #endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /libs/libcxx/include/cstdint: -------------------------------------------------------------------------------- 1 | #ifndef _CSTDINT_H 2 | #define _CSTDINT_H 3 | 4 | #include 5 | 6 | namespace std { 7 | using ::uint8_t; 8 | using ::uint16_t; 9 | using ::uint32_t; 10 | using ::uint64_t; 11 | using ::uintptr_t; 12 | 13 | using ::int8_t; 14 | using ::int16_t; 15 | using ::int32_t; 16 | using ::int64_t; 17 | using ::intptr_t; 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/arch_cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/x86/interrupts/tss.hpp" 3 | #include "arch/x86/dev/lapic.hpp" 4 | #include "manually_init.hpp" 5 | 6 | struct ArchCpu { 7 | Tss tss; 8 | ManuallyInit lapic_timer; 9 | usize kernel_stack_base; 10 | usize saved_halt_rsp; 11 | usize saved_halt_rip; 12 | u64 tsc_freq; 13 | u32 lapic_id; 14 | }; 15 | -------------------------------------------------------------------------------- /src/std/compare.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace kstd { 4 | template 5 | constexpr int threeway(const A& a, const B& b) requires requires(A a, B b) { 6 | a == b; 7 | a < b; 8 | a > b; 9 | } { 10 | if (a < b) { 11 | return -1; 12 | } 13 | else if (a > b) { 14 | return 1; 15 | } 16 | else { 17 | return 0; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/libc/include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_H 2 | #define _STDLIB_H 3 | 4 | #include "bits/utils.h" 5 | #include 6 | 7 | __begin 8 | 9 | void* malloc(size_t __size); 10 | void* realloc(void* __old, size_t __new_size); 11 | void free(void* __ptr); 12 | 13 | __attribute__((noreturn)) void exit(int status); 14 | __attribute__((noreturn)) void abort(); 15 | 16 | __end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/arch/aarch64/loader/early_paging.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | #include "arch/paging.hpp" 5 | 6 | class EarlyPageMap { 7 | public: 8 | void map_1gb(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 9 | void map(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 10 | 11 | u64 level0[512]; 12 | }; 13 | 14 | void* early_page_alloc(); 15 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/misc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | static inline void arch_hlt() { 5 | asm volatile("hlt"); 6 | } 7 | 8 | static inline bool arch_enable_irqs(bool enable) { 9 | u64 old; 10 | asm volatile("pushfq; pop %0" : "=rm"(old)); 11 | if (enable) { 12 | asm volatile("sti"); 13 | } 14 | else { 15 | asm volatile("cli"); 16 | } 17 | return old & 1 << 9; 18 | } 19 | -------------------------------------------------------------------------------- /src/arch/x86/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | loader/start.S 3 | loader/start.cpp 4 | 5 | mem/std_mem.cpp 6 | mem/paging.cpp 7 | mem/user.S 8 | 9 | start.cpp 10 | smp.cpp 11 | arch_sched.cpp 12 | mod.cpp 13 | smp_bringup.cpp 14 | 15 | acpi/madt.cpp 16 | ) 17 | target_include_directories(crescent PRIVATE include) 18 | 19 | add_subdirectory(dev) 20 | add_subdirectory(interrupts) 21 | -------------------------------------------------------------------------------- /libs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(LIB NAME) 2 | add_library(${NAME} STATIC ${ARGN}) 3 | target_compile_options(${NAME} PRIVATE 4 | -Wall -Wextra 5 | -fno-exceptions -fno-rtti 6 | -fno-strict-aliasing -fno-stack-protector 7 | -fPIC 8 | ) 9 | endmacro() 10 | 11 | add_subdirectory(common) 12 | add_subdirectory(libnet) 13 | add_subdirectory(libtext) 14 | add_subdirectory(libui) 15 | add_subdirectory(libwindower) 16 | -------------------------------------------------------------------------------- /libs/libc/src/cxx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "stdio.h" 3 | 4 | extern "C" void __cxa_pure_virtual() { 5 | 6 | } 7 | 8 | void* operator new(size_t size) { 9 | auto* ptr = malloc(size); 10 | if (!ptr) { 11 | __builtin_trap(); 12 | } 13 | return ptr; 14 | } 15 | 16 | void operator delete(void* ptr) { 17 | free(ptr); 18 | } 19 | 20 | void operator delete(void* ptr, size_t) { 21 | free(ptr); 22 | } 23 | -------------------------------------------------------------------------------- /src/std/concepts.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "type_traits.hpp" 3 | 4 | namespace kstd { 5 | template 6 | concept integral = is_integral_v; 7 | 8 | namespace __detail { 9 | template 10 | concept same_helper = kstd::is_same_v; 11 | } 12 | 13 | template 14 | concept same_as = __detail::same_helper && __detail::same_helper; 15 | } 16 | -------------------------------------------------------------------------------- /libs/libcxx/include/concepts: -------------------------------------------------------------------------------- 1 | #ifndef _CONCEPTS_H 2 | #define _CONCEPTS_H 3 | 4 | #include 5 | 6 | namespace std { 7 | namespace __detail { 8 | template 9 | concept __same_helper = is_same_v<__T, __U>; 10 | } 11 | 12 | template 13 | concept same_as = __detail::__same_helper<__T, __U> && __detail::__same_helper<__U, __T>; 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/dev/gpu/gpu_dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/user_dev.hpp" 3 | #include "gpu.hpp" 4 | 5 | class GpuDevice : public UserDevice { 6 | public: 7 | explicit GpuDevice(Gpu* gpu, kstd::string_view name) : gpu {gpu} { 8 | this->name = name; 9 | } 10 | 11 | int handle_request(const kstd::vector& data, kstd::vector& res, usize max_size) override { 12 | return ERR_UNSUPPORTED; 13 | } 14 | Gpu* gpu; 15 | }; 16 | -------------------------------------------------------------------------------- /src/exe/elf_loader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fs/vfs.hpp" 3 | #include "expected.hpp" 4 | 5 | struct LoadedElf { 6 | void (*entry)(void*); 7 | usize base; 8 | usize phdrs_addr; 9 | u16 phdr_count; 10 | u16 phdr_size; 11 | }; 12 | 13 | enum class ElfLoadError { 14 | Invalid, 15 | NoMemory 16 | }; 17 | 18 | struct Process; 19 | 20 | kstd::expected elf_load(Process* process, VNode* file); 21 | -------------------------------------------------------------------------------- /src/dev/gpu/gpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct GpuSurface { 5 | virtual ~GpuSurface() = default; 6 | virtual usize get_phys() = 0; 7 | }; 8 | 9 | class Gpu { 10 | public: 11 | virtual GpuSurface* create_surface() = 0; 12 | virtual void destroy_surface(GpuSurface* surface) = 0; 13 | virtual void flip(GpuSurface* surface) = 0; 14 | bool owns_boot_fb {}; 15 | bool supports_page_flipping {}; 16 | }; 17 | -------------------------------------------------------------------------------- /libs/libc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | LIB(libc 2 | src/stdio.cpp 3 | src/string.cpp 4 | src/stdlib.cpp 5 | src/cxx.cpp 6 | src/assert.cpp 7 | ) 8 | set_source_files_properties(src/string.cpp PROPERTIES COMPILE_FLAGS -O2) 9 | 10 | add_subdirectory(hzutils) 11 | 12 | target_include_directories(libc SYSTEM PUBLIC include) 13 | target_include_directories(libc SYSTEM PRIVATE ../libcxx/include) 14 | target_link_libraries(libc PRIVATE common hzutils) 15 | -------------------------------------------------------------------------------- /src/dev/dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "double_list.hpp" 3 | #include "utils/spinlock.hpp" 4 | 5 | struct Device { 6 | virtual ~Device() = default; 7 | 8 | virtual int suspend() = 0; 9 | virtual int resume() = 0; 10 | 11 | DoubleListHook hook {}; 12 | }; 13 | 14 | extern IrqSpinlock> ALL_DEVICES; 15 | 16 | void dev_add(Device* device); 17 | void dev_remove(Device* device); 18 | void dev_suspend_all(); 19 | void dev_resume_all(); 20 | -------------------------------------------------------------------------------- /include/crescent/posix_syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef CRESCENT_POSIX_SYSCALLS_H 2 | #define CRESCENT_POSIX_SYSCALLS_H 3 | 4 | typedef enum CrescentPosixSyscall { 5 | SYS_POSIX_MMAP = 0x1000, 6 | SYS_POSIX_MUNMAP, 7 | SYS_POSIX_MPROTECT, 8 | 9 | SYS_POSIX_SIGPROCMASK, 10 | SYS_POSIX_SIGACTION, 11 | SYS_POSIX_SIGRESTORE, 12 | SYS_POSIX_TGKILL, 13 | SYS_POSIX_KILL, 14 | 15 | SYS_POSIX_PPOLL, 16 | SYS_POSIX_IOCTL, 17 | SYS_POSIX_FCNTL 18 | } CrescentPosixSyscall; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/dev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | clock.cpp 3 | date_time_provider.cpp 4 | dev.cpp 5 | event.cpp 6 | evm.cpp 7 | user_dev.cpp 8 | random.cpp 9 | ) 10 | 11 | if(ARCH STREQUAL "x86_64") 12 | target_sources(crescent PRIVATE pci.cpp) 13 | add_subdirectory(sound) 14 | add_subdirectory(gpu) 15 | endif() 16 | 17 | add_subdirectory(bt) 18 | add_subdirectory(qemu) 19 | 20 | add_subdirectory(fb) 21 | add_subdirectory(net) 22 | add_subdirectory(usb) 23 | -------------------------------------------------------------------------------- /src/dev/usb/hcd/xhci/xhci.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mem/iospace.hpp" 3 | #include "functional.hpp" 4 | #include "utils/driver.hpp" 5 | 6 | struct IrqHandler; 7 | 8 | namespace xhci { 9 | struct GenericOps { 10 | void (*enable_irqs)(void* arg, bool enable); 11 | bool (*install_irq)(void* arg, IrqHandler* handler); 12 | void (*uninstall_irq)(void* arg, IrqHandler* handler); 13 | void* arg; 14 | }; 15 | 16 | InitStatus init(const GenericOps& ops, IoSpace space); 17 | } 18 | -------------------------------------------------------------------------------- /src/dev/bt/bt_dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dev/user_dev.hpp" 4 | #include "hci.hpp" 5 | #include "shared_ptr.hpp" 6 | 7 | class BtDevice : public UserDevice { 8 | public: 9 | BtDevice(kstd::shared_ptr hci, kstd::string_view name) : hci {std::move(hci)} { 10 | this->name = name; 11 | exclusive = true; 12 | } 13 | 14 | int handle_request(const kstd::vector& data, kstd::vector& res, usize max_size) override; 15 | 16 | private: 17 | kstd::shared_ptr hci; 18 | }; 19 | -------------------------------------------------------------------------------- /apps/desktop/src/desktop.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "taskbar.hpp" 4 | 5 | struct Desktop { 6 | explicit Desktop(ui::Context& ctx); 7 | 8 | void draw(); 9 | void handle_mouse(ui::MouseState new_state); 10 | void handle_keyboard(ui::KeyState new_state); 11 | 12 | void add_child(std::unique_ptr window) { 13 | gui.root_windows[0]->add_child(std::move(window)); 14 | } 15 | 16 | ui::Gui gui; 17 | 18 | TaskbarWindow* taskbar; 19 | ui::Window* start_menu {}; 20 | }; 21 | -------------------------------------------------------------------------------- /src/mem/mem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | template 5 | inline T* to_virt(usize phys) { 6 | extern usize HHDM_START; 7 | return reinterpret_cast(phys + HHDM_START); 8 | } 9 | 10 | template 11 | inline usize to_phys(T* ptr) { 12 | extern usize HHDM_START; 13 | return reinterpret_cast(ptr) - HHDM_START; 14 | } 15 | 16 | #define ALIGNUP(value, align) (((value) + ((align) - 1)) & ~((align) - 1)) 17 | #define ALIGNDOWN(value, align) ((value) & ~((align) - 1)) 18 | -------------------------------------------------------------------------------- /cmake/toolchain_x86_64_clang.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 3 | 4 | set(CMAKE_C_COMPILER clang) 5 | set(CMAKE_CXX_COMPILER clang++) 6 | set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld") 7 | set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld") 8 | set(CMAKE_C_COMPILER_TARGET "x86_64-linux-gnu") 9 | set(CMAKE_CXX_COMPILER_TARGET "x86_64-linux-gnu") 10 | set(CMAKE_ASM_COMPILER_TARGET "x86_64-linux-gnu") 11 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 12 | 13 | set(ARCH "x86_64") 14 | -------------------------------------------------------------------------------- /src/std/cstring.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstddef.hpp" 3 | 4 | extern "C" { 5 | void* memcpy(void* __restrict dest, const void* __restrict src, size_t size); 6 | void* memset(void* __restrict dest, int ch, size_t size); 7 | void* memmove(void* __restrict dest, const void* __restrict src, size_t size); 8 | int memcmp(const void* __restrict a, const void* __restrict b, size_t size); 9 | 10 | size_t strlen(const char* str); 11 | } 12 | 13 | #define memcpy __builtin_memcpy 14 | #define memset __builtin_memset 15 | -------------------------------------------------------------------------------- /src/arch/irq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/arch_irq.hpp" 3 | #include "functional.hpp" 4 | #include "double_list.hpp" 5 | 6 | struct IrqHandler { 7 | DoubleListHook hook {}; 8 | kstd::small_function fn {}; 9 | bool can_be_shared {}; 10 | }; 11 | 12 | void register_irq_handler(u32 num, IrqHandler* handler); 13 | void deregister_irq_handler(u32 num, IrqHandler* handler); 14 | 15 | enum class Ipi { 16 | Halt, 17 | Max 18 | }; 19 | 20 | struct Cpu; 21 | 22 | void arch_send_ipi(Ipi ipi, Cpu* cpu); 23 | -------------------------------------------------------------------------------- /src/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstdint.hpp" 3 | #include "cstddef.hpp" 4 | 5 | using u8 = uint8_t; 6 | using u16 = uint16_t; 7 | using u32 = uint32_t; 8 | using u64 = uint64_t; 9 | using usize = uintptr_t; 10 | using i8 = int8_t; 11 | using i16 = int16_t; 12 | using i32 = int32_t; 13 | using i64 = int64_t; 14 | using isize = intptr_t; 15 | 16 | static constexpr usize operator ""_usize(unsigned long long value) { 17 | return value; 18 | } 19 | 20 | #define offset(ptr, type, offset) ((type) ((usize) (ptr) + (offset))) 21 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(APP NAME SRC) 2 | add_executable(${NAME} ${SRC}) 3 | target_compile_options(${NAME} PRIVATE 4 | -Wall -Wextra 5 | -fno-exceptions -fno-rtti 6 | -fno-stack-protector 7 | -fPIE 8 | ) 9 | target_link_options(${NAME} PRIVATE 10 | -Wl,--fatal-warnings 11 | -fPIE -Wl,--export-dynamic 12 | ) 13 | install(TARGETS ${NAME}) 14 | endmacro() 15 | 16 | add_subdirectory(desktop) 17 | add_subdirectory(console) 18 | 19 | if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") 20 | add_subdirectory(evm) 21 | endif() 22 | -------------------------------------------------------------------------------- /src/arch/x86/mem/std_mem.cpp: -------------------------------------------------------------------------------- 1 | #include "cstring.hpp" 2 | 3 | #undef memcpy 4 | #undef memset 5 | 6 | void* memcpy(void* __restrict dest, const void* __restrict src, size_t size) { 7 | void* dest_copy = dest; 8 | asm volatile("rep movsb" : "+D"(dest_copy), "+S"(src), "+c"(size) : : "flags", "memory"); 9 | return dest; 10 | } 11 | 12 | void* memset(void* __restrict dest, int ch, size_t size) { 13 | void* dest_copy = dest; 14 | asm volatile("rep stosb" : "+D"(dest_copy), "+c"(size) : "a"(ch) : "flags", "memory"); 15 | return dest; 16 | } 17 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(acpi) 2 | add_subdirectory(dev) 3 | add_subdirectory(exe) 4 | add_subdirectory(fs) 5 | add_subdirectory(std) 6 | add_subdirectory(mem) 7 | add_subdirectory(sched) 8 | add_subdirectory(sys) 9 | add_subdirectory(utils) 10 | 11 | if(ARCH STREQUAL "x86_64") 12 | add_subdirectory(arch/x86) 13 | elseif(ARCH STREQUAL "aarch64") 14 | add_subdirectory(arch/aarch64) 15 | elseif(ARCH STREQUAL "user") 16 | add_subdirectory(arch/user) 17 | else() 18 | message(FATAL_ERROR "Unsupported architecture ${ARCH}") 19 | endif() 20 | -------------------------------------------------------------------------------- /src/mem/mmio.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.hpp" 4 | 5 | struct MmioMem { 6 | constexpr MmioMem() = default; 7 | constexpr explicit MmioMem(usize size) : virt {nullptr}, phys {0}, size {size} {} 8 | 9 | constexpr MmioMem(MmioMem&& other) : virt {other.virt}, phys {other.phys}, size {other.size} { 10 | other.virt = nullptr; 11 | other.phys = 0; 12 | other.size = 0; 13 | } 14 | 15 | MmioMem& operator==(MmioMem&& other); 16 | 17 | ~MmioMem(); 18 | 19 | [[nodiscard]] bool map(); 20 | 21 | void* virt; 22 | usize phys; 23 | usize size; 24 | }; 25 | -------------------------------------------------------------------------------- /src/sys/event_queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/event.h" 3 | #include "dev/event.hpp" 4 | #include "types.hpp" 5 | #include "utils/spinlock.hpp" 6 | 7 | class EventQueue { 8 | public: 9 | void push(InputEvent event); 10 | bool consume(InputEvent& res); 11 | 12 | bool is_empty(); 13 | 14 | Event produce_event {}; 15 | 16 | private: 17 | static constexpr int MAX_EVENTS = 256; 18 | 19 | InputEvent events[MAX_EVENTS] {}; 20 | Spinlock lock {}; 21 | int producer_ptr {}; 22 | int consumer_ptr {}; 23 | }; 24 | 25 | extern EventQueue GLOBAL_EVENT_QUEUE; 26 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/clock.hpp" 3 | #include "arch/irq.hpp" 4 | 5 | struct Cpu; 6 | 7 | struct ArmTickSource : public TickSource { 8 | constexpr ArmTickSource() : TickSource {"arm tick source", 1} {} 9 | 10 | void init_on_cpu(Cpu* cpu); 11 | 12 | void oneshot(u64 us) override; 13 | void reset() override; 14 | }; 15 | 16 | struct ArmClockSource : public ClockSource { 17 | constexpr ArmClockSource() : ClockSource {"arm clock source", 1} {} 18 | 19 | u64 get_ns() override; 20 | }; 21 | 22 | extern ArmClockSource ARM_CLOCK_SOURCE; 23 | -------------------------------------------------------------------------------- /src/dev/net/ethernet.cpp: -------------------------------------------------------------------------------- 1 | #include "ethernet.hpp" 2 | #include "ipv4.hpp" 3 | #include "arp.hpp" 4 | #include "packet.hpp" 5 | 6 | void ethernet_process_packet(Nic& nic, void* data, usize) { 7 | auto* hdr = static_cast(data); 8 | hdr->deserialize(); 9 | 10 | ReceivedPacket packet {}; 11 | packet.layer0.ethernet = *hdr; 12 | packet.layer1.raw = &hdr[1]; 13 | 14 | if (hdr->ether_type == EtherType::Ipv4) { 15 | ipv4_process_packet(nic, packet); 16 | } 17 | else if (hdr->ether_type == EtherType::Arp) { 18 | arp_process_packet(nic, packet); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/dev/dev.cpp: -------------------------------------------------------------------------------- 1 | #include "dev.hpp" 2 | 3 | void dev_add(Device* device) { 4 | ALL_DEVICES.lock()->push(device); 5 | } 6 | 7 | void dev_remove(Device* device) { 8 | ALL_DEVICES.lock()->remove(device); 9 | } 10 | 11 | void dev_suspend_all() { 12 | auto guard = ALL_DEVICES.lock(); 13 | for (auto& device : *guard) { 14 | device.suspend(); 15 | } 16 | } 17 | 18 | void dev_resume_all() { 19 | auto guard = ALL_DEVICES.lock(); 20 | for (auto& device : *guard) { 21 | device.resume(); 22 | } 23 | } 24 | 25 | constinit IrqSpinlock> ALL_DEVICES; 26 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/tss.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct Tss { 5 | u32 reserved1; 6 | u32 rsp0_low; 7 | u32 rsp0_high; 8 | u32 rsp1_low; 9 | u32 rsp1_high; 10 | u32 rsp2_low; 11 | u32 rsp2_high; 12 | u32 reserved2[2]; 13 | u32 ist1_low; 14 | u32 ist1_high; 15 | u32 ist2_low; 16 | u32 ist2_high; 17 | u32 ist3_low; 18 | u32 ist3_high; 19 | u32 ist4_low; 20 | u32 ist4_high; 21 | u32 ist5_low; 22 | u32 ist5_high; 23 | u32 ist6_low; 24 | u32 ist6_high; 25 | u32 ist7_low; 26 | u32 ist7_high; 27 | u32 reserved3[2]; 28 | u16 reserved4; 29 | u16 iopb; 30 | }; 31 | -------------------------------------------------------------------------------- /src/dev/net/checksum.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct Checksum { 5 | inline void add(u16 value) { 6 | sum += value; 7 | } 8 | 9 | inline void add(const void* data, u32 size) { 10 | if (size % 2) { 11 | --size; 12 | add(static_cast(data)[size]); 13 | } 14 | 15 | for (u32 i = 0; i < size / 2; ++i) { 16 | sum += static_cast(data)[i]; 17 | } 18 | } 19 | 20 | [[nodiscard]] inline u16 get() const { 21 | u32 res = (sum & 0xFFFF) + (sum >> 16); 22 | res = (res & 0xFFFF) + (res >> 16); 23 | return ~res; 24 | } 25 | 26 | private: 27 | u32 sum = 0; 28 | }; 29 | -------------------------------------------------------------------------------- /src/mem/unique_phys.cpp: -------------------------------------------------------------------------------- 1 | #include "unique_phys.hpp" 2 | #include "pmalloc.hpp" 3 | 4 | UniquePhysical& UniquePhysical::operator=(UniquePhysical&& other) { 5 | if (base) { 6 | pfree(base, count); 7 | } 8 | base = other.base; 9 | count = other.count; 10 | other.base = 0; 11 | other.count = 0; 12 | return *this; 13 | } 14 | 15 | UniquePhysical::~UniquePhysical() { 16 | if (base) { 17 | pfree(base, count); 18 | } 19 | } 20 | 21 | kstd::optional UniquePhysical::create(usize count) { 22 | auto base = pmalloc(count); 23 | if (!base) { 24 | return {}; 25 | } 26 | return UniquePhysical {base, count}; 27 | } 28 | -------------------------------------------------------------------------------- /libs/libcxx/include/new: -------------------------------------------------------------------------------- 1 | #ifndef _NEW_H 2 | #define _NEW_H 3 | 4 | #include 5 | #include 6 | 7 | constexpr void* operator new(size_t, void* __ptr) { 8 | return __ptr; 9 | } 10 | 11 | inline void* operator new(size_t __size) { 12 | return malloc(__size); 13 | } 14 | 15 | inline void operator delete(void* __ptr) { 16 | free(__ptr); 17 | } 18 | 19 | inline void operator delete(void* __ptr, size_t) { 20 | free(__ptr); 21 | } 22 | 23 | namespace std { 24 | template 25 | [[nodiscard]] constexpr __T* launder(__T* __ptr) noexcept { 26 | return __builtin_launder(__ptr); 27 | } 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/dev/net/ethernet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mac.hpp" 3 | #include "bit.hpp" 4 | 5 | struct Nic; 6 | 7 | void ethernet_process_packet(Nic& nic, void* data, usize size); 8 | 9 | enum class EtherType : u16 { 10 | Ipv4 = 0x800, 11 | Arp = 0x806, 12 | Ipv6 = 0x86DD 13 | }; 14 | 15 | struct EthernetHeader { 16 | Mac dest; 17 | Mac src; 18 | EtherType ether_type; 19 | 20 | void serialize() { 21 | ether_type = static_cast(kstd::to_be(static_cast(ether_type))); 22 | } 23 | 24 | void deserialize() { 25 | ether_type = static_cast(kstd::to_ne_from_be(static_cast(ether_type))); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /cmake/toolchain_aarch64_clang.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR "aarch64") 3 | 4 | set(CMAKE_C_COMPILER clang) 5 | set(CMAKE_CXX_COMPILER clang++) 6 | set(CMAKE_OBJCOPY llvm-objcopy) 7 | set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld") 8 | set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld") 9 | set(CMAKE_C_FLAGS "-mno-outline-atomics") 10 | set(CMAKE_CXX_FLAGS "-mno-outline-atomics") 11 | set(CMAKE_C_COMPILER_TARGET "aarch64-linux-gnu") 12 | set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu") 13 | set(CMAKE_ASM_COMPILER_TARGET "aarch64-linux-gnu") 14 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 15 | 16 | set(ARCH "aarch64") 17 | -------------------------------------------------------------------------------- /src/dev/fb/fb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "mem/iospace.hpp" 4 | #include "manually_init.hpp" 5 | #include "stdio.hpp" 6 | 7 | struct Framebuffer final : LogSink { 8 | Framebuffer(usize phys, u32 width, u32 height, usize pitch, u32 bpp); 9 | 10 | void write(kstd::string_view str) override; 11 | void set_color(Color color) override; 12 | void clear(); 13 | 14 | usize phys; 15 | IoSpace space; 16 | usize pitch; 17 | u32 width; 18 | u32 height; 19 | u32 bpp; 20 | u32 fg_color {0x00FF00}; 21 | 22 | u32 column = 0; 23 | u32 row = 0; 24 | u32 scale = 1; 25 | }; 26 | 27 | extern ManuallyInit BOOT_FB; 28 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/psci.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | enum class PsciError : i32 { 5 | Success = 0, 6 | NotSupported = -1, 7 | InvalidParameters = -2, 8 | Denied = -3, 9 | AlreadyOn = -4, 10 | OnPending = -5, 11 | InternalFailure = -6, 12 | NotPresent = -7, 13 | Disabled = -8, 14 | InvalidAddress = -9 15 | }; 16 | 17 | u64 psci_call(u64 a0); 18 | u64 psci_call(u64 a0, u64 a1); 19 | u64 psci_call(u64 a0, u64 a1, u64 a2); 20 | u64 psci_call(u64 a0, u64 a1, u64 a2, u64 a3); 21 | 22 | u32 psci_version(); 23 | i32 psci_cpu_on(u64 target_mpidr, u64 entry_phys, u64 ctx); 24 | void psci_system_off(); 25 | void psci_system_reset(); 26 | -------------------------------------------------------------------------------- /src/dev/net/nic/nic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/event.hpp" 3 | #include "dev/net/mac.hpp" 4 | #include "manually_destroy.hpp" 5 | #include "shared_ptr.hpp" 6 | #include "vector.hpp" 7 | 8 | struct Nic { 9 | virtual ~Nic() = default; 10 | 11 | virtual void send(const void* data, u32 size) = 0; 12 | 13 | void wait_for_ip(); 14 | bool wait_for_ip_with_timeout(usize seconds); 15 | 16 | Mac mac {}; 17 | u32 ip {}; 18 | u32 subnet_mask {}; 19 | u32 gateway_ip {}; 20 | Spinlock lock {}; 21 | Event ip_available_event {}; 22 | }; 23 | 24 | void nics_wait_ready(); 25 | 26 | extern ManuallyDestroy>>> NICS; 27 | -------------------------------------------------------------------------------- /libs/libc/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDIO_H 2 | #define _STDIO_H 3 | 4 | #include "bits/utils.h" 5 | #include 6 | 7 | __begin 8 | 9 | typedef struct FILE FILE; 10 | 11 | extern FILE* stdin; 12 | extern FILE* stdout; 13 | extern FILE* stderr; 14 | 15 | int puts(const char* __str); 16 | __attribute__((__format__(__printf__, 1, 2))) int printf(const char* __restrict fmt, ...); 17 | __attribute__((__format__(__printf__, 2, 3))) int fprintf(FILE* __restrict __file, const char* __restrict __fmt, ...); 18 | __attribute__((__format__(__printf__, 2, 0))) int vfprintf(FILE* __restrict __file, const char* __restrict __fmt, va_list __ap); 19 | 20 | __end 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/arch/x86/dev/lapic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "dev/clock.hpp" 4 | 5 | struct LapicTickSource final : TickSource { 6 | constexpr LapicTickSource(u64 max_us, u64 ticks_in_us) : TickSource {"lapic", max_us}, ticks_in_us {ticks_in_us} {} 7 | 8 | void oneshot(u64 us) override; 9 | void reset() override; 10 | 11 | static bool on_irq(struct IrqFrame*); 12 | 13 | u64 ticks_in_us; 14 | }; 15 | 16 | struct Cpu; 17 | 18 | void lapic_first_init(); 19 | void lapic_init(Cpu* cpu, bool initial); 20 | void lapic_eoi(); 21 | 22 | void lapic_ipi(u8 vec, u8 dest); 23 | void lapic_ipi_all(u8 vec); 24 | 25 | void lapic_boot_ap(u8 lapic_id, u32 boot_addr); 26 | -------------------------------------------------------------------------------- /libs/libui/include/ui/gui.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "window.hpp" 3 | #include "mouse.hpp" 4 | 5 | namespace ui { 6 | struct Gui { 7 | explicit Gui(Context& ctx, uint32_t width, uint32_t height); 8 | 9 | void draw(); 10 | void handle_mouse(MouseState new_state); 11 | void handle_keyboard(KeyState new_state); 12 | 13 | void destroy_window(Window* window); 14 | 15 | std::vector> root_windows; 16 | Context& ctx; 17 | MouseState mouse_state {}; 18 | uint32_t drag_x_off {}; 19 | uint32_t drag_y_off {}; 20 | Window* dragging {}; 21 | Window* last_mouse_over {}; 22 | bool key_states[SCANCODE_MAX] {}; 23 | bool draw_cursor {true}; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/sched/cpu_set.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "config.hpp" 4 | #include "cstring.hpp" 5 | 6 | struct CpuSet { 7 | inline void set(u32 num) { 8 | assert(num < CONFIG_MAX_CPUS); 9 | inner[num / 32] |= 1U << (num % 32); 10 | } 11 | 12 | inline void clear(u32 num) { 13 | assert(num < CONFIG_MAX_CPUS); 14 | inner[num / 32] &= ~(1U << (num % 32)); 15 | } 16 | 17 | inline bool test(u32 num) { 18 | return inner[num / 32] & 1U << (num % 32); 19 | } 20 | 21 | inline void clear_all() { 22 | memset(inner, 0, sizeof(inner)); 23 | } 24 | 25 | inline void set_all() { 26 | memset(inner, 0xFF, sizeof(inner)); 27 | } 28 | 29 | u32 inner[(CONFIG_MAX_CPUS + 31) & ~31]; 30 | }; 31 | -------------------------------------------------------------------------------- /src/mem/unique_phys.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | 5 | struct UniquePhysical { 6 | constexpr UniquePhysical(usize base, usize count) : base {base}, count {count} {} 7 | 8 | static kstd::optional create(usize count); 9 | 10 | constexpr UniquePhysical(UniquePhysical&& other) { 11 | base = other.base; 12 | count = other.count; 13 | other.base = 0; 14 | other.count = 0; 15 | } 16 | 17 | UniquePhysical(const UniquePhysical&) = delete; 18 | constexpr UniquePhysical& operator=(const UniquePhysical&) = delete; 19 | 20 | UniquePhysical& operator=(UniquePhysical&& other); 21 | 22 | ~UniquePhysical(); 23 | 24 | usize base; 25 | usize count; 26 | }; 27 | -------------------------------------------------------------------------------- /src/arch/x86/mod.cpp: -------------------------------------------------------------------------------- 1 | #include "mod.hpp" 2 | #include "loader/limine.h" 3 | 4 | static volatile limine_module_request MOD_REQUEST { 5 | .id = LIMINE_MODULE_REQUEST, 6 | .revision = 0, 7 | .response = nullptr, 8 | .internal_module_count = 0, 9 | .internal_modules = nullptr 10 | }; 11 | 12 | bool x86_get_module(Module& module, kstd::string_view name) { 13 | if (!MOD_REQUEST.response) { 14 | return false; 15 | } 16 | 17 | for (usize i = 0; i < MOD_REQUEST.response->module_count; ++i) { 18 | auto mod = MOD_REQUEST.response->modules[i]; 19 | if (mod->cmdline == name) { 20 | module = { 21 | .data = mod->address, 22 | .size = mod->size 23 | }; 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/gic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | enum class TriggerMode { 5 | None, 6 | Edge, 7 | Level 8 | }; 9 | 10 | struct Gic { 11 | virtual ~Gic() = default; 12 | 13 | virtual void mask_irq(u32 irq, bool mask) = 0; 14 | virtual void set_mode(u32 irq, TriggerMode mode) = 0; 15 | virtual void set_priority(u32 irq, u8 priority) = 0; 16 | virtual void set_affinity(u32 irq, u32 affinity) = 0; 17 | 18 | virtual u32 ack() = 0; 19 | virtual void eoi(u32 irq) = 0; 20 | 21 | virtual void send_ipi(u32 affinity, u8 id) = 0; 22 | virtual void send_ipi_to_others(u8 id) = 0; 23 | 24 | u32 num_irqs {}; 25 | }; 26 | 27 | void gic_init_on_cpu(); 28 | 29 | extern Gic* GIC; 30 | extern u32 GIC_VERSION; 31 | -------------------------------------------------------------------------------- /src/fs/pipe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vfs.hpp" 3 | #include "vector.hpp" 4 | #include "optional.hpp" 5 | #include "dev/event.hpp" 6 | #include "ring_buffer.hpp" 7 | 8 | class PipeVNode : public VNode { 9 | public: 10 | static kstd::optional> create(usize max_size, FileFlags read_flags, FileFlags write_flags); 11 | 12 | FsStatus read(void* data, usize& size, usize offset) override; 13 | FsStatus write(const void* data, usize& size, usize offset) override; 14 | FsStatus stat(FsStat& data) override; 15 | 16 | private: 17 | PipeVNode(kstd::shared_ptr> buffer, FileFlags flags, bool reading); 18 | 19 | kstd::shared_ptr> buffer; 20 | bool reading = false; 21 | }; 22 | -------------------------------------------------------------------------------- /src/mem/malloc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "double_list.hpp" 4 | 5 | class Allocator { 6 | public: 7 | void* alloc(usize size); 8 | void free(void* ptr, usize size); 9 | 10 | // 16 32 64 128 256 512 1024 2048 11 | static constexpr usize FREELIST_COUNT = 8; 12 | 13 | private: 14 | struct Node { 15 | DoubleListHook hook; 16 | }; 17 | static_assert(sizeof(Node) <= 16); 18 | 19 | struct Header { 20 | DoubleListHook hook; 21 | DoubleList list {}; 22 | usize count {}; 23 | usize max {}; 24 | }; 25 | 26 | DoubleList freelists[FREELIST_COUNT] {}; 27 | 28 | static constexpr usize size_to_index(usize size); 29 | }; 30 | 31 | extern Allocator ALLOCATOR; 32 | -------------------------------------------------------------------------------- /src/std/new.cpp: -------------------------------------------------------------------------------- 1 | #include "assert.hpp" 2 | #include "mem/malloc.hpp" 3 | #include "stdio.hpp" 4 | 5 | void* operator new(size_t size) { 6 | auto ret = ALLOCATOR.alloc(size); 7 | assert(ret); 8 | return ret; 9 | } 10 | 11 | void* operator new[](size_t size) { 12 | auto ret = ALLOCATOR.alloc(size); 13 | assert(ret); 14 | return ret; 15 | } 16 | 17 | void operator delete(void* ptr, size_t size) { 18 | ALLOCATOR.free(ptr, size); 19 | } 20 | 21 | void operator delete(void*) { 22 | panic("unsized operator delete called"); 23 | } 24 | 25 | void operator delete[](void*) { 26 | panic("unsized array operator delete called"); 27 | } 28 | 29 | void operator delete[](void*, size_t) { 30 | panic("sized array operator delete called"); 31 | } 32 | -------------------------------------------------------------------------------- /src/std/inttypes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "string_view.hpp" 3 | 4 | namespace kstd { 5 | namespace __detail { 6 | constexpr char to_lower(char c) { 7 | if (c >= 'A' && c <= 'Z') { 8 | return static_cast(c | 1 << 5); 9 | } 10 | else { 11 | return c; 12 | } 13 | } 14 | } 15 | 16 | template 17 | constexpr T to_integer(kstd::string_view str, int base) { 18 | static constexpr char CHARS[] = "0123456789abcdef"; 19 | 20 | T value {}; 21 | for (auto c : str) { 22 | c = __detail::to_lower(c); 23 | if (c < '0' || c > CHARS[base - 1]) { 24 | return value; 25 | } 26 | value *= base; 27 | value += c <= '9' ? (c - '0') : (c - 'a' + 10); 28 | } 29 | 30 | return value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/arch_syscalls.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "arch/aarch64/interrupts/exceptions.hpp" 4 | 5 | struct SyscallFrame : ExceptionFrame { 6 | constexpr u64* num() { 7 | return &x[0]; 8 | } 9 | 10 | constexpr u64* ret() { 11 | return &x[0]; 12 | } 13 | 14 | constexpr u64* error() { 15 | return &x[1]; 16 | } 17 | 18 | constexpr u64* arg0() { 19 | return &x[1]; 20 | } 21 | 22 | constexpr u64* arg1() { 23 | return &x[2]; 24 | } 25 | 26 | constexpr u64* arg2() { 27 | return &x[3]; 28 | } 29 | 30 | constexpr u64* arg3() { 31 | return &x[4]; 32 | } 33 | 34 | constexpr u64* arg4() { 35 | return &x[5]; 36 | } 37 | 38 | constexpr u64* arg5() { 39 | return &x[6]; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /src/dev/net/udp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "bit.hpp" 4 | #include "shared_ptr.hpp" 5 | #include "sys/socket.hpp" 6 | 7 | struct UdpHeader { 8 | u16 src_port; 9 | u16 dest_port; 10 | u16 length; 11 | u16 checksum; 12 | 13 | void serialize() { 14 | src_port = kstd::to_be(src_port); 15 | dest_port = kstd::to_be(dest_port); 16 | length = kstd::to_be(length); 17 | } 18 | 19 | void deserialize() { 20 | src_port = kstd::to_ne_from_be(src_port); 21 | dest_port = kstd::to_ne_from_be(dest_port); 22 | length = kstd::to_ne_from_be(length); 23 | } 24 | }; 25 | 26 | struct Nic; 27 | struct ReceivedPacket; 28 | 29 | kstd::shared_ptr udp_socket_create(int flags); 30 | void udp_process_packet(Nic& nic, ReceivedPacket& packet); 31 | -------------------------------------------------------------------------------- /src/std/utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "type_traits.hpp" 3 | 4 | namespace kstd { 5 | [[noreturn]] inline void unreachable() { 6 | __builtin_unreachable(); 7 | } 8 | 9 | template 10 | struct pair { 11 | T1 first; 12 | T2 second; 13 | }; 14 | } 15 | 16 | namespace std { 17 | template 18 | constexpr kstd::remove_reference_t&& move(T&& value) { 19 | return static_cast&&>(value); 20 | } 21 | 22 | template 23 | constexpr T&& forward(kstd::remove_reference_t& value) { 24 | return static_cast(value); 25 | } 26 | 27 | template 28 | constexpr T&& forward(kstd::remove_reference_t&& value) { 29 | return static_cast(value); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/misc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | static inline void arch_hlt() { 5 | asm volatile("wfi"); 6 | } 7 | 8 | static inline bool arch_enable_irqs(bool enable) { 9 | u64 old; 10 | asm volatile("mrs %0, daif" : "=r"(old)); 11 | 12 | // bit0 == fiq, bit1 == irq, bit2 == SError, bit3 == Debug 13 | if (enable) { 14 | asm volatile("msr daifclr, #0b10"); 15 | } 16 | else { 17 | asm volatile("msr daifset, #0b10"); 18 | } 19 | 20 | return !(old & 1 << 7); 21 | } 22 | 23 | static inline void mem_barrier() { 24 | asm volatile("dmb ish"); 25 | } 26 | 27 | static inline void write_barrier() { 28 | asm volatile("dmb ishst" : : : "memory"); 29 | } 30 | 31 | static inline void read_barrier() { 32 | asm volatile("dmb ishld"); 33 | } 34 | -------------------------------------------------------------------------------- /libs/libui/include/ui/button.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "window.hpp" 3 | 4 | namespace ui { 5 | class ButtonWindow : public Window { 6 | public: 7 | ButtonWindow(); 8 | 9 | void draw(Context& ctx) override; 10 | bool handle_mouse(Context& ctx, const MouseState& old_state, const MouseState& new_state) override; 11 | void on_mouse_leave(Context& ctx, const MouseState& new_state) override; 12 | 13 | bool handle_keyboard(Context& ctx, const KeyState& old_state, const KeyState& new_state) override { 14 | return false; 15 | } 16 | 17 | using Callback = void (*)(void* arg); 18 | Callback callback {}; 19 | void* arg {}; 20 | uint32_t active_color {0xFF0000}; 21 | uint32_t inactive_color {0x00FFFF}; 22 | 23 | private: 24 | bool prev_mouse_state {}; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /CMakeOptions.cmake: -------------------------------------------------------------------------------- 1 | set(CONFIG_MAX_CPUS 24 CACHE STRING "Maximum number of cpus to support") 2 | option(CONFIG_TRACING "Enable verbose trace logging" OFF) 3 | 4 | option(BUILD_APPS "Build apps and libraries" ON) 5 | 6 | if(ARCH STREQUAL "x86_64") 7 | set(CONFIG_PCI ON CACHE BOOL "Enable pci support") 8 | else() 9 | set(CONFIG_PCI OFF) 10 | endif() 11 | 12 | if(ARCH STREQUAL "aarch64") 13 | set(CONFIG_DTB ON CACHE BOOL "Enable dtb support") 14 | else() 15 | set(CONFIG_DTB OFF) 16 | endif() 17 | 18 | option(CONFIG_USB_XHCI "Enable xhci usb support" ON) 19 | if(CONFIG_PCI AND CONFIG_USB_XHCI) 20 | option(CONFIG_XHCI_PCI "Enable xhci pci support" ON) 21 | endif() 22 | 23 | configure_file(config.hpp.in config.hpp @ONLY) 24 | target_include_directories(crescent PRIVATE "${CMAKE_BINARY_DIR}") 25 | -------------------------------------------------------------------------------- /src/std/initializer_list.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstddef.hpp" 3 | 4 | namespace std { 5 | template 6 | class initializer_list { 7 | public: 8 | using value_type = T; 9 | using reference = const T&; 10 | using const_reference = const T&; 11 | using size_type = size_t; 12 | 13 | using iterator = const T*; 14 | using const_iterator = const T*; 15 | 16 | constexpr initializer_list() noexcept = default; 17 | 18 | [[nodiscard]] constexpr size_t size() const noexcept { 19 | return _len; 20 | } 21 | 22 | constexpr const T* begin() const noexcept { 23 | return _start; 24 | } 25 | 26 | constexpr const T* end() const noexcept { 27 | return _start + _len; 28 | } 29 | 30 | private: 31 | const T* _start {}; 32 | size_t _len {}; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/std/manually_destroy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utility.hpp" 3 | #include "new.hpp" 4 | #include "assert.hpp" 5 | 6 | template 7 | class ManuallyDestroy { 8 | public: 9 | ManuallyDestroy() { 10 | new (storage.data) T {}; 11 | } 12 | 13 | ManuallyDestroy(T&& value) { // NOLINT(*-explicit-constructor) 14 | new (storage.data) T {std::move(value)}; 15 | } 16 | 17 | void destroy() { 18 | kstd::launder(reinterpret_cast(storage.data))->~T(); 19 | } 20 | 21 | T* operator->() { 22 | return kstd::launder(reinterpret_cast(storage.data)); 23 | } 24 | 25 | T& operator*() { 26 | return *kstd::launder(reinterpret_cast(storage.data)); 27 | } 28 | 29 | private: 30 | struct alignas(T) Storage { 31 | char data[sizeof(T)]; 32 | }; 33 | 34 | Storage storage; 35 | }; 36 | -------------------------------------------------------------------------------- /libs/libc/include/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef _ELF_H 2 | #define _ELF_H 3 | 4 | #include 5 | 6 | typedef uint64_t Elf64_Xword; 7 | typedef int64_t Elf64_Sxword; 8 | typedef uint64_t Elf64_Addr; 9 | 10 | typedef struct { 11 | Elf64_Sxword d_tag; 12 | union { 13 | Elf64_Xword d_val; 14 | Elf64_Addr d_ptr; 15 | } d_un; 16 | } Elf64_Dyn; 17 | 18 | #define DT_NULL 0 19 | #define DT_RELA 7 20 | #define DT_RELASZ 8 21 | 22 | typedef struct { 23 | Elf64_Addr r_offset; 24 | Elf64_Xword r_info; 25 | Elf64_Xword r_addend; 26 | } Elf64_Rela; 27 | 28 | #define ELF64_R_SYM(info) ((info) >> 32) 29 | #define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) 30 | #define ELF64_R_INFO(sym, type) (((Elf64_Xword) (sym) << 32) | (type)) 31 | 32 | #define R_X86_64_RELATIVE 8 33 | 34 | #define R_AARCH64_RELATIVE 1027 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/dev/usb/hcd/xhci/transfer_ring.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "transfer_ring.hpp" 3 | #include "dev/usb/packet.hpp" 4 | #include "dev/event.hpp" 5 | #include "rb_tree.hpp" 6 | #include "compare.hpp" 7 | #include "trb.hpp" 8 | 9 | namespace xhci { 10 | struct TransferRing { 11 | TransferRing(); 12 | 13 | ~TransferRing(); 14 | 15 | void reset(); 16 | 17 | bool add_trb(TransferTrb trb); 18 | 19 | usize phys; 20 | TransferTrb* trbs; 21 | u32 ring_ptr {}; 22 | u32 max_packet_size {}; 23 | u32 used_count {}; 24 | bool ring_c {true}; 25 | 26 | void control(const usb::setup::Packet* setup); 27 | bool normal(const usb::normal::Packet* packet); 28 | usize normal_large(const usb::normal::LargePacket* packet); 29 | 30 | RbTree events {}; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/dev/net/ipv4.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "ip.hpp" 4 | #include "bit.hpp" 5 | 6 | struct Ipv4Header { 7 | u8 ihl_version; 8 | u8 ecn_dscp; 9 | u16 total_len; 10 | u16 ident; 11 | u16 frag_flags; 12 | u8 ttl; 13 | IpProtocol protocol; 14 | u16 hdr_checksum; 15 | u32 src_addr; 16 | u32 dest_addr; 17 | 18 | void serialize() { 19 | total_len = kstd::to_be(total_len); 20 | ident = kstd::to_be(ident); 21 | frag_flags = kstd::to_be(frag_flags); 22 | } 23 | 24 | void deserialize() { 25 | total_len = kstd::to_ne_from_be(total_len); 26 | ident = kstd::to_ne_from_be(ident); 27 | frag_flags = kstd::to_ne_from_be(frag_flags); 28 | } 29 | 30 | void update_checksum(); 31 | }; 32 | 33 | struct Nic; 34 | struct ReceivedPacket; 35 | 36 | void ipv4_process_packet(Nic& nic, ReceivedPacket& packet); 37 | -------------------------------------------------------------------------------- /src/std/array.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstddef.hpp" 3 | #include "initializer_list.hpp" 4 | 5 | namespace kstd { 6 | template 7 | struct array { 8 | constexpr T* begin() { 9 | return data; 10 | } 11 | constexpr const T* begin() const { 12 | return data; 13 | } 14 | 15 | constexpr T* end() { 16 | return data; 17 | } 18 | constexpr const T* end() const { 19 | return data; 20 | } 21 | 22 | [[nodiscard]] constexpr size_t size() const { 23 | return N; 24 | } 25 | 26 | constexpr T& operator[](size_t index) { 27 | return data[index]; 28 | } 29 | constexpr const T& operator[](size_t index) const { 30 | return data[index]; 31 | } 32 | 33 | T data[N]; 34 | }; 35 | 36 | template 37 | array(T, U...) -> array; 38 | } 39 | -------------------------------------------------------------------------------- /src/dev/net/arp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "bit.hpp" 4 | #include "mac.hpp" 5 | #include "optional.hpp" 6 | 7 | struct [[gnu::packed]] ArpHeader { 8 | u16 htype; 9 | u16 ptype; 10 | u8 hlen; 11 | u8 plen; 12 | u16 oper; 13 | Mac sender_hw_addr; 14 | u32 sender_protocol_addr; 15 | Mac target_hw_addr; 16 | u32 target_protocol_addr; 17 | 18 | inline void serialize() { 19 | htype = kstd::to_be(htype); 20 | ptype = kstd::to_be(ptype); 21 | oper = kstd::to_be(oper); 22 | } 23 | 24 | inline void deserialize() { 25 | htype = kstd::to_ne_from_be(htype); 26 | ptype = kstd::to_ne_from_be(ptype); 27 | oper = kstd::to_ne_from_be(oper); 28 | } 29 | }; 30 | 31 | struct Nic; 32 | struct ReceivedPacket; 33 | 34 | void arp_process_packet(Nic& nic, ReceivedPacket& packet); 35 | kstd::optional arp_get_mac(u32 ip); 36 | -------------------------------------------------------------------------------- /libs/libcxx/include/initializer_list: -------------------------------------------------------------------------------- 1 | #ifndef _INITIALIZER_LIST_H 2 | #define _INITIALIZER_LIST_H 3 | 4 | #include 5 | 6 | namespace std { 7 | template 8 | class initializer_list { 9 | public: 10 | constexpr initializer_list() = default; 11 | 12 | using value_type = __T; 13 | using reference = const __T&; 14 | using const_reference = const __T&; 15 | using size_type = std::size_t; 16 | using iterator = const __T*; 17 | using const_iterator = const __T*; 18 | 19 | constexpr size_type size() const noexcept { 20 | return _size; 21 | } 22 | 23 | constexpr const_iterator begin() const noexcept { 24 | return _ptr; 25 | } 26 | 27 | constexpr const_iterator end() const noexcept { 28 | return _ptr + _size; 29 | } 30 | 31 | private: 32 | const __T* _ptr; 33 | size_t _size; 34 | }; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/mem/vspace.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "rb_tree.hpp" 4 | #include "vmem.hpp" 5 | #include "compare.hpp" 6 | #include "arch/paging.hpp" 7 | 8 | class VirtualSpace { 9 | public: 10 | void init(usize base, usize size); 11 | void destroy(); 12 | 13 | void* alloc(usize size); 14 | void free(void* ptr, usize size); 15 | 16 | void* alloc_backed(usize size, PageFlags flags, CacheMode cache_mode = CacheMode::WriteBack); 17 | void free_backed(void* ptr, usize size); 18 | 19 | private: 20 | struct Region { 21 | RbTreeHook hook {}; 22 | usize base {}; 23 | usize size {}; 24 | 25 | constexpr int operator<=>(const Region& other) const { 26 | return kstd::threeway(base, other.base); 27 | } 28 | }; 29 | 30 | VMem vmem; 31 | Spinlock> regions; 32 | }; 33 | 34 | extern VirtualSpace KERNEL_VSPACE; 35 | -------------------------------------------------------------------------------- /libs/libui/include/ui/text.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "window.hpp" 3 | #include "libtext/libtext.hpp" 4 | #include 5 | #include 6 | 7 | namespace ui { 8 | struct TextWindow : public Window { 9 | TextWindow(); 10 | 11 | void draw(Context& ctx) override; 12 | 13 | bool handle_mouse(Context&, const MouseState&, const MouseState&) override { 14 | return false; 15 | } 16 | 17 | void on_mouse_enter(Context&, const MouseState&) override {} 18 | 19 | void on_mouse_leave(Context&, const MouseState&) override {} 20 | 21 | bool handle_keyboard(Context&, const KeyState&, const KeyState&) override { 22 | return false; 23 | } 24 | 25 | uint32_t text_color = 0xFFFFFF; 26 | std::string text; 27 | 28 | private: 29 | libtext::Context text_ctx; 30 | std::unordered_map glyph_cache {}; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/arch_thread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "sched/sysv.hpp" 4 | 5 | struct Process; 6 | 7 | struct ArchThread { 8 | constexpr ArchThread() = default; 9 | ArchThread(void (*fn)(void*), void* arg, Process* process); 10 | ArchThread(const SysvInfo& sysv, Process* process); 11 | ~ArchThread(); 12 | 13 | u8* sp {}; 14 | u8* syscall_sp {}; 15 | usize handler_ip {}; 16 | usize handler_sp {}; 17 | usize* kernel_stack_base {}; 18 | u8* user_stack_base {}; 19 | u8* simd {}; 20 | usize tpidr_el0 {}; 21 | }; 22 | 23 | // used in arch_sched.cpp 24 | static_assert(offsetof(ArchThread, sp) == 0); 25 | // used in exceptions.S 26 | static_assert(offsetof(ArchThread, syscall_sp) == 8); 27 | // used in user.S 28 | static_assert(offsetof(ArchThread, handler_ip) == 16); 29 | static_assert(offsetof(ArchThread, handler_sp) == 24); 30 | -------------------------------------------------------------------------------- /src/dev/evm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "expected.hpp" 3 | #include "mem/pmalloc.hpp" 4 | #include "memory.hpp" 5 | #include "shared_ptr.hpp" 6 | #include "utils/flags_enum.hpp" 7 | #include "crescent/evm.h" 8 | 9 | namespace evm { 10 | struct VirtualCpu { 11 | virtual ~VirtualCpu() = default; 12 | 13 | virtual int run() = 0; 14 | virtual int write_state(EvmStateBits changed_state) = 0; 15 | virtual int read_state(EvmStateBits wanted_state) = 0; 16 | virtual int trigger_irq(const EvmIrqInfo& info) = 0; 17 | 18 | u64 state_phys {}; 19 | EvmGuestState* state {}; 20 | }; 21 | 22 | struct Evm { 23 | virtual ~Evm(); 24 | 25 | virtual int map_page(u64 guest, u64 host) = 0; 26 | virtual void unmap_page(u64 guest) = 0; 27 | 28 | virtual kstd::expected, int> create_vcpu() = 0; 29 | 30 | DoubleList pages {}; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/fs/vfs.cpp: -------------------------------------------------------------------------------- 1 | #include "vfs.hpp" 2 | 3 | kstd::shared_ptr vfs_lookup(kstd::shared_ptr start, kstd::string_view path) { 4 | if (path.is_empty()) { 5 | return nullptr; 6 | } 7 | 8 | assert(start); 9 | auto node = std::move(start); 10 | 11 | size_t i = 0; 12 | while (path[i] == '/') { 13 | ++i; 14 | if (i == path.size()) { 15 | return node; 16 | } 17 | } 18 | 19 | while (i < path.size()) { 20 | auto end = path.find('/', i); 21 | if (end == kstd::string_view::npos) { 22 | return node->lookup(path.substr(i, end)); 23 | } 24 | else { 25 | auto slice = path.substr(i, (end - i)); 26 | auto next = node->lookup(slice); 27 | if (!next) { 28 | return nullptr; 29 | } 30 | node = std::move(next); 31 | i = end + 1; 32 | } 33 | 34 | while (i < path.size() && path[i] == '/') { 35 | ++i; 36 | } 37 | } 38 | 39 | return node; 40 | } 41 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/arch_syscalls.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | struct SyscallFrame { 5 | u64 rax; 6 | u64 rbx; 7 | u64 rcx; 8 | u64 rdx; 9 | u64 rdi; 10 | u64 rsi; 11 | u64 rbp; 12 | u64 r8; 13 | u64 r9; 14 | u64 r10; 15 | u64 r11; 16 | u64 r12; 17 | u64 r13; 18 | u64 r14; 19 | u64 r15; 20 | 21 | constexpr u64* num() { 22 | return &rdi; 23 | } 24 | 25 | constexpr u64* ret() { 26 | return &rax; 27 | } 28 | 29 | constexpr u64* error() { 30 | return &rdi; 31 | } 32 | 33 | constexpr u64* arg0() { 34 | return &rsi; 35 | } 36 | 37 | constexpr u64* arg1() { 38 | return &rdx; 39 | } 40 | 41 | constexpr u64* arg2() { 42 | return &rax; 43 | } 44 | 45 | constexpr u64* arg3() { 46 | return &r8; 47 | } 48 | 49 | constexpr u64* arg4() { 50 | return &r9; 51 | } 52 | 53 | constexpr u64* arg5() { 54 | return &r10; 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/dev/sound/sound_dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/devlink.h" 3 | #include "dev/user_dev.hpp" 4 | #include "types.hpp" 5 | 6 | struct SoundDeviceInfo { 7 | usize output_count; 8 | }; 9 | 10 | struct SoundDevice : public UserDevice { 11 | SoundDevice() { 12 | name = "sound"; 13 | } 14 | 15 | int handle_request(const kstd::vector& data, kstd::vector& res, usize max_size) final; 16 | 17 | virtual int get_info(SoundDeviceInfo& res) = 0; 18 | virtual int get_output_info(usize index, SoundOutputInfo& res) = 0; 19 | 20 | virtual int set_active_output(void* id) = 0; 21 | virtual int set_output_params(SoundOutputParams& params) = 0; 22 | virtual int set_volume(u8 percentage) = 0; 23 | virtual int queue_output(const void* buffer, usize& size) = 0; 24 | virtual int play(bool play) = 0; 25 | virtual int wait_until_consumed(usize trip_size, usize& remaining) = 0; 26 | }; 27 | -------------------------------------------------------------------------------- /src/mem/iospace.cpp: -------------------------------------------------------------------------------- 1 | #include "iospace.hpp" 2 | #include "sched/process.hpp" 3 | #include "vspace.hpp" 4 | 5 | bool IoSpace::map(CacheMode cache_mode) { 6 | base = reinterpret_cast(KERNEL_VSPACE.alloc(size)); 7 | if (!base) { 8 | println("failed to allocate mapping for io space"); 9 | return false; 10 | } 11 | 12 | usize align = phys & (PAGE_SIZE - 1); 13 | usize aligned_phys = phys & ~(PAGE_SIZE - 1); 14 | 15 | auto& KERNEL_MAP = KERNEL_PROCESS->page_map; 16 | 17 | for (usize i = 0; i < size + align; i += PAGE_SIZE) { 18 | auto virt = base + i; 19 | if (!KERNEL_MAP.map(virt, aligned_phys + i, PageFlags::Read | PageFlags::Write, cache_mode)) { 20 | println("kernel map failed"); 21 | for (usize j = 0; j < i; j += PAGE_SIZE) { 22 | KERNEL_MAP.unmap(base + j); 23 | } 24 | return false; 25 | } 26 | } 27 | 28 | base += align; 29 | 30 | return true; 31 | } 32 | -------------------------------------------------------------------------------- /apps/desktop/src/taskbar.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace ui { 5 | struct TextWindow; 6 | } 7 | 8 | struct TaskbarWindow : public ui::Window { 9 | static constexpr uint32_t HEIGHT = 30; 10 | static constexpr uint32_t BG_COLOR = 0xCFCFCF; 11 | 12 | explicit TaskbarWindow(uint32_t width); 13 | 14 | void add_icon(uint32_t color); 15 | void add_entry(std::unique_ptr entry); 16 | 17 | void update_time(ui::Context& ctx); 18 | 19 | bool handle_mouse(ui::Context& ctx, const ui::MouseState& old_state, const ui::MouseState& new_state) override { 20 | return false; 21 | } 22 | 23 | bool handle_keyboard(ui::Context& ctx, const ui::KeyState& old_state, const ui::KeyState& new_state) override { 24 | return false; 25 | } 26 | 27 | ui::TextWindow* time_text {}; 28 | ui::TextWindow* date_text {}; 29 | uint32_t last_x {}; 30 | uint32_t last_width {}; 31 | }; 32 | -------------------------------------------------------------------------------- /src/arch/x86/include/x86/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace x86 { 4 | static inline u8 in1(u16 port) { 5 | u8 value; 6 | asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); 7 | return value; 8 | } 9 | 10 | static inline u16 in2(u16 port) { 11 | u16 value; 12 | asm volatile("inw %1, %0" : "=a"(value) : "Nd"(port)); 13 | return value; 14 | } 15 | 16 | static inline u32 in4(u16 port) { 17 | u32 value; 18 | asm volatile("inl %1, %0" : "=a"(value) : "Nd"(port)); 19 | return value; 20 | } 21 | 22 | static inline void out1(u16 port, u8 value) { 23 | asm volatile("outb %1, %0" : : "Nd"(port), "a"(value)); 24 | } 25 | 26 | static inline void out2(u16 port, u16 value) { 27 | asm volatile("outw %1, %0" : : "Nd"(port), "a"(value)); 28 | } 29 | 30 | static inline void out4(u16 port, u32 value) { 31 | asm volatile("outl %1, %0" : : "Nd"(port), "a"(value)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libs/libcxx/include/utility: -------------------------------------------------------------------------------- 1 | #ifndef _UTILITY_H 2 | #define _UTILITY_H 3 | 4 | #include 5 | 6 | namespace std { 7 | template 8 | constexpr remove_reference_t<__T>&& move(__T&& __value) noexcept { 9 | return static_cast&&>(__value); 10 | } 11 | 12 | template 13 | constexpr __T&& forward(remove_reference_t<__T>& value) noexcept { 14 | return static_cast<__T&&>(value); 15 | } 16 | template 17 | constexpr __T&& forward(remove_reference_t<__T>&& value) noexcept { 18 | return static_cast<__T&&>(value); 19 | } 20 | 21 | template 22 | struct pair { 23 | using first_type = __T1; 24 | using second_type = __T2; 25 | 26 | first_type first; 27 | second_type second; 28 | }; 29 | 30 | struct in_place_t {}; 31 | 32 | inline constexpr in_place_t in_place {}; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/arch_thread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "sched/sysv.hpp" 4 | 5 | struct Process; 6 | 7 | struct ArchThread { 8 | constexpr ArchThread() : self {this} {} 9 | ArchThread(void (*fn)(void*), void* arg, Process* process); 10 | ArchThread(const SysvInfo& sysv, Process* process); 11 | ~ArchThread(); 12 | 13 | ArchThread* self; 14 | u8* sp {}; 15 | u8* syscall_sp {}; 16 | u8* saved_user_sp {}; 17 | usize handler_ip {}; 18 | usize handler_sp {}; 19 | usize* kernel_stack_base {}; 20 | u8* user_stack_base {}; 21 | u8* simd {}; 22 | usize fs_base {}; 23 | usize gs_base {}; 24 | }; 25 | 26 | static_assert(offsetof(ArchThread, sp) == 8); 27 | static_assert(offsetof(ArchThread, syscall_sp) == 16); 28 | static_assert(offsetof(ArchThread, saved_user_sp) == 24); 29 | static_assert(offsetof(ArchThread, handler_ip) == 32); 30 | static_assert(offsetof(ArchThread, handler_sp) == 40); 31 | -------------------------------------------------------------------------------- /src/arch/x86/simd_state.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct FxState { 4 | u16 fcw; 5 | u16 fsw; 6 | u8 ftw; 7 | u8 reserved0; 8 | u16 fop; 9 | u64 fip; 10 | u64 fdp; 11 | u32 mxcsr; 12 | u32 mxcsr_mask; 13 | u8 st0[10]; 14 | u8 reserved1[6]; 15 | u8 st1[10]; 16 | u8 reserved2[6]; 17 | u8 st2[10]; 18 | u8 reserved3[6]; 19 | u8 st3[10]; 20 | u8 reserved4[6]; 21 | u8 st4[10]; 22 | u8 reserved5[6]; 23 | u8 st5[10]; 24 | u8 reserved6[6]; 25 | u8 st6[10]; 26 | u8 reserved7[6]; 27 | u8 st7[10]; 28 | u8 reserved8[6]; 29 | u8 xmm0[16]; 30 | u8 xmm1[16]; 31 | u8 xmm2[16]; 32 | u8 xmm3[16]; 33 | u8 xmm4[16]; 34 | u8 xmm5[16]; 35 | u8 xmm6[16]; 36 | u8 xmm7[16]; 37 | u8 xmm8[16]; 38 | u8 xmm9[16]; 39 | u8 xmm10[16]; 40 | u8 xmm11[16]; 41 | u8 xmm12[16]; 42 | u8 xmm13[16]; 43 | u8 xmm14[16]; 44 | u8 xmm15[16]; 45 | u8 reserved9[48]; 46 | u8 available[48]; 47 | }; 48 | static_assert(sizeof(FxState) == 512); 49 | -------------------------------------------------------------------------------- /apps/desktop/src/desktop.cpp: -------------------------------------------------------------------------------- 1 | #include "desktop.hpp" 2 | #include 3 | 4 | Desktop::Desktop(ui::Context& ctx) : gui {ctx, ctx.width, ctx.height - TaskbarWindow::HEIGHT} { 5 | assert(ctx.height > TaskbarWindow::HEIGHT); 6 | 7 | auto taskbar_unique = std::make_unique(ctx.width); 8 | taskbar_unique->set_pos(0, ctx.height - TaskbarWindow::HEIGHT); 9 | taskbar = static_cast(taskbar_unique.get()); 10 | gui.root_windows.push_back(std::move(taskbar_unique)); 11 | 12 | ctx.add_dirty_rect({ 13 | .x = 0, 14 | .y = ctx.height - TaskbarWindow::HEIGHT, 15 | .width = ctx.width, 16 | .height = TaskbarWindow::HEIGHT 17 | }); 18 | } 19 | 20 | void Desktop::draw() { 21 | gui.draw(); 22 | } 23 | 24 | void Desktop::handle_mouse(ui::MouseState new_state) { 25 | gui.handle_mouse(new_state); 26 | } 27 | 28 | void Desktop::handle_keyboard(ui::KeyState new_state) { 29 | gui.handle_keyboard(new_state); 30 | } 31 | -------------------------------------------------------------------------------- /libs/libtext/include/libtext/libtext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace libtext { 8 | struct Bitmap { 9 | std::vector pixels; 10 | uint32_t width; 11 | uint32_t height; 12 | 13 | [[nodiscard]] constexpr uint32_t operator[](size_t y, size_t x) const { 14 | return pixels[y * width + x]; 15 | } 16 | }; 17 | 18 | struct Context { 19 | static std::optional create(std::string_view font_path = ""); 20 | 21 | std::optional rasterize_glyph(uint32_t codepoint, uint32_t width, uint32_t height, uint32_t fg, uint32_t bg); 22 | 23 | private: 24 | constexpr explicit Context(std::vector font, std::vector glyph_mappings) 25 | : font {std::move(font)}, glyph_mappings {std::move(glyph_mappings)} {} 26 | 27 | std::vector font; 28 | std::vector glyph_mappings; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/dev/net/packet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ethernet.hpp" 3 | #include "ipv4.hpp" 4 | #include "udp.hpp" 5 | 6 | struct Packet { 7 | explicit Packet(u32 size); 8 | ~Packet(); 9 | 10 | void* add_header(u32 hdr_size); 11 | 12 | void add_ethernet(const Mac& src, const Mac& dest, EtherType ether_type); 13 | void add_ipv4(IpProtocol protocol, u16 payload_size, u32 src_addr, u32 dest_addr); 14 | void add_udp(u16 src_port, u16 dest_port, u16 length); 15 | 16 | union { 17 | EthernetHeader* ethernet {}; 18 | }; 19 | union { 20 | Ipv4Header* ipv4 {}; 21 | }; 22 | union { 23 | UdpHeader* udp {}; 24 | }; 25 | 26 | void* data; 27 | u32 size; 28 | u32 offset {}; 29 | }; 30 | 31 | struct ReceivedPacket { 32 | union { 33 | EthernetHeader ethernet; 34 | } layer0; 35 | union { 36 | void* raw; 37 | Ipv4Header ipv4; 38 | } layer1; 39 | union { 40 | void* raw; 41 | UdpHeader udp; 42 | } layer2; 43 | u16 layer2_len; 44 | }; 45 | -------------------------------------------------------------------------------- /src/std/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(crescent PRIVATE 2 | cstring.cpp 3 | stdio.cpp 4 | new.cpp 5 | cxx.cpp 6 | ) 7 | 8 | if(ARCH STREQUAL "user") 9 | include(FetchContent) 10 | FetchContent_Declare( 11 | googletest 12 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip 13 | ) 14 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 15 | FetchContent_MakeAvailable(googletest) 16 | 17 | enable_testing() 18 | 19 | add_executable(std_tests 20 | tests.cpp 21 | ../mem/vmem.cpp 22 | ) 23 | target_compile_options(std_tests PRIVATE -Wall -Wextra -fsanitize=undefined,address) 24 | target_compile_definitions(std_tests PRIVATE TESTING) 25 | target_include_directories(std_tests PRIVATE . .. ../mem) 26 | target_link_libraries(std_tests GTest::gtest_main) 27 | target_link_options(std_tests PRIVATE -fsanitize=undefined,address) 28 | 29 | include(GoogleTest) 30 | gtest_discover_tests(std_tests) 31 | endif() 32 | -------------------------------------------------------------------------------- /src/sys/event_queue.cpp: -------------------------------------------------------------------------------- 1 | #include "event_queue.hpp" 2 | #include "stdio.hpp" 3 | 4 | void EventQueue::push(InputEvent event) { 5 | IrqGuard irq_guard {}; 6 | auto guard = lock.lock(); 7 | int next = (producer_ptr + 1) % MAX_EVENTS; 8 | if (next == consumer_ptr) { 9 | println("[kernel]: warning: discarding event"); 10 | return; 11 | } 12 | events[producer_ptr] = event; 13 | producer_ptr = next; 14 | produce_event.signal_one(); 15 | } 16 | 17 | bool EventQueue::consume(InputEvent& res) { 18 | IrqGuard irq_guard {}; 19 | auto guard = lock.lock(); 20 | 21 | if (consumer_ptr == producer_ptr) { 22 | return false; 23 | } 24 | 25 | res = events[consumer_ptr]; 26 | consumer_ptr = (consumer_ptr + 1) % MAX_EVENTS; 27 | 28 | return true; 29 | } 30 | 31 | bool EventQueue::is_empty() { 32 | IrqGuard irq_guard {}; 33 | auto guard = lock.lock(); 34 | 35 | return consumer_ptr == producer_ptr; 36 | } 37 | 38 | EventQueue GLOBAL_EVENT_QUEUE {}; 39 | 40 | -------------------------------------------------------------------------------- /src/arch/cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "arch/arch_cpu.hpp" 3 | #include "sched/sched.hpp" 4 | #include "dev/clock.hpp" 5 | #include "sched/process.hpp" 6 | #include "sched/deferred_work.hpp" 7 | 8 | [[noreturn]] void arch_idle_fn(void*); 9 | [[noreturn]] void sched_thread_destroyer_fn(void*); 10 | 11 | struct Cpu : public ArchCpu { 12 | Scheduler scheduler; 13 | Thread idle_thread {"idle", this, &*KERNEL_PROCESS, arch_idle_fn, nullptr}; 14 | Thread thread_destroyer {"thread destroyer", this, &*KERNEL_PROCESS, sched_thread_destroyer_fn, nullptr}; 15 | Thread* kernel_main {}; 16 | Spinlock> sched_destroy_list {}; 17 | Event sched_destroy_event {}; 18 | TickSource* cpu_tick_source {}; 19 | DoubleList deferred_work {}; 20 | u32 number {}; 21 | kstd::atomic thread_count {}; 22 | kstd::atomic ipi_ack {}; 23 | }; 24 | 25 | usize arch_get_cpu_count(); 26 | Cpu* arch_get_cpu(usize index); 27 | -------------------------------------------------------------------------------- /src/arch/user/include/arch/paging.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | enum class CacheMode { 5 | WriteCombine, 6 | WriteBack 7 | }; 8 | 9 | constexpr usize PAGE_SIZE = 0x1000; 10 | 11 | enum class PageFlags { 12 | Read = 1 << 0, 13 | Write = 1 << 1, 14 | Execute = 1 << 2, 15 | User = 1 << 3 16 | }; 17 | 18 | constexpr PageFlags operator|(PageFlags lhs, PageFlags rhs) { 19 | return static_cast(static_cast(lhs) | static_cast(rhs)); 20 | } 21 | 22 | constexpr PageFlags& operator|=(PageFlags& lhs, PageFlags rhs) { 23 | lhs = lhs | rhs; 24 | return lhs; 25 | } 26 | 27 | struct PageMap { 28 | constexpr explicit PageMap(PageMap*) {} 29 | 30 | constexpr bool map(usize, usize, PageFlags, CacheMode) { 31 | return true; 32 | } 33 | 34 | constexpr usize get_phys(usize virt) { 35 | return virt; 36 | } 37 | 38 | constexpr void unmap(usize) {} 39 | 40 | constexpr void protect(usize, PageFlags, CacheMode) {} 41 | 42 | constexpr void use() {} 43 | }; 44 | -------------------------------------------------------------------------------- /src/mem/iospace.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "register.hpp" 4 | #include "arch/paging.hpp" 5 | 6 | class IoSpace : public MemSpace { 7 | public: 8 | constexpr IoSpace() : MemSpace {0} {} 9 | inline explicit IoSpace(void* virt) : MemSpace {reinterpret_cast(virt)} {} 10 | constexpr IoSpace(usize phys, usize size) : MemSpace {0}, phys {phys}, size {size} {} 11 | 12 | constexpr void set_phys(usize new_phys, usize new_size) { 13 | phys = new_phys; 14 | size = new_size; 15 | } 16 | 17 | constexpr IoSpace subspace(usize offset) { 18 | return {*this, offset}; 19 | } 20 | 21 | [[nodiscard]] bool map(CacheMode cache_mode); 22 | 23 | inline void* mapping() { 24 | return reinterpret_cast(base); 25 | } 26 | 27 | private: 28 | constexpr IoSpace(const IoSpace& other, usize offset) : MemSpace {other.base + offset} { 29 | phys = other.phys + offset; 30 | size = other.size - offset; 31 | } 32 | 33 | usize phys {}; 34 | usize size {}; 35 | }; 36 | -------------------------------------------------------------------------------- /src/mem/pmalloc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "double_list.hpp" 4 | #include "utils/spinlock.hpp" 5 | 6 | struct PRegion; 7 | struct Page { 8 | DoubleListHook hook {}; 9 | PRegion* region {}; 10 | usize ref_count {}; 11 | usize page_num : 36 {}; 12 | bool used : 1 {}; 13 | bool in_list : 1 {}; 14 | u8 list_index : 4 {}; 15 | IrqSpinlock lock {}; 16 | 17 | [[nodiscard]] constexpr usize phys() const { 18 | return page_num << 12; 19 | } 20 | 21 | static Page* from_phys(usize phys); 22 | }; 23 | 24 | struct PRegion { 25 | DoubleListHook hook {}; 26 | usize base {}; 27 | usize page_count {}; 28 | usize res_count {}; 29 | Page pages[1]; 30 | }; 31 | 32 | extern Spinlock> P_REGIONS; 33 | 34 | void pmalloc_add_mem(usize phys, usize size); 35 | usize pmalloc(usize count); 36 | void pfree(usize addr, usize count); 37 | usize pmalloc_get_total_mem(); 38 | usize pmalloc_get_reserved_mem(); 39 | usize pmalloc_get_used_mem(); 40 | -------------------------------------------------------------------------------- /libs/libui/include/ui/context.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "primitive.hpp" 6 | 7 | namespace ui { 8 | struct Context { 9 | uint32_t* fb {}; 10 | uintptr_t pitch_32 {}; 11 | uint32_t width {}; 12 | uint32_t height {}; 13 | uint32_t x_off {}; 14 | uint32_t y_off {}; 15 | 16 | void add_dirty_rect(const Rect& rect); 17 | 18 | void draw_filled_rect(const Rect& rect, uint32_t color) const; 19 | void draw_bitmap( 20 | const uint32_t* pixels, 21 | uint32_t x, 22 | uint32_t y, 23 | uint32_t width, 24 | uint32_t height) const; 25 | void draw_rect_outline(const Rect& rect, uint32_t color, uint32_t thickness) const; 26 | 27 | private: 28 | friend struct Gui; 29 | friend struct Window; 30 | 31 | void add_clip_rect(const Rect& rect); 32 | void clear_clip_rects(); 33 | 34 | std::vector clip_rects {}; 35 | std::vector subtract_rects {}; 36 | std::vector dirty_rects {}; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/sys/posix/signals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SIGHUP 1 4 | #define SIGINT 2 5 | #define SIGQUIT 3 6 | #define SIGILL 4 7 | #define SIGTRAP 5 8 | #define SIGABRT 6 9 | #define SIGIOT SIGABRT 10 | #define SIGBUS 7 11 | #define SIGFPE 8 12 | #define SIGKILL 9 13 | #define SIGUSR1 10 14 | #define SIGSEGV 11 15 | #define SIGUSR2 12 16 | #define SIGPIPE 13 17 | #define SIGALRM 14 18 | #define SIGTERM 15 19 | #define SIGSTKFLT 16 20 | #define SIGCHLD 17 21 | #define SIGCONT 18 22 | #define SIGSTOP 19 23 | #define SIGTSTP 20 24 | #define SIGTTIN 21 25 | #define SIGTTOU 22 26 | #define SIGURG 23 27 | #define SIGXCPU 24 28 | #define SIGXFSZ 25 29 | #define SIGVTALRM 26 30 | #define SIGPROF 27 31 | #define SIGWINCH 28 32 | #define SIGIO 29 33 | #define SIGPOLL SIGIO 34 | #define SIGPWR 30 35 | #define SIGSYS 31 36 | 37 | struct Thread; 38 | 39 | enum class PosixSignalDisposition { 40 | Kill, 41 | Ignore, 42 | Stop, 43 | Continue 44 | }; 45 | 46 | PosixSignalDisposition posix_handle_default_signal(int sig); 47 | -------------------------------------------------------------------------------- /src/std/manually_init.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utility.hpp" 3 | #include "new.hpp" 4 | #include "assert.hpp" 5 | 6 | template 7 | class ManuallyInit { 8 | public: 9 | void initialize(T&& value) { 10 | new (storage.data) T {std::move(value)}; 11 | initialized = true; 12 | } 13 | 14 | template 15 | void initialize(Args... args) { 16 | new (storage.data) T {std::forward(args)...}; 17 | initialized = true; 18 | } 19 | 20 | void destroy() { 21 | kstd::launder(reinterpret_cast(storage.data))->~T(); 22 | } 23 | 24 | T* operator->() { 25 | return kstd::launder(reinterpret_cast(storage.data)); 26 | } 27 | 28 | T& operator*() { 29 | return *kstd::launder(reinterpret_cast(storage.data)); 30 | } 31 | 32 | [[nodiscard]] constexpr bool is_initialized() const { 33 | return initialized; 34 | } 35 | 36 | private: 37 | struct alignas(T) Storage { 38 | char data[sizeof(T)]; 39 | }; 40 | 41 | Storage storage; 42 | bool initialized; 43 | }; 44 | -------------------------------------------------------------------------------- /src/sched/signal_ctx.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "utils/flags_enum.hpp" 4 | #include "arch/irq.hpp" 5 | 6 | enum class SignalFlags : unsigned long { 7 | NoChildStop = 1, 8 | NoChildWait = 2, 9 | SigInfo = 4, 10 | Restorer = 0x4000000, 11 | AltStack = 0x8000000, 12 | RestartSyscall = 0x10000000, 13 | NoDefer = 0x40000000, 14 | ResetOnEntry = 0x80000000 15 | }; 16 | FLAGS_ENUM(SignalFlags); 17 | 18 | struct Thread; 19 | 20 | struct ThreadSignalContext { 21 | u64 blocked_signals {}; 22 | u64 pending_signals {}; 23 | 24 | void check_signals(IrqFrame* frame, Thread* thread); 25 | }; 26 | 27 | struct SignalContext { 28 | bool send_signal(Thread* thread, int sig, bool check_mask); 29 | 30 | struct Signal { 31 | static constexpr usize DEFAULT = 0; 32 | static constexpr usize IGNORE = 1; 33 | 34 | usize handler; 35 | u64 mask; 36 | SignalFlags flags; 37 | usize restorer; 38 | usize stack_base; 39 | usize stack_size; 40 | }; 41 | 42 | Signal signals[64] {}; 43 | }; 44 | -------------------------------------------------------------------------------- /src/arch/aarch64/mem/std_mem.cpp: -------------------------------------------------------------------------------- 1 | #include "cstring.hpp" 2 | #include "types.hpp" 3 | 4 | #undef memcpy 5 | #undef memset 6 | 7 | void* memcpy(void* __restrict dest, const void* __restrict src, size_t size) { 8 | auto* dest_ptr = static_cast(dest); 9 | auto* src_ptr = static_cast(src); 10 | for (; size; --size) { 11 | *dest_ptr++ = *src_ptr++; 12 | } 13 | return dest; 14 | } 15 | 16 | void* memset(void* __restrict dest, int ch, size_t size) { 17 | if (!size) { 18 | return dest; 19 | } 20 | 21 | u64 c = static_cast(ch); 22 | auto* ptr = static_cast(dest); 23 | 24 | for (; reinterpret_cast(ptr) & 7;) { 25 | *ptr++ = c; 26 | if (--size == 0) { 27 | return dest; 28 | } 29 | } 30 | 31 | c |= c << 8; 32 | c |= c << 16; 33 | c |= c << 32; 34 | 35 | for (; size >= 8; size -= 8) { 36 | *reinterpret_cast(ptr) = c; 37 | ptr += 8; 38 | } 39 | 40 | for (; size; --size) { 41 | *ptr++ = c; 42 | } 43 | 44 | return dest; 45 | } 46 | -------------------------------------------------------------------------------- /apps/desktop/src/window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static constexpr uint32_t TITLEBAR_HEIGHT = 20; 8 | static constexpr uint32_t BORDER_WIDTH = 4; 9 | static constexpr uint32_t BORDER_COLOR = 0xFFFFFF; 10 | static constexpr uint32_t TITLEBAR_ACTIVE_COLOR = 0xFFFFFF; 11 | 12 | struct DesktopWindow : public ui::Window { 13 | explicit DesktopWindow(bool no_decorations); 14 | ~DesktopWindow() override = default; 15 | 16 | bool handle_mouse(ui::Context& ctx, const ui::MouseState& old_state, const ui::MouseState& new_state) override; 17 | void on_mouse_enter(ui::Context& ctx, const ui::MouseState& new_state) override; 18 | void on_mouse_leave(ui::Context& ctx, const ui::MouseState& new_state) override; 19 | 20 | bool handle_keyboard(ui::Context& ctx, const ui::KeyState& old_state, const ui::KeyState& new_state) override; 21 | 22 | void update_titlebar(uint32_t width) override {} 23 | 24 | void set_title(std::string_view title); 25 | }; 26 | -------------------------------------------------------------------------------- /include/crescent/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef CRESCENT_SOCKET_H 2 | #define CRESCENT_SOCKET_H 3 | 4 | #include "syscalls.h" 5 | #include 6 | 7 | typedef enum SocketType { 8 | SOCKET_TYPE_IPC, 9 | SOCKET_TYPE_UDP, 10 | SOCKET_TYPE_TCP 11 | } SocketType; 12 | 13 | typedef enum SocketAddressType { 14 | SOCKET_ADDRESS_TYPE_IPC, 15 | SOCKET_ADDRESS_TYPE_IPV4, 16 | SOCKET_ADDRESS_TYPE_IPV6 17 | } SocketAddressType; 18 | 19 | typedef struct SocketAddress { 20 | SocketAddressType type; 21 | } SocketAddress; 22 | 23 | typedef struct IpcSocketAddress { 24 | SocketAddress generic; 25 | CrescentHandle target; 26 | } IpcSocketAddress; 27 | 28 | typedef struct Ipv4SocketAddress { 29 | SocketAddress generic; 30 | uint32_t ipv4; 31 | uint16_t port; 32 | } Ipv4SocketAddress; 33 | 34 | typedef struct Ipv6SocketAddress { 35 | SocketAddress generic; 36 | uint16_t ipv6[8]; 37 | uint16_t port; 38 | } Ipv6SocketAddress; 39 | 40 | typedef enum SocketFlag { 41 | SOCK_NONE = 0, 42 | SOCK_NONBLOCK = 1 << 0 43 | } SocketFlag; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/sys/user_access.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | extern "C" bool mem_copy_to_user(usize user, const void* kernel, usize size); 5 | extern "C" bool mem_copy_to_kernel(void* kernel, usize user, usize size); 6 | extern "C" bool atomic_load32_user(usize user, u32* ret); 7 | 8 | struct UserAccessor { 9 | inline constexpr explicit UserAccessor(usize addr) : addr {addr} {} 10 | template 11 | inline explicit UserAccessor(T* ptr) : addr {reinterpret_cast(ptr)} {} 12 | 13 | inline bool load(void* data, usize size) { 14 | return mem_copy_to_kernel(data, addr, size); 15 | } 16 | 17 | template 18 | inline bool load(T& data) { 19 | return load(static_cast(&data), sizeof(T)); 20 | } 21 | 22 | inline bool store(const void* data, usize size) { 23 | return mem_copy_to_user(addr, data, size); 24 | } 25 | 26 | template 27 | inline bool store(const T& data) { 28 | return store(static_cast(&data), sizeof(T)); 29 | } 30 | 31 | private: 32 | usize addr; 33 | }; 34 | -------------------------------------------------------------------------------- /src/dev/net/nic/nic.cpp: -------------------------------------------------------------------------------- 1 | #include "nic.hpp" 2 | #include "dev/clock.hpp" 3 | 4 | ManuallyDestroy>>> NICS; 5 | 6 | void Nic::wait_for_ip() { 7 | bool wait = false; 8 | { 9 | IrqGuard irq_guard {}; 10 | auto guard = lock.lock(); 11 | if (!ip) { 12 | wait = true; 13 | } 14 | } 15 | 16 | if (wait) { 17 | ip_available_event.wait(); 18 | } 19 | 20 | assert(ip); 21 | } 22 | 23 | bool Nic::wait_for_ip_with_timeout(usize seconds) { 24 | bool wait = false; 25 | { 26 | IrqGuard irq_guard {}; 27 | auto guard = lock.lock(); 28 | if (!ip) { 29 | wait = true; 30 | } 31 | } 32 | 33 | if (wait) { 34 | if (!ip_available_event.wait_with_timeout(NS_IN_S * seconds)) { 35 | IrqGuard irq_guard {}; 36 | auto guard = lock.lock(); 37 | return ip; 38 | } 39 | } 40 | 41 | assert(ip); 42 | return true; 43 | } 44 | 45 | void nics_wait_ready() { 46 | IrqGuard irq_guard {}; 47 | auto guard = NICS->lock(); 48 | for (auto& nic : *guard) { 49 | nic->wait_for_ip_with_timeout(1); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /libs/libui/src/button.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/button.hpp" 2 | 3 | using namespace ui; 4 | 5 | ButtonWindow::ButtonWindow() : Window {true} { 6 | bg_color = inactive_color; 7 | internal = true; 8 | } 9 | 10 | void ButtonWindow::draw(Context& ctx) { 11 | ctx.draw_filled_rect(rect, bg_color); 12 | } 13 | 14 | bool ButtonWindow::handle_mouse(Context& ctx, const MouseState&, const MouseState& new_state) { 15 | if (!prev_mouse_state && new_state.left_pressed) { 16 | bg_color = active_color; 17 | prev_mouse_state = true; 18 | ctx.add_dirty_rect(get_abs_rect()); 19 | } 20 | else if (prev_mouse_state && !new_state.left_pressed) { 21 | bg_color = inactive_color; 22 | prev_mouse_state = false; 23 | if (callback) { 24 | callback(arg); 25 | } 26 | ctx.add_dirty_rect(get_abs_rect()); 27 | } 28 | 29 | return true; 30 | } 31 | 32 | void ButtonWindow::on_mouse_leave(Context& ctx, const MouseState& new_state) { 33 | if (prev_mouse_state) { 34 | bg_color = inactive_color; 35 | prev_mouse_state = false; 36 | ctx.add_dirty_rect(get_abs_rect()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/sched/ipc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sys/socket.hpp" 3 | #include "dev/event.hpp" 4 | 5 | struct IpcSocket final : public Socket { 6 | IpcSocket(kstd::shared_ptr owner_desc, int flags); 7 | 8 | ~IpcSocket() override; 9 | 10 | static constexpr usize IPC_BUFFER_SIZE = 512; 11 | 12 | int connect(const AnySocketAddress& address) override; 13 | int disconnect() override; 14 | int listen(uint32_t port) override; 15 | int accept(kstd::shared_ptr& connection, int connection_flags) override; 16 | int send(const void* data, usize& size) override; 17 | int receive(void* data, usize& size) override; 18 | 19 | int get_peer_name(AnySocketAddress& address) override; 20 | 21 | IpcSocket* pending {}; 22 | IpcSocket* target {}; 23 | KernelIpcSocketAddress target_address {}; 24 | kstd::shared_ptr owner_desc {}; 25 | Event pending_event {}; 26 | u8 buf[IPC_BUFFER_SIZE] {}; 27 | usize buf_read_ptr {}; 28 | usize buf_write_ptr {}; 29 | usize buf_size {}; 30 | Event write_event {}; 31 | Event read_event {}; 32 | Spinlock lock {}; 33 | }; 34 | -------------------------------------------------------------------------------- /src/arch/aarch64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BOARD "virt" CACHE STRING "Board to target") 2 | set_property(CACHE BOARD PROPERTY STRINGS virt msm) 3 | 4 | message(STATUS "Targeting board '${BOARD}'") 5 | 6 | if(BOARD STREQUAL "virt") 7 | target_compile_definitions(crescent PRIVATE BOARD_QEMU_VIRT) 8 | elseif(BOARD STREQUAL "msm") 9 | target_compile_definitions(crescent PRIVATE BOARD_MSM) 10 | endif() 11 | 12 | target_sources(crescent PRIVATE 13 | loader/start.S 14 | loader/start.cpp 15 | loader/early_paging.cpp 16 | mem/std_mem.cpp 17 | mem/paging.cpp 18 | mem/mem.cpp 19 | mem/user.S 20 | 21 | kernel_dtb.cpp 22 | dtb.cpp 23 | arch_sched.cpp 24 | cpu.cpp 25 | smp.cpp 26 | start.cpp 27 | ) 28 | target_include_directories(crescent PRIVATE include) 29 | 30 | set_source_files_properties( 31 | ${CMAKE_CURRENT_LIST_DIR}/loader/start.cpp 32 | ${CMAKE_CURRENT_LIST_DIR}/loader/early_paging.cpp 33 | ${CMAKE_CURRENT_LIST_DIR}/dtb.cpp 34 | ${CMAKE_CURRENT_LIST_DIR}/smp.cpp 35 | TARGET_DIRECTORY crescent 36 | PROPERTIES COMPILE_FLAGS -mno-unaligned-access 37 | ) 38 | 39 | add_subdirectory(dev) 40 | add_subdirectory(interrupts) 41 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/usermode.S: -------------------------------------------------------------------------------- 1 | .globl x86_syscall_stub 2 | .type x86_syscall_stub, @function 3 | x86_syscall_stub: 4 | swapgs 5 | mov %rsp, %gs:24 6 | mov %gs:16, %rsp 7 | cld 8 | sti 9 | 10 | sub $128, %rsp 11 | mov %rax, 0(%rsp) 12 | mov %rbx, 8(%rsp) 13 | mov %rcx, 16(%rsp) 14 | mov %rdx, 24(%rsp) 15 | mov %rdi, 32(%rsp) 16 | mov %rsi, 40(%rsp) 17 | mov %rbp, 48(%rsp) 18 | mov %r8, 56(%rsp) 19 | mov %r9, 64(%rsp) 20 | mov %r10, 72(%rsp) 21 | mov %r11, 80(%rsp) 22 | mov %r12, 88(%rsp) 23 | mov %r13, 96(%rsp) 24 | mov %r14, 104(%rsp) 25 | mov %r15, 112(%rsp) 26 | 27 | mov %rsp, %rdi 28 | call syscall_handler 29 | 30 | mov 0(%rsp), %rax 31 | mov 8(%rsp), %rbx 32 | mov 16(%rsp), %rcx 33 | mov 24(%rsp), %rdx 34 | mov 32(%rsp), %rdi 35 | mov 40(%rsp), %rsi 36 | mov 48(%rsp), %rbp 37 | mov 56(%rsp), %r8 38 | mov 64(%rsp), %r9 39 | mov 72(%rsp), %r10 40 | mov 80(%rsp), %r11 41 | mov 88(%rsp), %r12 42 | mov 96(%rsp), %r13 43 | mov 104(%rsp), %r14 44 | mov 112(%rsp), %r15 45 | add $128, %rsp 46 | 47 | cli 48 | mov %gs:24, %rsp 49 | swapgs 50 | sysretq 51 | 52 | .section .note.GNU-stack 53 | -------------------------------------------------------------------------------- /src/utils/flags_enum.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "type_traits.hpp" 3 | 4 | #define FLAGS_ENUM(name) \ 5 | constexpr name operator|(const name& lhs, const name& rhs) { \ 6 | using underlying = kstd::underlying_type_t; \ 7 | return static_cast(static_cast(lhs) | static_cast(rhs)); \ 8 | } \ 9 | constexpr bool operator&(const name& lhs, const name& rhs) { \ 10 | using underlying = kstd::underlying_type_t; \ 11 | return static_cast(lhs) & static_cast(rhs); \ 12 | } \ 13 | constexpr name operator~(const name& value) { \ 14 | using underlying = kstd::underlying_type_t; \ 15 | return static_cast(~static_cast(value)); \ 16 | } \ 17 | constexpr name& operator|=(name& lhs, const name& rhs) { \ 18 | lhs = lhs | rhs; \ 19 | return lhs; \ 20 | } \ 21 | constexpr name& operator&=(name& lhs, const name& rhs) { \ 22 | using underlying = kstd::underlying_type_t; \ 23 | lhs = static_cast(static_cast(lhs) & static_cast(rhs)); \ 24 | return lhs; \ 25 | } \ 26 | namespace __ ## name {} \ 27 | using namespace __ ## name 28 | -------------------------------------------------------------------------------- /src/std/format.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "string_view.hpp" 3 | #include 4 | 5 | namespace kstd { 6 | template 7 | concept FormatSink = requires(T value) { 8 | value += "hello world!"; 9 | }; 10 | 11 | struct hex_fmt { 12 | uint64_t value; 13 | }; 14 | 15 | template 16 | struct formatter { 17 | constexpr explicit formatter(Sink& sink) : sink {sink} {} 18 | 19 | formatter& operator<<(string_view str) { 20 | sink += str; 21 | return *this; 22 | } 23 | 24 | formatter& operator<<(uint64_t value) { 25 | format_number(value, 10); 26 | return *this; 27 | } 28 | 29 | formatter& operator<<(hex_fmt value) { 30 | format_number(value.value, 16); 31 | return *this; 32 | } 33 | 34 | private: 35 | static constexpr char CHARS[] = "0123456789ABCDEF"; 36 | 37 | void format_number(uint64_t value, int base) { 38 | char buf[64]; 39 | char* ptr = buf + 64; 40 | do { 41 | *--ptr = CHARS[value % base]; 42 | value /= base; 43 | } while (value); 44 | sink += string_view {ptr, static_cast(buf + 64 - ptr)}; 45 | } 46 | 47 | Sink& sink; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /libs/libui/src/text.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/text.hpp" 2 | 3 | using namespace ui; 4 | 5 | TextWindow::TextWindow() 6 | : Window {true}, text_ctx {libtext::Context::create().value()} { 7 | } 8 | 9 | void TextWindow::draw(Context& ctx) { 10 | ctx.draw_filled_rect(rect, bg_color); 11 | 12 | uint32_t y_offset = 0; 13 | uint32_t x_offset = 0; 14 | 15 | for (auto c : text) { 16 | auto bitmap = glyph_cache.find(c); 17 | if (bitmap == glyph_cache.end()) { 18 | auto new_bitmap = text_ctx.rasterize_glyph(c, 8, 16, text_color, bg_color).value(); 19 | glyph_cache.insert(std::pair {static_cast(c), std::move(new_bitmap)}); 20 | bitmap = glyph_cache.find(c); 21 | assert(bitmap != glyph_cache.end()); 22 | } 23 | 24 | if (x_offset + bitmap->second.width > rect.width) { 25 | x_offset = 0; 26 | y_offset += bitmap->second.height; 27 | if (y_offset >= rect.height) { 28 | return; 29 | } 30 | } 31 | 32 | ctx.draw_bitmap( 33 | bitmap->second.pixels.data(), 34 | rect.x + x_offset, 35 | rect.y + y_offset, 36 | bitmap->second.width, 37 | bitmap->second.height); 38 | 39 | x_offset += bitmap->second.width; 40 | } 41 | } -------------------------------------------------------------------------------- /src/arch/user/generic.cpp: -------------------------------------------------------------------------------- 1 | #include "arch/aarch64/dtb.hpp" 2 | #include "mem/pmalloc.hpp" 3 | #include "sched/process.hpp" 4 | #include "sched/sched.hpp" 5 | #include 6 | 7 | bool IRQS_ENABLED; 8 | namespace { 9 | Thread* CURRENT_THREAD; 10 | } 11 | 12 | Thread* get_current_thread() { 13 | return CURRENT_THREAD; 14 | } 15 | 16 | void set_current_thread(Thread* thread) { 17 | CURRENT_THREAD = thread; 18 | } 19 | 20 | extern "C" void sched_switch_thread(Thread* prev, Thread* current) { 21 | 22 | } 23 | 24 | class StdioLogSink : public LogSink { 25 | public: 26 | void write(kstd::string_view str) override { 27 | printf("%.*s", static_cast(str.size()), str.data()); 28 | fflush(stdout); 29 | } 30 | }; 31 | StdioLogSink LOG_SINK {}; 32 | 33 | [[noreturn]] void kmain(); 34 | 35 | extern void kernel_dtb_init(dtb::Dtb plain_dtb); 36 | 37 | int main() { 38 | LOG.lock()->register_sink(&LOG_SINK); 39 | 40 | auto mem = malloc(1024ULL * 1024 * 1024 * 2); 41 | pmalloc_add_mem(reinterpret_cast(mem), 1024ULL * 1024 * 1024 * 2); 42 | 43 | KERNEL_PROCESS.initialize("kernel", false); 44 | CURRENT_THREAD = new Thread {"kernel", nullptr, &*KERNEL_PROCESS}; 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/dev/user_dev.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vector.hpp" 3 | #include "manually_destroy.hpp" 4 | #include "shared_ptr.hpp" 5 | #include "utils/spinlock.hpp" 6 | #include "string.hpp" 7 | #include "crescent/devlink.h" 8 | 9 | struct UserDevice { 10 | virtual ~UserDevice() = default; 11 | 12 | kstd::string name {}; 13 | kstd::atomic open_count {}; 14 | bool exclusive {}; 15 | 16 | virtual int handle_request(const kstd::vector& data, kstd::vector& res, usize max_size) = 0; 17 | }; 18 | 19 | struct DeviceHandle { 20 | explicit DeviceHandle(kstd::shared_ptr device) : device {std::move(device)} { 21 | this->device->open_count.fetch_add(1, kstd::memory_order::relaxed); 22 | } 23 | 24 | ~DeviceHandle() { 25 | device->open_count.fetch_sub(1, kstd::memory_order::relaxed); 26 | } 27 | 28 | kstd::shared_ptr device; 29 | }; 30 | 31 | usize user_dev_add(kstd::shared_ptr device, CrescentDeviceType type); 32 | void user_dev_remove(usize index, CrescentDeviceType type); 33 | int user_dev_wait_for_change(CrescentDeviceType type, CrescentDeviceChange& ret); 34 | 35 | extern ManuallyDestroy>>> USER_DEVICES 36 | [static_cast(CrescentDeviceTypeMax)]; 37 | -------------------------------------------------------------------------------- /src/arch/aarch64/mem/mem.cpp: -------------------------------------------------------------------------------- 1 | #include "aarch64_mem.hpp" 2 | #include "mem/pmalloc.hpp" 3 | 4 | void aarch64_mem_check_add_usable_range(usize base, usize len, MemReserve* reserve, u32 reserve_count) { 5 | auto end = base + len; 6 | 7 | for (u32 i = 0; i < reserve_count; ++i) { 8 | const auto& entry = reserve[i]; 9 | auto entry_start = entry.base; 10 | auto entry_end = entry_start + entry.len; 11 | 12 | if (base < entry_end && end > entry_start) { 13 | if (entry_start <= base) { 14 | u64 used = entry_end - base; 15 | base = entry_end; 16 | len -= used; 17 | } 18 | else { 19 | u64 first_size = entry_start - base; 20 | u64 first_base = base; 21 | aarch64_mem_check_add_usable_range(first_base, first_size, reserve, reserve_count); 22 | 23 | if (entry_end < end) { 24 | u64 second_size = end - entry_end; 25 | u64 second_base = entry_end; 26 | aarch64_mem_check_add_usable_range(second_base, second_size, reserve, reserve_count); 27 | } 28 | return; 29 | } 30 | } 31 | } 32 | 33 | auto base_align = base & (0x1000 - 1); 34 | base = (base + 0x1000 - 1) & ~(0x1000 - 1); 35 | len -= base_align; 36 | len &= ~(0x1000 - 1); 37 | 38 | if (len < 0x1000) { 39 | return; 40 | } 41 | 42 | pmalloc_add_mem(base, len); 43 | } 44 | -------------------------------------------------------------------------------- /src/sys/socket.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "crescent/socket.h" 4 | #include "shared_ptr.hpp" 5 | #include "variant.hpp" 6 | 7 | struct ProcessDescriptor; 8 | 9 | struct KernelIpcSocketAddress { 10 | SocketAddress generic; 11 | ProcessDescriptor* descriptor; 12 | }; 13 | 14 | union AnySocketAddress { 15 | SocketAddress generic; 16 | KernelIpcSocketAddress ipc; 17 | Ipv4SocketAddress ipv4; 18 | Ipv6SocketAddress ipv6; 19 | }; 20 | 21 | struct Socket { 22 | constexpr explicit Socket(int flags) : flags {flags} {} 23 | 24 | virtual ~Socket() = default; 25 | 26 | virtual int connect(const AnySocketAddress& address) = 0; 27 | virtual int disconnect() = 0; 28 | virtual int listen(uint32_t port) = 0; 29 | virtual int accept(kstd::shared_ptr& connection, int connection_flags) = 0; 30 | virtual int send(const void* data, usize& size) = 0; 31 | virtual int receive(void* data, usize& size) = 0; 32 | 33 | virtual int send_to(const void* data, usize& size, const AnySocketAddress& dest) { 34 | return ERR_UNSUPPORTED; 35 | } 36 | 37 | virtual int receive_from(void* data, usize& size, AnySocketAddress& src) { 38 | return ERR_UNSUPPORTED; 39 | } 40 | 41 | virtual int get_peer_name(AnySocketAddress& address) = 0; 42 | 43 | protected: 44 | int flags; 45 | }; 46 | -------------------------------------------------------------------------------- /src/dev/event.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sched/thread.hpp" 3 | #include "functional.hpp" 4 | #include "vector.hpp" 5 | 6 | struct Waitable { 7 | DoubleListHook hook {}; 8 | Thread* thread {}; 9 | bool in_list {}; 10 | }; 11 | 12 | struct Event { 13 | static usize wait_any(Event** events, usize count, u64 max_ns); 14 | 15 | void reset(); 16 | void wait(bool consume = true); 17 | bool wait_with_timeout(u64 max_ns); 18 | 19 | void signal_one(); 20 | void signal_one_if_not_pending(); 21 | void signal_all(); 22 | 23 | void signal_count(usize count); 24 | 25 | inline bool is_being_waited() { 26 | IrqGuard irq_guard {}; 27 | auto guard = lock.lock(); 28 | return !waiters.is_empty(); 29 | } 30 | 31 | [[nodiscard]] bool is_pending() { 32 | IrqGuard irq_guard {}; 33 | auto guard = lock.lock(); 34 | return signaled_count > 0; 35 | } 36 | 37 | private: 38 | DoubleList waiters {}; 39 | usize signaled_count {}; 40 | Spinlock lock {}; 41 | }; 42 | 43 | struct CallbackProducer { 44 | [[nodiscard]] usize add_callback(kstd::small_function callback); 45 | void remove_callback(usize index); 46 | 47 | void signal_one(); 48 | void signal_all(); 49 | 50 | private: 51 | Spinlock>> callbacks {}; 52 | }; 53 | -------------------------------------------------------------------------------- /src/arch/x86/interrupts/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include "gdt.hpp" 2 | #include "tss.hpp" 3 | 4 | static constexpr u64 gdt_entry(u32 base, u8 access, u8 flags, u32 limit) { 5 | return static_cast(limit & 0xFFFF) | 6 | (static_cast(limit >> 16) << 48) | 7 | (static_cast(access) << 40) | 8 | (static_cast(flags) << 52) | 9 | (base & 0xFFFF) << 16 | 10 | (static_cast(base >> 16 & 0xFF) << 32) | 11 | (static_cast(base >> 24 & 0xFF) << 56); 12 | } 13 | 14 | namespace { 15 | u64 GDT[8] { 16 | gdt_entry(0, 0, 0, 0), 17 | // kernel code 18 | gdt_entry(0, 0x9A, 0xA, 0), 19 | // kernel data 20 | gdt_entry(0, 0x92, 0xC, 0), 21 | // padding for syscall 22 | gdt_entry(0, 0, 0, 0), 23 | // user data 24 | gdt_entry(0, 0xF2, 0xC, 0), 25 | // user code 26 | gdt_entry(0, 0xFA, 0xA, 0), 27 | 0, 28 | 0 29 | }; 30 | } 31 | 32 | struct [[gnu::packed]] Gdtr { 33 | u16 size; 34 | u64 offset; 35 | }; 36 | 37 | extern "C" void x86_load_gdt_asm(Gdtr* gdtr); 38 | 39 | void x86_load_gdt(Tss* tss) { 40 | auto tss_addr = reinterpret_cast(tss); 41 | GDT[sizeof(GDT) / 8 - 2] = gdt_entry(tss_addr, 0x89, 0, sizeof(Tss) - 1); 42 | GDT[sizeof(GDT) / 8 - 1] = tss_addr >> 32; 43 | Gdtr gdtr {.size = sizeof(GDT) - 1, .offset = reinterpret_cast(GDT)}; 44 | x86_load_gdt_asm(&gdtr); 45 | } 46 | -------------------------------------------------------------------------------- /src/arch/x86/acpi/madt.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi/acpi.hpp" 2 | #include "arch/x86/dev/io_apic.hpp" 3 | #include "x86/io.hpp" 4 | #include "cstring.hpp" 5 | 6 | void x86_madt_parse() { 7 | auto* madt = static_cast(acpi::get_table("APIC")); 8 | if (!madt) { 9 | return; 10 | } 11 | 12 | if (madt->flags & acpi::Madt::FLAG_LEGACY_PIC) { 13 | x86::out1(0x21, 0xFF); 14 | x86::out1(0xA1, 0xFF); 15 | } 16 | 17 | u32 off = sizeof(acpi::Madt); 18 | u32 len = madt->hdr.length; 19 | auto ptr = reinterpret_cast(madt) + sizeof(acpi::Madt); 20 | while (off < len) { 21 | auto entry_type = ptr[0]; 22 | auto entry_len = ptr[1]; 23 | 24 | // IO APIC 25 | if (entry_type == 1) { 26 | u32 addr; 27 | u32 gsi_base; 28 | memcpy(&addr, &ptr[4], 4); 29 | memcpy(&gsi_base, &ptr[8], 4); 30 | 31 | IO_APIC.register_io_apic(addr, gsi_base); 32 | } 33 | // IO APIC irq source override 34 | else if (entry_type == 2) { 35 | u8 irq_num = ptr[3]; 36 | 37 | u32 gsi; 38 | memcpy(&gsi, &ptr[4], 4); 39 | u16 flags; 40 | memcpy(&flags, &ptr[8], 2); 41 | 42 | u8 polarity = flags & 0b11; 43 | u8 trigger = flags >> 2 & 0b11; 44 | 45 | IO_APIC.register_override(irq_num, gsi, polarity == 0b11, trigger == 0b11); 46 | } 47 | 48 | off += entry_len; 49 | ptr += entry_len; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /libs/libwindower/include/windower/windower.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/syscalls.h" 3 | #include "protocol.h" 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | typedef struct WindowerWindow { 11 | uint32_t width; 12 | uint32_t height; 13 | 14 | struct Windower* owner; 15 | void* handle; 16 | CrescentHandle fb_handle; 17 | void* fb_mapping; 18 | } WindowerWindow; 19 | 20 | typedef struct Windower { 21 | CrescentHandle control_connection; 22 | CrescentHandle event_pipe; 23 | } Windower; 24 | 25 | int windower_connect(Windower* res); 26 | void windower_destroy(Windower* windower); 27 | int windower_create_window(Windower* windower, WindowerWindow* res, uint32_t x, uint32_t y, uint32_t width, uint32_t height); 28 | 29 | void windower_window_destroy(WindowerWindow* window); 30 | int windower_window_map_fb(WindowerWindow* window); 31 | WindowerProtocolWindowEvent windower_window_wait_for_event(WindowerWindow* window); 32 | int windower_window_poll_event(WindowerWindow* window, WindowerProtocolWindowEvent* event); 33 | void windower_window_redraw(WindowerWindow* window); 34 | void windower_window_close(WindowerWindow* window); 35 | 36 | static inline void* windower_window_get_fb_mapping(WindowerWindow* window) { 37 | return window->fb_mapping; 38 | } 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /apps/evm/src/vm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/syscalls.h" 3 | #include "crescent/evm.h" 4 | #include 5 | #include 6 | 7 | struct IoRegion { 8 | uint16_t base; 9 | uint16_t size; 10 | uint32_t (*read)(void* arg, uint16_t offset, uint8_t size); 11 | void (*write)(void* arg, uint16_t offset, uint32_t value, uint8_t size); 12 | void* arg; 13 | }; 14 | 15 | struct MmioRegion { 16 | uint64_t base; 17 | uint64_t size; 18 | 19 | uint64_t (*read)(void* arg, uint64_t offset, uint8_t size); 20 | void (*write)(void* arg, uint64_t offset, uint64_t value, uint8_t size); 21 | void* arg; 22 | }; 23 | 24 | struct VirtualCpu { 25 | CrescentHandle handle; 26 | EvmGuestState* state; 27 | }; 28 | 29 | struct Vm { 30 | Vm(uint32_t* fb, uint32_t fb_size); 31 | 32 | ~Vm(); 33 | 34 | void run(); 35 | 36 | bool handle_vm_exit(VirtualCpu& vcpu); 37 | 38 | void add_io_region(IoRegion region); 39 | void add_mmio_region(MmioRegion region); 40 | 41 | void map_mem(size_t guest, void* mem, size_t size); 42 | void unmap_mem(size_t guest, size_t size); 43 | 44 | [[nodiscard]] uint32_t map_mem_alloc(void* mem, size_t size); 45 | 46 | std::vector io_regions; 47 | std::vector mmio_regions; 48 | std::vector vcpus; 49 | 50 | CrescentHandle handle {}; 51 | size_t mapped_mmio_size {}; 52 | }; 53 | 54 | extern Vm* VM; 55 | -------------------------------------------------------------------------------- /src/std/span.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cstddef.hpp" 3 | #include "initializer_list.hpp" 4 | 5 | namespace kstd { 6 | inline constexpr size_t dynamic_extent = size_t(-1); 7 | 8 | template 9 | class span { 10 | public: 11 | constexpr span() = default; 12 | template 13 | constexpr span(It first, size_t size) 14 | : _begin {first}, _size {size} {} 15 | 16 | template 17 | constexpr span(It first, It last) 18 | : _begin {first}, _size {last - first} {} 19 | 20 | constexpr span(std::initializer_list list) 21 | : _begin {list.begin()}, _size {list.size()} {} 22 | 23 | template 24 | constexpr span(const T (&arr)[N]) : _begin {&arr[0]}, _size {N} {} 25 | 26 | [[nodiscard]] constexpr const T* begin() const { 27 | return _begin; 28 | } 29 | 30 | [[nodiscard]] constexpr const T* end() const { 31 | return _begin + _size; 32 | } 33 | 34 | [[nodiscard]] constexpr size_t size() const { 35 | return _size; 36 | } 37 | 38 | [[nodiscard]] constexpr bool is_empty() const { 39 | return _size; 40 | } 41 | 42 | [[nodiscard]] constexpr const T* data() const { 43 | return _begin; 44 | } 45 | 46 | constexpr const T& operator[](size_t index) const { 47 | return _begin[index]; 48 | } 49 | 50 | private: 51 | const T* _begin; 52 | size_t _size {}; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /src/dev/net/ipv4.cpp: -------------------------------------------------------------------------------- 1 | #include "ipv4.hpp" 2 | #include "checksum.hpp" 3 | #include "cstring.hpp" 4 | #include "dhcp.hpp" 5 | #include "packet.hpp" 6 | #include "stdio.hpp" 7 | #include "tcp.hpp" 8 | #include "udp.hpp" 9 | 10 | void ipv4_process_packet(Nic& nic, ReceivedPacket& packet) { 11 | auto orig_layer1 = packet.layer1.raw; 12 | 13 | Ipv4Header hdr {}; 14 | memcpy(&hdr, orig_layer1, sizeof(Ipv4Header)); 15 | hdr.deserialize(); 16 | 17 | packet.layer1.ipv4 = hdr; 18 | 19 | if ((hdr.frag_flags & 0x1FF) || (hdr.frag_flags >> 13 & 1U << 2)) { 20 | println("[kernel][ipv4]: fragmentation is not supported"); 21 | return; 22 | } 23 | 24 | auto hdr_len = (hdr.ihl_version & 0xF) * 4; 25 | packet.layer2.raw = offset(orig_layer1, void*, hdr_len); 26 | packet.layer2_len = hdr.total_len - hdr_len; 27 | 28 | if (hdr.protocol == IpProtocol::Tcp) { 29 | tcp_process_packet(nic, packet); 30 | } 31 | else if (hdr.protocol == IpProtocol::Udp) { 32 | UdpHeader udp_hdr {}; 33 | memcpy(&udp_hdr, packet.layer2.raw, sizeof(UdpHeader)); 34 | udp_hdr.deserialize(); 35 | if (udp_hdr.dest_port == 68) { 36 | dhcp_process_packet(nic, packet); 37 | } 38 | else { 39 | udp_process_packet(nic, packet); 40 | } 41 | } 42 | } 43 | 44 | void Ipv4Header::update_checksum() { 45 | hdr_checksum = 0; 46 | Checksum sum; 47 | sum.add(this, 20); 48 | hdr_checksum = sum.get(); 49 | } 50 | -------------------------------------------------------------------------------- /src/arch/x86/dev/io_apic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mem/iospace.hpp" 3 | 4 | enum class IoApicDelivery : u8 { 5 | Fixed = 0b0, 6 | LowPrio = 0b1, 7 | Smi = 0b10, 8 | Nmi = 0b100, 9 | Init = 0b101, 10 | ExtInt = 0b111 11 | }; 12 | 13 | enum class IoApicPolarity : u8 { 14 | ActiveHigh = 0, 15 | ActiveLow = 1 16 | }; 17 | 18 | enum class IoApicTrigger : u8 { 19 | Edge = 0, 20 | Level = 1 21 | }; 22 | 23 | struct IoApicIrqInfo { 24 | IoApicDelivery delivery; 25 | IoApicPolarity polarity; 26 | IoApicTrigger trigger; 27 | u8 vec; 28 | }; 29 | 30 | class IoApicManager { 31 | public: 32 | void register_io_apic(u32 phys, u32 gsi_base); 33 | void register_override(u8 irq, u32 gsi, bool active_low, bool level_triggered); 34 | 35 | void register_irq(u32 gsi, IoApicIrqInfo info); 36 | void register_isa_irq(u32 irq, u8 vec, bool active_low = false, bool level_triggered = false); 37 | 38 | void deregister_irq(u32 gsi); 39 | void deregister_isa_irq(u32 irq); 40 | 41 | private: 42 | struct IoApic { 43 | IoSpace space {}; 44 | u32 gsi_base {}; 45 | u8 gsi_count {}; 46 | 47 | u32 read(u8 reg); 48 | void write(u8 reg, u32 value); 49 | }; 50 | IoApic io_apics[16] {}; 51 | 52 | struct Override { 53 | u32 gsi; 54 | bool used; 55 | bool active_low; 56 | bool level_triggered; 57 | }; 58 | Override overrides[16] {}; 59 | u8 io_apic_count {}; 60 | }; 61 | 62 | extern IoApicManager IO_APIC; 63 | -------------------------------------------------------------------------------- /src/mem/vmem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "double_list.hpp" 4 | #include "utils/spinlock.hpp" 5 | 6 | class VMem { 7 | public: 8 | void init(usize base, usize size, usize quantum); 9 | void destroy(bool assert_allocations); 10 | usize xalloc(usize size, usize min, usize max); 11 | void xfree(usize ptr, usize size); 12 | private: 13 | static constexpr unsigned int size_to_index(usize size); 14 | 15 | static constexpr usize FREELIST_COUNT = sizeof(void*) * 8; 16 | static constexpr usize HASHTAB_COUNT = 16; 17 | 18 | struct Segment { 19 | DoubleListHook list_hook {}; 20 | DoubleListHook seg_list_hook {}; 21 | usize base {}; 22 | usize size {}; 23 | 24 | enum class Type { 25 | Free, 26 | Used, 27 | Span 28 | } type {}; 29 | }; 30 | DoubleList freelists[FREELIST_COUNT] {}; 31 | DoubleList seg_list {}; 32 | DoubleList hash_tab[HASHTAB_COUNT] {}; 33 | Segment* free_segs {}; 34 | Segment* seg_page_list {}; 35 | usize _base {}; 36 | usize _size {}; 37 | usize _quantum {}; 38 | IrqSpinlock lock {}; 39 | 40 | Segment* seg_alloc(); 41 | void seg_free(Segment* seg); 42 | void freelist_remove(Segment* seg); 43 | void freelist_insert_no_merge(Segment* seg); 44 | void freelist_insert(Segment* seg); 45 | void hashtab_insert(Segment* seg); 46 | Segment* hashtab_remove(usize key); 47 | }; 48 | -------------------------------------------------------------------------------- /src/sched/handle_table.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/user_dev.hpp" 3 | #include "dev/evm.hpp" 4 | #include "fs/vfs.hpp" 5 | #include "sched/ipc.hpp" 6 | #include "sched/shared_mem.hpp" 7 | #include "shared_ptr.hpp" 8 | #include "sys/socket.hpp" 9 | #include "unique_ptr.hpp" 10 | #include "utils/spinlock.hpp" 11 | #include "variant.hpp" 12 | #include "vector.hpp" 13 | 14 | struct ProcessDescriptor; 15 | struct ThreadDescriptor; 16 | 17 | struct EmptyHandle {}; 18 | 19 | struct OpenFile { 20 | constexpr explicit OpenFile(kstd::shared_ptr node) : node {std::move(node)} {} 21 | 22 | kstd::shared_ptr node; 23 | uint64_t cursor {}; 24 | }; 25 | 26 | using Handle = kstd::variant< 27 | kstd::monostate, 28 | EmptyHandle, 29 | DeviceHandle, 30 | kstd::shared_ptr, 31 | kstd::shared_ptr, 32 | kstd::shared_ptr, 33 | kstd::shared_ptr, 34 | kstd::shared_ptr, 35 | kstd::shared_ptr, 36 | kstd::shared_ptr 37 | >; 38 | 39 | class HandleTable { 40 | public: 41 | kstd::optional get(CrescentHandle handle); 42 | CrescentHandle insert(Handle&& handle); 43 | bool replace(CrescentHandle replace, Handle&& with); 44 | bool remove(CrescentHandle handle); 45 | 46 | private: 47 | kstd::vector table; 48 | CrescentHandle count {}; 49 | kstd::vector free_handles; 50 | IrqSpinlock lock {}; 51 | }; 52 | -------------------------------------------------------------------------------- /libs/libc/src/stdlib.cpp: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "stdio.h" 3 | #include "sys.hpp" 4 | #include "string.h" 5 | #include 6 | 7 | namespace { 8 | struct ArenaAllocator { 9 | static void* allocate(size_t size) { 10 | size = (size + 0x1000 - 1) & ~(0x1000 - 1); 11 | void* ret = nullptr; 12 | if (sys_map(&ret, size, CRESCENT_PROT_READ | CRESCENT_PROT_WRITE)) { 13 | return nullptr; 14 | } 15 | return ret; 16 | } 17 | 18 | static void deallocate(void* ptr, size_t size) { 19 | size = (size + 0x1000 - 1) & ~(0x1000 - 1); 20 | sys_unmap(ptr, size); 21 | } 22 | }; 23 | 24 | constinit hz::slab_allocator ALLOCATOR {ArenaAllocator {}}; 25 | } 26 | 27 | void* malloc(size_t size) { 28 | return ALLOCATOR.alloc(size); 29 | } 30 | 31 | void* realloc(void* old, size_t new_size) { 32 | if (!new_size) { 33 | ALLOCATOR.free(old); 34 | return nullptr; 35 | } 36 | 37 | void* ptr = ALLOCATOR.alloc(new_size); 38 | if (!ptr) { 39 | return nullptr; 40 | } 41 | if (old) { 42 | auto old_size = ALLOCATOR.get_size_for_allocation(old); 43 | memcpy(ptr, old, new_size < old_size ? new_size : old_size); 44 | ALLOCATOR.free(old); 45 | } 46 | return ptr; 47 | } 48 | 49 | void free(void* ptr) { 50 | ALLOCATOR.free(ptr); 51 | } 52 | 53 | __attribute__((noreturn)) void exit(int status) { 54 | sys_process_exit(status); 55 | } 56 | 57 | __attribute__((noreturn)) void abort() { 58 | __builtin_trap(); 59 | } 60 | -------------------------------------------------------------------------------- /src/exe/elf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | 4 | #define EI_NIDENT 16 5 | 6 | enum class ElfType : u16 { 7 | None = 0, 8 | Rel = 1, 9 | Exec = 2, 10 | Dyn = 3 11 | }; 12 | 13 | enum class ElfMachine : u16 { 14 | X86_64 = 0x3E, 15 | AArch64 = 0xB7 16 | }; 17 | 18 | struct Elf64_Ehdr { 19 | unsigned char e_ident[EI_NIDENT]; 20 | ElfType e_type; 21 | ElfMachine e_machine; 22 | u32 e_version; 23 | u64 e_entry; 24 | u64 e_phoff; 25 | u64 e_shoff; 26 | u32 e_flags; 27 | u16 e_ehsize; 28 | u16 e_phentsize; 29 | u16 e_phnum; 30 | u16 e_shentsize; 31 | u16 e_shnum; 32 | u16 e_shstrndx; 33 | }; 34 | 35 | #define EI_MAG0 0 36 | #define EI_MAG1 1 37 | #define EI_MAG2 2 38 | #define EI_MAG3 3 39 | #define ELFMAG0 0x7F 40 | #define ELFMAG1 'E' 41 | #define ELFMAG2 'L' 42 | #define ELFMAG3 'F' 43 | 44 | #define EI_CLASS 4 45 | #define ELFCLASS32 1 46 | #define ELFCLASS64 2 47 | 48 | #define EI_DATA 5 49 | #define ELFDATA2LSB 1 50 | #define ELFDATA2MSB 2 51 | 52 | #define EI_VERSION 6 53 | #define EV_CURRENT 1 54 | 55 | enum class PhdrType : u32 { 56 | Null = 0, 57 | Load = 1, 58 | Dynamic = 2, 59 | Interp = 3, 60 | Note = 4, 61 | Shlib = 5, 62 | Phdr = 6, 63 | Tls = 7 64 | }; 65 | 66 | struct Elf64_Phdr { 67 | PhdrType p_type; 68 | u32 p_flags; 69 | u64 p_offset; 70 | u64 p_vaddr; 71 | u64 p_paddr; 72 | u64 p_filesz; 73 | u64 p_memsz; 74 | u64 p_align; 75 | }; 76 | 77 | #define PF_X 0x1 78 | #define PF_W 0x2 79 | #define PF_R 0x4 80 | -------------------------------------------------------------------------------- /src/sched/sched.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "deferred_work.hpp" 3 | #include "dev/clock.hpp" 4 | #include "double_list.hpp" 5 | #include "sched/thread.hpp" 6 | #include "types.hpp" 7 | #include "utils/spinlock.hpp" 8 | 9 | struct Cpu; 10 | struct Process; 11 | 12 | static constexpr usize SCHED_MAX_SLEEP_US = US_IN_S * 60 * 60 * 24; 13 | 14 | struct Scheduler { 15 | Scheduler(); 16 | 17 | static constexpr usize MAX_US = 50 * US_IN_MS; 18 | static constexpr usize SCHED_LEVELS = 12; 19 | 20 | void queue(Thread* thread); 21 | void update_schedule(); 22 | void do_schedule() const; 23 | 24 | void sleep(u64 ns); 25 | void yield(); 26 | 27 | void block(); 28 | void unblock(Thread* thread, bool remove_sleeping, bool assert_not_sleeping); 29 | 30 | [[noreturn]] void exit_process(int status); 31 | [[noreturn]] void exit_thread(int status); 32 | 33 | void enable_preemption(Cpu* cpu); 34 | void on_timer(Cpu* cpu); 35 | 36 | struct Level { 37 | Spinlock> list {}; 38 | usize slice_us; 39 | }; 40 | 41 | Level levels[SCHED_LEVELS] {}; 42 | 43 | Thread* prev {}; 44 | Thread* current {}; 45 | u64 current_irq_period {}; 46 | u64 us_to_next_schedule {}; 47 | DeferredIrqWork irq_work {.fn = [this]() { 48 | do_schedule(); 49 | }}; 50 | Spinlock> sleeping_threads {}; 51 | }; 52 | 53 | void sched_init(bool bsp); 54 | Thread* get_current_thread(); 55 | void set_current_thread(Thread* thread); 56 | -------------------------------------------------------------------------------- /apps/evm/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sys.h" 2 | #include "windower/windower.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace protocol = windower::protocol; 8 | 9 | #include "vga.hpp" 10 | #include "vm.hpp" 11 | 12 | int main() { 13 | windower::Windower windower; 14 | if (auto status = windower::Windower::connect(windower); status != 0) { 15 | puts("[console]: failed to connect to window manager"); 16 | return 1; 17 | } 18 | 19 | uint32_t width = 800; 20 | uint32_t height = 600; 21 | 22 | windower::Window window; 23 | if (auto status = windower.create_window(window, 0, 0, width, height); status != 0) { 24 | puts("[console]: failed to create window"); 25 | return 1; 26 | } 27 | 28 | if (window.map_fb() != 0) { 29 | puts("[console]: failed to map fb"); 30 | return 1; 31 | } 32 | auto* fb = static_cast(window.get_fb_mapping()); 33 | 34 | Vm vm {fb, (width * height * 4 + 0xFFF) & ~0xFFF}; 35 | printf("run vm\n"); 36 | vm.run(); 37 | 38 | vga_print_text_mem(fb); 39 | 40 | window.redraw(); 41 | 42 | while (true) { 43 | auto event = window.wait_for_event(); 44 | if (event.type == protocol::WindowEvent::CloseRequested) { 45 | window.close(); 46 | break; 47 | } 48 | else if (event.type == protocol::WindowEvent::Key) { 49 | printf("[evm]: received scan %u pressed %u -> %u\n", event.key.code, event.key.prev_pressed, event.key.pressed); 50 | 51 | window.redraw(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lds/x86_64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | OUTPUT_ARCH(i386:x86-64) 3 | ENTRY(_start) 4 | 5 | PHDRS { 6 | text PT_LOAD FLAGS(1 << 0 | 1 << 2); 7 | rodata PT_LOAD FLAGS(1 << 2); 8 | data PT_LOAD FLAGS(1 << 1 | 1 << 2); 9 | dynamic PT_DYNAMIC FLAGS(1 << 1 | 1 << 2); 10 | } 11 | 12 | SECTIONS { 13 | KERNEL_START = 0xFFFFFFFF80000000; 14 | . = 0xFFFFFFFF80000000; 15 | 16 | TEXT_START = .; 17 | .text : { 18 | *(.text .text.*) 19 | } :text 20 | TEXT_END = .; 21 | 22 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 23 | 24 | RODATA_START = .; 25 | .rodata : { 26 | *(.rodata .rodata.*) 27 | } :rodata 28 | .drivers : { 29 | DRIVERS_START = .; 30 | KEEP(*(.drivers)) 31 | DRIVERS_END = .; 32 | } 33 | RODATA_END = .; 34 | 35 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 36 | 37 | DATA_START = .; 38 | .data : { 39 | *(.data .data.*) 40 | } :data 41 | 42 | .dynamic : { 43 | *(.dynamic) 44 | } :data :dynamic 45 | 46 | .init_array : { 47 | INIT_ARRAY_START = .; 48 | KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))) 49 | KEEP(*(.init_array)) 50 | INIT_ARRAY_END = .; 51 | } :data 52 | 53 | .cpu_local_ctors : { 54 | CPU_LOCAL_CTORS_START = .; 55 | KEEP(*(.cpu_local_ctors)) 56 | CPU_LOCAL_CTORS_END = .; 57 | } :data 58 | 59 | .bss : { 60 | __CPU_LOCAL_START = .; 61 | *(.bss.cpu_local) 62 | __CPU_LOCAL_END = .; 63 | *(.bss .bss.*) 64 | *(COMMON) 65 | } :data 66 | DATA_END = .; 67 | 68 | /DISCARD/ : { 69 | *(.eh_frame) 70 | *(.eh_frame_hdr) 71 | *(.note .note.*) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /libs/libwindower/include/windower/protocol.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace windower::protocol { 7 | struct Request { 8 | enum { 9 | CreateWindow, 10 | CloseWindow, 11 | Redraw 12 | } type; 13 | union { 14 | struct { 15 | uint32_t x; 16 | uint32_t y; 17 | uint32_t width; 18 | uint32_t height; 19 | } create_window; 20 | 21 | struct { 22 | void* window_handle; 23 | } close_window; 24 | 25 | struct { 26 | void* window_handle; 27 | } redraw; 28 | }; 29 | }; 30 | 31 | struct Response { 32 | enum { 33 | Ack, 34 | Connected, 35 | WindowCreated 36 | } type; 37 | 38 | union { 39 | struct { 40 | CrescentHandle event_handle; 41 | } connected; 42 | 43 | struct { 44 | void* window_handle; 45 | } ack; 46 | 47 | struct { 48 | void* window_handle; 49 | CrescentHandle fb_handle; 50 | } window_created; 51 | }; 52 | }; 53 | 54 | struct WindowEvent { 55 | enum { 56 | CloseRequested, 57 | Mouse, 58 | MouseEnter, 59 | MouseLeave, 60 | Key 61 | } type; 62 | 63 | void* window_handle; 64 | 65 | union { 66 | char dummy; 67 | 68 | struct { 69 | uint32_t x; 70 | uint32_t y; 71 | bool left_pressed; 72 | bool right_pressed; 73 | bool middle_pressed; 74 | } mouse; 75 | 76 | struct { 77 | Scancode code; 78 | bool prev_pressed; 79 | bool pressed; 80 | } key; 81 | }; 82 | }; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/std/cstring.cpp: -------------------------------------------------------------------------------- 1 | #include "cstring.hpp" 2 | 3 | void* memmove(void* __restrict dest, const void* __restrict src, size_t size) { 4 | if (dest < src) { 5 | return memcpy(dest, src, size); 6 | } 7 | else { 8 | auto* dest_ptr = static_cast(dest) + size; 9 | auto* src_ptr = static_cast(src) + size; 10 | for (; size; --size) { 11 | *--dest_ptr = *--src_ptr; 12 | } 13 | return dest; 14 | } 15 | } 16 | 17 | #undef memcpy 18 | #undef memset 19 | 20 | [[gnu::weak]] void* memcpy(void* __restrict dest, const void* __restrict src, size_t size) { 21 | auto* dest_ptr = static_cast(dest); 22 | auto* src_ptr = static_cast(src); 23 | for (; size; --size) { 24 | *dest_ptr++ = *src_ptr++; 25 | } 26 | return dest; 27 | } 28 | 29 | [[gnu::weak]] void* memset(void* __restrict dest, int ch, size_t size) { 30 | auto* dest_ptr = static_cast(dest); 31 | auto c = static_cast(ch); 32 | for (; size; --size) { 33 | *dest_ptr++ = c; 34 | } 35 | return dest; 36 | } 37 | 38 | int memcmp(const void* __restrict a, const void* __restrict b, size_t size) { 39 | auto* a_ptr = static_cast(a); 40 | auto* b_ptr = static_cast(b); 41 | for (; size; --size) { 42 | auto res = *a_ptr++ - *b_ptr++; 43 | if (res != 0) { 44 | return res; 45 | } 46 | } 47 | return 0; 48 | } 49 | 50 | size_t strlen(const char* str) { 51 | size_t len = 0; 52 | while (*str++) ++len; 53 | return len; 54 | } 55 | -------------------------------------------------------------------------------- /src/sched/handle_table.cpp: -------------------------------------------------------------------------------- 1 | #include "handle_table.hpp" 2 | #include "process.hpp" 3 | 4 | kstd::optional HandleTable::get(CrescentHandle handle) { 5 | auto guard = lock.lock(); 6 | 7 | if (handle >= count) { 8 | return {}; 9 | } 10 | 11 | auto loc = table[handle]; 12 | if (loc.get()) { 13 | return {}; 14 | } 15 | return loc; 16 | } 17 | 18 | CrescentHandle HandleTable::insert(Handle&& handle) { 19 | auto guard = lock.lock(); 20 | 21 | CrescentHandle index; 22 | if (!free_handles.is_empty()) { 23 | index = free_handles.pop().value(); 24 | } 25 | else { 26 | if (count == table.size()) { 27 | auto new_size = table.size() < 8 ? 8 : (table.size() + table.size() / 2); 28 | table.resize(new_size); 29 | } 30 | index = count++; 31 | } 32 | 33 | table[index] = std::move(handle); 34 | 35 | return index; 36 | } 37 | 38 | bool HandleTable::replace(CrescentHandle replace, Handle&& with) { 39 | auto guard = lock.lock(); 40 | 41 | if (replace >= count) { 42 | return false; 43 | } 44 | 45 | auto& loc = table[replace]; 46 | if (loc.get()) { 47 | return false; 48 | } 49 | loc = std::move(with); 50 | return true; 51 | } 52 | 53 | bool HandleTable::remove(CrescentHandle handle) { 54 | auto guard = lock.lock(); 55 | 56 | if (handle >= count) { 57 | return false; 58 | } 59 | 60 | auto& loc = table[handle]; 61 | if (loc.get()) { 62 | return false; 63 | } 64 | loc = kstd::monostate {}; 65 | free_handles.push(handle); 66 | 67 | return true; 68 | } 69 | -------------------------------------------------------------------------------- /src/std/tests.cpp: -------------------------------------------------------------------------------- 1 | #include "vector.hpp" 2 | #include "vmem.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | TEST(vmem_suite, vmem_tests) { 8 | VMem vmem {}; 9 | vmem.init(0xFFFF000000000000, 0xFFFFFFFF80000000 - 0xFFFF000000000000, 0x1000); 10 | 11 | std::vector> allocations; 12 | int count = rand() % 5000; 13 | for (int i = 0; i < count; ++i) { 14 | int size = rand() % (1024 * 1024); 15 | auto mem = vmem.xalloc(size, 0, 0); 16 | EXPECT_NE(mem, 0); 17 | allocations.emplace_back(mem, size); 18 | } 19 | 20 | for (int i = 0; i < count - 2; i += 2) { 21 | auto alloc = allocations[i]; 22 | vmem.xfree(alloc.first, alloc.second); 23 | allocations[i] = {0, 0}; 24 | } 25 | 26 | for (int i = 0; i < count; ++i) { 27 | auto alloc = allocations[i]; 28 | if (alloc.first) { 29 | vmem.xfree(alloc.first, alloc.second); 30 | } 31 | } 32 | 33 | vmem.destroy(true); 34 | 35 | vmem.init(0x1000, 0x1000, 0x1000); 36 | auto ptr0 = vmem.xalloc(0x1000, 0, 0); 37 | EXPECT_EQ(ptr0, 0x1000); 38 | EXPECT_EQ(vmem.xalloc(0x1000, 0, 0), 0); 39 | vmem.xfree(ptr0, 0x1000); 40 | ptr0 = vmem.xalloc(0x1000, 0, 0); 41 | EXPECT_EQ(ptr0, 0x1000); 42 | vmem.xfree(ptr0, 0x1000); 43 | 44 | vmem.destroy(true); 45 | } 46 | 47 | TEST(memory, vector) { 48 | kstd::vector vec {}; 49 | auto count = rand() % 2000; 50 | for (int i = 0; i < count; ++i) { 51 | vec.push(i); 52 | } 53 | 54 | vec.remove(0); 55 | vec.remove(vec.size() - 1); 56 | 57 | kstd::vector other {}; 58 | other.push(10); 59 | vec = other; 60 | } 61 | -------------------------------------------------------------------------------- /src/std/limits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace kstd { 4 | template 5 | class numeric_limits; 6 | template<> 7 | class numeric_limits { 8 | public: 9 | static constexpr int digits = 1; 10 | }; 11 | template<> 12 | class numeric_limits { 13 | public: 14 | static constexpr int digits = 7; 15 | }; 16 | template<> 17 | class numeric_limits { 18 | public: 19 | static constexpr int digits = 8; 20 | }; 21 | template<> 22 | class numeric_limits { 23 | public: 24 | static constexpr int digits = 8 * sizeof(short) - 1; 25 | }; 26 | template<> 27 | class numeric_limits { 28 | public: 29 | static constexpr int digits = 8 * sizeof(short); 30 | }; 31 | template<> 32 | class numeric_limits { 33 | public: 34 | static constexpr int digits = 8 * sizeof(int) - 1; 35 | 36 | static constexpr int max = __INT_MAX__; 37 | }; 38 | template<> 39 | class numeric_limits { 40 | public: 41 | static constexpr int digits = 8 * sizeof(int); 42 | }; 43 | template<> 44 | class numeric_limits { 45 | public: 46 | static constexpr int digits = 8 * sizeof(long) - 1; 47 | }; 48 | template<> 49 | class numeric_limits { 50 | public: 51 | static constexpr int digits = 8 * sizeof(long); 52 | }; 53 | template<> 54 | class numeric_limits { 55 | public: 56 | static constexpr int digits = 8 * sizeof(long long) - 1; 57 | }; 58 | template<> 59 | class numeric_limits { 60 | public: 61 | static constexpr int digits = 8 * sizeof(long long); 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/arch/aarch64/include/arch/paging.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | #include "manually_init.hpp" 5 | #include "mem/pmalloc.hpp" 6 | 7 | constexpr usize PAGE_SIZE = 0x1000; 8 | 9 | enum class PageFlags { 10 | Read = 1 << 0, 11 | Write = 1 << 1, 12 | Execute = 1 << 2, 13 | User = 1 << 3 14 | }; 15 | 16 | enum class CacheMode { 17 | WriteBack, 18 | WriteCombine, 19 | Uncached 20 | }; 21 | 22 | constexpr PageFlags operator|(PageFlags lhs, PageFlags rhs) { 23 | return static_cast(static_cast(lhs) | static_cast(rhs)); 24 | } 25 | constexpr PageFlags& operator|=(PageFlags& lhs, PageFlags rhs) { 26 | lhs = lhs | rhs; 27 | return lhs; 28 | } 29 | constexpr bool operator&(PageFlags lhs, PageFlags rhs) { 30 | return static_cast(lhs) & static_cast(rhs); 31 | } 32 | 33 | class PageMap { 34 | public: 35 | explicit PageMap(PageMap* kernel_map); 36 | explicit PageMap(u64* early_map); 37 | ~PageMap(); 38 | 39 | [[nodiscard]] bool map_1gb(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 40 | [[nodiscard]] bool map(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 41 | void protect(u64 virt, PageFlags flags, CacheMode cache_mode); 42 | 43 | [[nodiscard]] u64 get_phys(u64 virt); 44 | 45 | void unmap(u64 virt); 46 | void use(); 47 | 48 | void fill_high_half(); 49 | 50 | constexpr bool operator==(const PageMap& other) const { 51 | return level0 == other.level0; 52 | } 53 | 54 | u64* level0; 55 | 56 | private: 57 | DoubleList used_pages {}; 58 | IrqSpinlock lock {}; 59 | }; 60 | -------------------------------------------------------------------------------- /src/arch/x86/include/arch/paging.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "optional.hpp" 4 | #include "mem/pmalloc.hpp" 5 | #include "manually_init.hpp" 6 | 7 | constexpr usize PAGE_SIZE = 0x1000; 8 | 9 | enum class PageFlags { 10 | Read = 1 << 0, 11 | Write = 1 << 1, 12 | Execute = 1 << 2, 13 | User = 1 << 3 14 | }; 15 | 16 | enum class CacheMode { 17 | WriteBack, 18 | WriteCombine, 19 | WriteThrough, 20 | Uncached 21 | }; 22 | 23 | constexpr PageFlags operator|(PageFlags lhs, PageFlags rhs) { 24 | return static_cast(static_cast(lhs) | static_cast(rhs)); 25 | } 26 | constexpr PageFlags& operator|=(PageFlags& lhs, PageFlags rhs) { 27 | lhs = lhs | rhs; 28 | return lhs; 29 | } 30 | constexpr bool operator&(PageFlags lhs, PageFlags rhs) { 31 | return static_cast(lhs) & static_cast(rhs); 32 | } 33 | 34 | class PageMap { 35 | public: 36 | explicit PageMap(PageMap* kernel_map); 37 | ~PageMap(); 38 | 39 | [[nodiscard]] bool map_2mb(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 40 | [[nodiscard]] bool map(u64 virt, u64 phys, PageFlags flags, CacheMode cache_mode); 41 | void protect(u64 virt, PageFlags flags, CacheMode cache_mode); 42 | 43 | [[nodiscard]] u64 get_phys(u64 virt); 44 | 45 | void unmap(u64 virt); 46 | void use(); 47 | 48 | constexpr bool operator==(const PageMap& other) const { 49 | return level0 == other.level0; 50 | } 51 | 52 | void fill_high_half(); 53 | 54 | [[nodiscard]] u64 get_top_level_phys() const; 55 | 56 | private: 57 | u64* level0; 58 | DoubleList used_pages {}; 59 | IrqSpinlock lock {}; 60 | }; 61 | -------------------------------------------------------------------------------- /src/dev/usb/device.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "packet.hpp" 3 | #include "mem/unique_phys.hpp" 4 | #include "expected.hpp" 5 | #include "desc.hpp" 6 | #include "vector.hpp" 7 | #include "span.hpp" 8 | 9 | namespace usb { 10 | struct Device { 11 | virtual ~Device() = default; 12 | 13 | Status control(setup::Packet setup); 14 | 15 | virtual void control_async(setup::Packet* setup) = 0; 16 | virtual bool normal_one(normal::Packet* packet) = 0; 17 | virtual usize normal_multiple(normal::Packet* packets, usize count) = 0; 18 | virtual usize normal_large(normal::LargePacket* packet) = 0; 19 | 20 | virtual Status set_config(const UniquePhysical& config) = 0; 21 | 22 | void attach(); 23 | 24 | kstd::expected get_device_descriptor(); 25 | kstd::expected get_config_descriptor(u8 index); 26 | 27 | usize max_normal_packets {}; 28 | }; 29 | 30 | struct Descriptor { 31 | u8 type; 32 | u8 length; 33 | void* data; 34 | }; 35 | 36 | struct Interface { 37 | InterfaceDescriptor desc {}; 38 | kstd::vector eps; 39 | kstd::vector descs; 40 | }; 41 | 42 | struct Config { 43 | const UniquePhysical& raw; 44 | const kstd::vector& interfaces; 45 | }; 46 | 47 | struct AssignedDevice { 48 | Device& device; 49 | kstd::vector interfaces; 50 | kstd::vector descs; 51 | void* data; 52 | u8 interface_index; 53 | 54 | [[nodiscard]] InterfaceAssocDescriptor* get_iface_assoc() const; 55 | }; 56 | 57 | namespace clazz { 58 | inline constexpr u8 WIRELESS_CONTROLLER = 0xE0; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/sched/mutex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dev/event.hpp" 3 | #include "atomic.hpp" 4 | #include "utils/irq_guard.hpp" 5 | 6 | template 7 | struct Mutex; 8 | 9 | template 10 | struct Mutex { 11 | constexpr Mutex() = default; 12 | constexpr explicit Mutex(T&& value) : value {std::move(value)} {} 13 | 14 | struct Guard { 15 | ~Guard() { 16 | owner.inner.store(false, kstd::memory_order::release); 17 | owner.unlock_event.signal_one(); 18 | } 19 | 20 | T* operator->() { 21 | return &owner.value; 22 | } 23 | 24 | T& operator*() { 25 | return owner.value; 26 | } 27 | 28 | Mutex& owner; 29 | }; 30 | 31 | Guard lock() { 32 | IrqGuard irq_guard {}; 33 | while (true) { 34 | if (!inner.exchange(true, kstd::memory_order::acquire)) { 35 | break; 36 | } 37 | unlock_event.wait(); 38 | } 39 | return {*this}; 40 | } 41 | 42 | private: 43 | friend Guard; 44 | 45 | T value; 46 | Event unlock_event {}; 47 | kstd::atomic inner {}; 48 | }; 49 | 50 | template<> 51 | struct Mutex { 52 | constexpr Mutex() = default; 53 | 54 | struct Guard { 55 | ~Guard() { 56 | owner.inner.store(false, kstd::memory_order::release); 57 | owner.unlock_event.signal_one(); 58 | } 59 | 60 | Mutex& owner; 61 | }; 62 | 63 | Guard lock() { 64 | IrqGuard irq_guard {}; 65 | while (true) { 66 | if (!inner.exchange(true, kstd::memory_order::acquire)) { 67 | break; 68 | } 69 | unlock_event.wait(); 70 | } 71 | return {*this}; 72 | } 73 | 74 | private: 75 | friend Guard; 76 | 77 | Event unlock_event {}; 78 | kstd::atomic inner {}; 79 | }; 80 | -------------------------------------------------------------------------------- /src/std/expected.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "type_traits.hpp" 3 | #include "utility.hpp" 4 | 5 | namespace kstd { 6 | template 7 | struct unexpected { 8 | T value; 9 | }; 10 | 11 | template 12 | class expected { 13 | public: 14 | constexpr expected(T&& value) // NOLINT(*-explicit-constructor) 15 | : data {.value {std::move(value)}}, success {true} {} 16 | constexpr expected(const T& value) // NOLINT(*-explicit-constructor) 17 | : data {.value {value}}, success {true} {} 18 | constexpr expected(E&& error) // NOLINT(*-explicit-constructor) 19 | : data {.error {std::move(error)}}, success {false} {} 20 | constexpr expected(const E& value) // NOLINT(*-explicit-constructor) 21 | : data {.error {value}}, success {false} {} 22 | 23 | constexpr T& value() & { 24 | return data.value; 25 | } 26 | constexpr const T& value() const & { 27 | return data.value; 28 | } 29 | 30 | constexpr T&& value() && { 31 | return std::move(data.value); 32 | } 33 | 34 | constexpr E& error() & { 35 | return data.error; 36 | } 37 | constexpr const E& error() const & { 38 | return data.error; 39 | } 40 | constexpr E&& error() && { 41 | return std::move(data.error); 42 | } 43 | 44 | constexpr explicit operator bool() const { 45 | return success; 46 | } 47 | 48 | constexpr ~expected() { 49 | if (success) { 50 | data.value.~T(); 51 | } 52 | else { 53 | data.error.~E(); 54 | } 55 | } 56 | 57 | private: 58 | union Data { 59 | constexpr ~Data() {} 60 | T value; 61 | E error; 62 | } data; 63 | bool success; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/it-compiles-test.yml: -------------------------------------------------------------------------------- 1 | name: It Compiles! 2 | on: [push, workflow_dispatch] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-24.04 6 | steps: 7 | - name: Disable initramfs update 8 | run: sudo sed -i 's/yes/no/g' /etc/initramfs-tools/update-initramfs.conf 9 | - name: Disable man-db update 10 | run: sudo rm -f /var/lib/man-db/auto-update 11 | 12 | - name: Install llvm 13 | run: | 14 | wget https://apt.llvm.org/llvm.sh 15 | chmod +x llvm.sh 16 | sudo ./llvm.sh 19 17 | sudo rm -f $(which clang) $(which clang++) 18 | sudo rm -f /usr/bin/clang /usr/bin/clang++ 19 | sudo ln -s $(which clang-19) /usr/bin/clang 20 | sudo ln -s $(which clang++-19) /usr/bin/clang++ 21 | sudo ln -s $(which llvm-objcopy-19) /usr/bin/llvm-objcopy 22 | 23 | - name: Install qpkg 24 | run: | 25 | wget https://github.com/Qwinci/qpkg/releases/latest/download/qpkg-x86_64-unknown-linux-musl.tar.gz 26 | tar -xf qpkg-x86_64-unknown-linux-musl.tar.gz 27 | sudo mv qpkg /usr/bin 28 | 29 | - name: Install dependencies 30 | run: | 31 | sudo apt-get update && sudo apt-get install make cmake ninja-build acpica-tools git -y 32 | 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | with: 36 | repository: 'Qwinci/crescent-bootstrap' 37 | submodules: true 38 | 39 | - name: Build (x86_64) 40 | run: | 41 | make ci 42 | 43 | - name: Build (Aarch64) 44 | run: | 45 | make ARCH=aarch64 ci 46 | 47 | -------------------------------------------------------------------------------- /src/dev/net/nic/virtio.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/driver.hpp" 2 | 3 | namespace virtio { 4 | struct PciCap { 5 | u8 id; 6 | u8 next; 7 | u8 len; 8 | u8 cfg_type; 9 | u8 bar; 10 | u8 index; 11 | u8 padding[2]; 12 | u32 offset; 13 | u32 length; 14 | }; 15 | 16 | static constexpr u8 TYPE_COMMON_CFG = 1; 17 | static constexpr u8 TYPE_NOTIFY_CFG = 2; 18 | static constexpr u8 TYPE_ISR_CFG = 3; 19 | static constexpr u8 TYPE_DEVICE_CFG = 4; 20 | static constexpr u8 TYPE_PCI_CFG = 5; 21 | static constexpr u8 TYPE_SHARED_MEM_CFG = 8; 22 | static constexpr u8 TYPE_VENDOR_CFG = 9; 23 | 24 | struct CommonCfg { 25 | u32 device_feature_select; 26 | u32 device_feature; 27 | u32 driver_feature_select; 28 | u32 driver_feature; 29 | u16 config_msix_vector; 30 | u16 num_queues; 31 | u8 device_status; 32 | u8 config_generation; 33 | u16 queue_select; 34 | u16 queue_size; 35 | u16 queue_msix_vector; 36 | u16 queue_enable; 37 | u16 queue_notify_off; 38 | u64 queue_desc; 39 | u64 queue_driver; 40 | u64 queue_device; 41 | u16 queue_notify_data; 42 | u16 queue_reset; 43 | }; 44 | 45 | struct NotifyCap { 46 | PciCap cap; 47 | u32 notify_off_multiplier; 48 | }; 49 | 50 | static constexpr u32 NO_VECTOR = 0xFFFF; 51 | } 52 | 53 | static InitStatus virtio_nic_init(pci::Device& device) { 54 | println("[kernel][nic]: virtio nic init"); 55 | 56 | return InitStatus::Success; 57 | } 58 | 59 | static constexpr PciDriver VIRTIO_NIC_DRIVER { 60 | .init = virtio_nic_init, 61 | .match = PciMatch::Device, 62 | .devices { 63 | {.vendor = 0x1AF4, .device = 0x1041} 64 | } 65 | }; 66 | 67 | PCI_DRIVER(VIRTIO_NIC_DRIVER); 68 | -------------------------------------------------------------------------------- /src/dev/usb/hcd/xhci/xhci_pci.cpp: -------------------------------------------------------------------------------- 1 | #include "xhci.hpp" 2 | #include "utils/driver.hpp" 3 | #include "arch/irq.hpp" 4 | 5 | namespace { 6 | void enable_irqs(void* arg, bool enable) { 7 | auto device = static_cast(arg); 8 | device->enable_irqs(enable); 9 | } 10 | 11 | bool install_irq(void* arg, IrqHandler* handler) { 12 | auto device = static_cast(arg); 13 | assert(device->alloc_irqs(1, 1, pci::IrqFlags::All)); 14 | u32 irq = device->get_irq(0); 15 | register_irq_handler(irq, handler); 16 | return true; 17 | } 18 | 19 | void uninstall_irq(void* arg, IrqHandler* handler) { 20 | auto device = static_cast(arg); 21 | deregister_irq_handler(device->get_irq(0), handler); 22 | device->free_irqs(); 23 | } 24 | } 25 | 26 | static InitStatus xhci_pci_init(pci::Device& device) { 27 | println("[kernel]: xhci pci init"); 28 | 29 | device.enable_io_space(true); 30 | device.enable_mem_space(true); 31 | device.enable_bus_master(true); 32 | 33 | IoSpace space {device.map_bar(0)}; 34 | 35 | xhci::GenericOps ops { 36 | .enable_irqs = enable_irqs, 37 | .install_irq = install_irq, 38 | .uninstall_irq = uninstall_irq, 39 | .arg = &device 40 | }; 41 | 42 | return xhci::init(ops, space); 43 | } 44 | 45 | static bool xhci_match(pci::Device& device) { 46 | auto prog = device.read(pci::common::PROG_IF); 47 | return prog >= 0x30 && prog < 0x40; 48 | } 49 | 50 | static PciDriver XHCI_DRIVER { 51 | .init = xhci_pci_init, 52 | .match = PciMatch::Class | PciMatch::Subclass, 53 | ._class = 0xC, 54 | .subclass = 0x3, 55 | .fine_match = xhci_match 56 | }; 57 | 58 | PCI_DRIVER(XHCI_DRIVER); 59 | -------------------------------------------------------------------------------- /src/fs/pipe.cpp: -------------------------------------------------------------------------------- 1 | #include "pipe.hpp" 2 | 3 | PipeVNode::PipeVNode(kstd::shared_ptr> buffer, FileFlags flags, bool reading) 4 | : VNode {flags, false}, buffer {std::move(buffer)}, reading {reading} {} 5 | 6 | kstd::optional> PipeVNode::create(usize max_size, FileFlags read_flags, FileFlags write_flags) { 7 | auto buffer = kstd::make_shared>(max_size); 8 | if (!buffer) { 9 | return {}; 10 | } 11 | 12 | PipeVNode reading {buffer, read_flags, true}; 13 | PipeVNode writing {std::move(buffer), write_flags, false}; 14 | 15 | return {{std::move(reading), std::move(writing)}}; 16 | } 17 | 18 | FsStatus PipeVNode::read(void* data, usize& size, usize offset) { 19 | if (!reading || offset) { 20 | return FsStatus::Unsupported; 21 | } 22 | 23 | if (flags & FileFlags::NonBlock) { 24 | size = buffer->read(data, size); 25 | if (!size) { 26 | return FsStatus::TryAgain; 27 | } 28 | return FsStatus::Success; 29 | } 30 | else { 31 | buffer->read_block(data, size); 32 | return FsStatus::Success; 33 | } 34 | } 35 | 36 | FsStatus PipeVNode::write(const void* data, usize& size, usize offset) { 37 | if (reading || offset) { 38 | return FsStatus::Unsupported; 39 | } 40 | 41 | if (flags & FileFlags::NonBlock) { 42 | size = buffer->write(data, size); 43 | if (!size) { 44 | return FsStatus::TryAgain; 45 | } 46 | return FsStatus::Success; 47 | } 48 | else { 49 | buffer->write_block(data, size); 50 | return FsStatus::Success; 51 | } 52 | } 53 | 54 | FsStatus PipeVNode::stat(FsStat& data) { 55 | data.size = buffer->size(); 56 | return FsStatus::Success; 57 | } 58 | -------------------------------------------------------------------------------- /src/arch/aarch64/dev/ramfb.cpp: -------------------------------------------------------------------------------- 1 | #include "ramfb.hpp" 2 | #include "arch/paging.hpp" 3 | #include "bit.hpp" 4 | #include "cstring.hpp" 5 | #include "dev/fb/fb.hpp" 6 | #include "dev/qemu/fw_cfg_aarch64.hpp" 7 | #include "mem/mem.hpp" 8 | #include "mem/pmalloc.hpp" 9 | 10 | struct [[gnu::packed]] RamfbConfig { 11 | u64 addr; 12 | u32 fourcc; 13 | u32 flags; 14 | u32 width; 15 | u32 height; 16 | u32 stride; 17 | 18 | void serialize() { 19 | addr = kstd::to_be(addr); 20 | fourcc = kstd::to_be(fourcc); 21 | flags = kstd::to_be(flags); 22 | width = kstd::to_be(width); 23 | height = kstd::to_be(height); 24 | stride = kstd::to_be(stride); 25 | } 26 | }; 27 | 28 | static constexpr u32 fourcc_code(char a, char b, char c, char d) { 29 | return a | b << 8 | c << 16 | d << 24; 30 | } 31 | 32 | static constexpr u32 DRM_FORMAT_XRGB8888 = fourcc_code('X', 'R', '2', '4'); 33 | 34 | void ramfb_init() { 35 | auto file_opt = qemu_fw_cfg_get_file("etc/ramfb"); 36 | if (!file_opt) { 37 | return; 38 | } 39 | auto file = file_opt.value(); 40 | 41 | u32 width = 1024; 42 | u32 height = 768; 43 | u32 stride = width * 4; 44 | 45 | auto addr = pmalloc((stride * height + PAGE_SIZE) / PAGE_SIZE); 46 | assert(addr); 47 | memset(to_virt(addr), 0, stride * height); 48 | 49 | RamfbConfig config { 50 | .addr = addr, 51 | .fourcc = DRM_FORMAT_XRGB8888, 52 | .flags = 0, 53 | .width = width, 54 | .height = height, 55 | .stride = stride 56 | }; 57 | config.serialize(); 58 | 59 | assert(qemu_fw_cfg_write(file, &config, sizeof(config))); 60 | 61 | BOOT_FB.initialize( 62 | addr, 63 | width, 64 | height, 65 | stride, 66 | 32U); 67 | } 68 | -------------------------------------------------------------------------------- /lds/aarch64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-littleaarch64) 2 | OUTPUT_ARCH(aarch64) 3 | ENTRY(asm_start) 4 | 5 | PHDRS { 6 | text PT_LOAD FLAGS(1 << 0 | 1 << 2); 7 | rodata PT_LOAD FLAGS(1 << 2); 8 | data PT_LOAD FLAGS(1 << 1 | 1 << 2); 9 | dynamic PT_DYNAMIC FLAGS(1 << 1 | 1 << 2); 10 | } 11 | 12 | SECTIONS { 13 | . = 0xFFFFFFFF80000000; 14 | /*. = 0x40080000;*/ 15 | KERNEL_START = .; 16 | 17 | TEXT_START = .; 18 | .text : { 19 | KEEP(*(.text.boot)) 20 | *(.text .text.*) 21 | } :text 22 | TEXT_END = .; 23 | 24 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 25 | 26 | RODATA_START = .; 27 | .rodata : { 28 | *(.rodata .rodata.*) 29 | } :rodata 30 | .drivers : { 31 | DRIVERS_START = .; 32 | KEEP(*(.drivers)) 33 | DRIVERS_END = .; 34 | } 35 | RODATA_END = .; 36 | 37 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 | 39 | DATA_START = .; 40 | .data : { 41 | *(.data .data.*) 42 | } :data 43 | 44 | .dynamic : { 45 | *(.dynamic) 46 | } :data :dynamic 47 | 48 | .init_array : { 49 | INIT_ARRAY_START = .; 50 | KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))) 51 | KEEP(*(.init_array)) 52 | INIT_ARRAY_END = .; 53 | } :data 54 | 55 | .cpu_local_ctors : { 56 | CPU_LOCAL_CTORS_START = .; 57 | KEEP(*(.cpu_local_ctors)) 58 | CPU_LOCAL_CTORS_END = .; 59 | } :data 60 | 61 | .bss : { 62 | BSS_START = .; 63 | __CPU_LOCAL_START = .; 64 | *(.bss.cpu_local) 65 | __CPU_LOCAL_END = .; 66 | *(.bss .bss.*) 67 | *(COMMON) 68 | BSS_END = .; 69 | } :data 70 | DATA_END = .; 71 | 72 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 73 | KERNEL_END = .; 74 | 75 | /DISCARD/ : { 76 | *(.eh_frame) 77 | *(.eh_frame_hdr) 78 | *(.note .note.*) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /libs/libwindower/include/windower/windower.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "crescent/syscalls.h" 3 | #include "protocol.hpp" 4 | #include 5 | 6 | namespace windower { 7 | struct Window { 8 | ~Window(); 9 | 10 | constexpr Window() = default; 11 | constexpr Window(const Window&) = delete; 12 | constexpr Window(Window&& other) { 13 | width = other.width; 14 | height = other.height; 15 | owner = other.owner; 16 | handle = other.handle; 17 | fb_handle = other.fb_handle; 18 | fb_mapping = other.fb_mapping; 19 | other.owner = nullptr; 20 | other.handle = nullptr; 21 | other.fb_handle = INVALID_CRESCENT_HANDLE; 22 | other.fb_mapping = nullptr; 23 | } 24 | 25 | constexpr Window& operator=(const Window&) = delete; 26 | constexpr Window& operator=(Window&&) = delete; 27 | 28 | int map_fb(); 29 | 30 | [[nodiscard]] constexpr void* get_fb_mapping() const { 31 | return fb_mapping; 32 | } 33 | 34 | protocol::WindowEvent wait_for_event(); 35 | 36 | void redraw(); 37 | 38 | void close(); 39 | 40 | uint32_t width {}; 41 | uint32_t height {}; 42 | private: 43 | friend struct Windower; 44 | 45 | struct Windower* owner {}; 46 | void* handle {}; 47 | CrescentHandle fb_handle = INVALID_CRESCENT_HANDLE; 48 | void* fb_mapping = nullptr; 49 | }; 50 | 51 | struct Windower { 52 | ~Windower(); 53 | 54 | static int connect(Windower& res); 55 | 56 | int create_window(Window& res, uint32_t x, uint32_t y, uint32_t width, uint32_t height); 57 | 58 | private: 59 | friend Window; 60 | 61 | CrescentHandle control_connection = INVALID_CRESCENT_HANDLE; 62 | CrescentHandle event_pipe = INVALID_CRESCENT_HANDLE; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /libs/libcxx/include/bit: -------------------------------------------------------------------------------- 1 | #ifndef _BIT_H 2 | #define _BIT_H 3 | 4 | #include 5 | 6 | namespace std { 7 | enum class endian { 8 | little = __ORDER_LITTLE_ENDIAN__, 9 | big = __ORDER_BIG_ENDIAN__, 10 | native = __BYTE_ORDER__ 11 | }; 12 | 13 | template 14 | constexpr __T byteswap(__T __value) { 15 | if constexpr (sizeof(__T) == 1) { 16 | return __value; 17 | } 18 | else if constexpr (sizeof(__T) == 2) { 19 | return __builtin_bswap16(__value); 20 | } 21 | else if constexpr (sizeof(__T) == 4) { 22 | return __builtin_bswap32(__value); 23 | } 24 | else if constexpr (sizeof(__T) == 8) { 25 | return __builtin_bswap64(__value); 26 | } 27 | else { 28 | __builtin_unreachable(); 29 | } 30 | } 31 | 32 | template 33 | constexpr __To bit_cast(const __From& __from) { 34 | return __builtin_bit_cast(__To, __from); 35 | } 36 | 37 | template 38 | constexpr __T rotl(__T __x, int __s) { 39 | constexpr auto __N = numeric_limits<__T>::digits; 40 | int __r = __s % __N; 41 | if (__r == 0) { 42 | return __x; 43 | } 44 | else if (__r > 0) { 45 | return __x << __r | (__x >> (__N - __r)); 46 | } 47 | else { 48 | __r = -__r; 49 | return __x >> __r | __x << (__N - __r); 50 | } 51 | } 52 | 53 | template 54 | constexpr __T rotr(__T __x, int __s) { 55 | constexpr auto __N = numeric_limits<__T>::digits; 56 | int __r = __s % __N; 57 | if (__r == 0) { 58 | return __x; 59 | } 60 | else if (__r > 0) { 61 | return __x >> __r | __x << (__N - __r); 62 | } 63 | else { 64 | __r = -__r; 65 | return __x << __r | (__x >> (__N - __r)); 66 | } 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/std/unique_ptr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utility.hpp" 3 | #include "assert.hpp" 4 | 5 | namespace kstd { 6 | template 7 | class unique_ptr { 8 | public: 9 | constexpr unique_ptr() = default; 10 | constexpr unique_ptr(kstd::nullptr_t) : ptr {nullptr} {} // NOLINT(*-explicit-constructor) 11 | 12 | constexpr explicit unique_ptr(T* new_ptr) { 13 | ptr = new_ptr; 14 | } 15 | 16 | template 17 | unique_ptr(unique_ptr&& other) { // NOLINT(*-explicit-constructor) 18 | ptr = other.ptr; 19 | other.ptr = nullptr; 20 | } 21 | unique_ptr(const unique_ptr&) = delete; 22 | 23 | template 24 | unique_ptr& operator=(unique_ptr&& other) { 25 | ptr = other.ptr; 26 | return *this; 27 | } 28 | 29 | constexpr unique_ptr& operator=(const unique_ptr&) = delete; 30 | 31 | constexpr T* data() { 32 | return ptr; 33 | } 34 | 35 | constexpr const T* data() const { 36 | return ptr; 37 | } 38 | 39 | constexpr explicit operator bool() const { 40 | return ptr; 41 | } 42 | 43 | constexpr T& operator*() { 44 | assert(ptr); 45 | return *ptr; 46 | } 47 | 48 | constexpr const T& operator*() const { 49 | assert(ptr); 50 | return *ptr; 51 | } 52 | 53 | constexpr T* operator->() { 54 | return ptr; 55 | } 56 | 57 | constexpr const T* operator->() const { 58 | return ptr; 59 | } 60 | 61 | ~unique_ptr() { 62 | delete ptr; 63 | } 64 | 65 | private: 66 | template 67 | friend class unique_ptr; 68 | 69 | T* ptr {}; 70 | }; 71 | 72 | template 73 | unique_ptr make_unique(Args&&... args) { 74 | return unique_ptr {new T {std::forward(args)...}}; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/dev/net/packet.cpp: -------------------------------------------------------------------------------- 1 | #include "packet.hpp" 2 | #include "mem/malloc.hpp" 3 | #include "assert.hpp" 4 | #include "new.hpp" 5 | #include "cstring.hpp" 6 | 7 | Packet::Packet(u32 size) : size {size} { 8 | data = ALLOCATOR.alloc(size); 9 | assert(data); 10 | } 11 | 12 | void Packet::add_ethernet(const Mac& src, const Mac& dest, EtherType ether_type) { 13 | ethernet = new (add_header(sizeof(EthernetHeader))) EthernetHeader { 14 | .dest = dest, 15 | .src = src, 16 | .ether_type = ether_type 17 | }; 18 | ethernet->serialize(); 19 | } 20 | 21 | void Packet::add_ipv4(IpProtocol protocol, u16 payload_size, u32 src_addr, u32 dest_addr) { 22 | Ipv4Header hdr { 23 | .ihl_version = 5 | 4 << 4, 24 | .ecn_dscp = 0, 25 | .total_len = static_cast(20 + payload_size), 26 | .ident = 0, 27 | .frag_flags = 0, 28 | .ttl = 64, 29 | .protocol = protocol, 30 | .hdr_checksum = 0, 31 | .src_addr = src_addr, 32 | .dest_addr = dest_addr 33 | }; 34 | hdr.serialize(); 35 | hdr.update_checksum(); 36 | 37 | auto* ptr = add_header(sizeof(Ipv4Header)); 38 | memcpy(ptr, &hdr, sizeof(hdr)); 39 | ipv4 = static_cast(ptr); 40 | } 41 | 42 | void Packet::add_udp(u16 src_port, u16 dest_port, u16 length) { 43 | UdpHeader hdr { 44 | .src_port = src_port, 45 | .dest_port = dest_port, 46 | .length = static_cast(8 + length), 47 | .checksum = 0 48 | }; 49 | hdr.serialize(); 50 | 51 | auto* ptr = add_header(sizeof(UdpHeader)); 52 | memcpy(ptr, &hdr, sizeof(hdr)); 53 | udp = static_cast(ptr); 54 | } 55 | 56 | void* Packet::add_header(u32 hdr_size) { 57 | auto* ptr = offset(data, void*, offset); 58 | offset += hdr_size; 59 | return ptr; 60 | } 61 | 62 | Packet::~Packet() { 63 | ALLOCATOR.free(data, size); 64 | } 65 | -------------------------------------------------------------------------------- /src/sys/service.cpp: -------------------------------------------------------------------------------- 1 | #include "service.hpp" 2 | 3 | struct Service { 4 | DoubleListHook hook {}; 5 | kstd::vector features; 6 | kstd::shared_ptr descriptor; 7 | }; 8 | 9 | namespace { 10 | Spinlock> SERVICES {}; 11 | } 12 | 13 | void service_create(kstd::vector&& features, Process* process) { 14 | auto descriptor = kstd::make_shared(process, 0); 15 | process->add_descriptor(descriptor.data()); 16 | auto* service = new Service { 17 | .features {std::move(features)}, 18 | .descriptor {std::move(descriptor)} 19 | }; 20 | IrqGuard irq_guard {}; 21 | auto guard = SERVICES.lock(); 22 | guard->push(service); 23 | process->service = service; 24 | } 25 | 26 | void service_remove(Process* process) { 27 | IrqGuard irq_guard {}; 28 | { 29 | auto proc_guard = process->service->descriptor->process.lock(); 30 | *proc_guard = nullptr; 31 | } 32 | 33 | auto guard = SERVICES.lock(); 34 | guard->remove(process->service); 35 | delete process->service; 36 | process->service = nullptr; 37 | } 38 | 39 | kstd::shared_ptr service_get(const kstd::vector& needed_features) { 40 | IrqGuard irq_guard {}; 41 | auto guard = SERVICES.lock(); 42 | for (const auto& service : *guard) { 43 | bool service_found = true; 44 | 45 | for (const auto& needed_feature : needed_features) { 46 | bool found = false; 47 | for (const auto& feature : service.features) { 48 | if (feature == needed_feature) { 49 | found = true; 50 | break; 51 | } 52 | } 53 | 54 | if (!found) { 55 | service_found = false; 56 | break; 57 | } 58 | } 59 | 60 | if (service_found) { 61 | return service.descriptor; 62 | } 63 | } 64 | 65 | return nullptr; 66 | } 67 | -------------------------------------------------------------------------------- /src/sys/posix/all.cpp: -------------------------------------------------------------------------------- 1 | #include "arch/arch_syscalls.hpp" 2 | #include "array.hpp" 3 | #include "crescent/posix_syscalls.h" 4 | #include "crescent/syscalls.h" 5 | #include "errno.hpp" 6 | 7 | void posix_mmap(SyscallFrame* frame); 8 | void posix_munmap(SyscallFrame* frame); 9 | void posix_mprotect(SyscallFrame* frame); 10 | 11 | void posix_sigprocmask(SyscallFrame* frame); 12 | void posix_sigaction(SyscallFrame* frame); 13 | void posix_sigrestore(SyscallFrame* frame); 14 | void posix_tgkill(SyscallFrame* frame); 15 | void posix_kill(SyscallFrame* frame); 16 | 17 | void posix_ppoll(SyscallFrame* frame); 18 | void posix_ioctl(SyscallFrame* frame); 19 | void posix_fcntl(SyscallFrame* frame); 20 | 21 | using Fn = void (*)(SyscallFrame* frame); 22 | 23 | #define E(num) ((num) - static_cast(SYS_POSIX_START)) 24 | 25 | static constexpr auto generate_syscall_array() { 26 | kstd::array arr {}; 27 | arr[E(SYS_POSIX_MMAP)] = posix_mmap; 28 | arr[E(SYS_POSIX_MUNMAP)] = posix_munmap; 29 | arr[E(SYS_POSIX_MPROTECT)] = posix_mprotect; 30 | arr[E(SYS_POSIX_SIGPROCMASK)] = posix_sigprocmask; 31 | arr[E(SYS_POSIX_SIGACTION)] = posix_sigaction; 32 | arr[E(SYS_POSIX_SIGRESTORE)] = posix_sigrestore; 33 | arr[E(SYS_POSIX_TGKILL)] = posix_tgkill; 34 | arr[E(SYS_POSIX_KILL)] = posix_kill; 35 | arr[E(SYS_POSIX_PPOLL)] = posix_ppoll; 36 | arr[E(SYS_POSIX_IOCTL)] = posix_ioctl; 37 | arr[E(SYS_POSIX_FCNTL)] = posix_fcntl; 38 | 39 | return arr; 40 | } 41 | 42 | #undef E 43 | 44 | constexpr auto POSIX_SYSCALL_ARRAY = generate_syscall_array(); 45 | 46 | void handle_posix_syscall(usize num, SyscallFrame* frame) { 47 | if (num - SYS_POSIX_START > 256 || !POSIX_SYSCALL_ARRAY[num - SYS_POSIX_START]) { 48 | *frame->error() = ENOSYS; 49 | return; 50 | } 51 | POSIX_SYSCALL_ARRAY[num - SYS_POSIX_START](frame); 52 | } 53 | -------------------------------------------------------------------------------- /src/utils/cpu_var.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.hpp" 3 | #include "arch/cpu.hpp" 4 | 5 | extern char __CPU_LOCAL_START[]; 6 | 7 | template 8 | struct CpuVar { 9 | struct Guard { 10 | ~Guard() { 11 | arch_enable_irqs(old); 12 | } 13 | 14 | T& get() { 15 | return *ptr; 16 | } 17 | 18 | T* operator->() { 19 | return ptr; 20 | } 21 | 22 | T& operator*() { 23 | return *ptr; 24 | } 25 | 26 | private: 27 | friend CpuVar; 28 | constexpr explicit Guard(T* ptr, bool old) : ptr {ptr}, old {old} {} 29 | T* ptr; 30 | bool old; 31 | }; 32 | 33 | Guard get() { 34 | bool old = arch_enable_irqs(false); 35 | auto ptr = __get_unsafe(); 36 | return Guard {ptr, old}; 37 | } 38 | 39 | T* __get_unsafe() { 40 | usize base; 41 | #ifdef __x86_64__ 42 | asm volatile("mov %%gs:160, %0" : "=r"(base)); 43 | #elif defined(__aarch64__) 44 | usize thread; 45 | asm volatile("mrs %0, tpidr_el1" : "=r"(thread)); 46 | base = *reinterpret_cast(thread + 136); 47 | #else 48 | #error missing architecture specific code 49 | #endif 50 | return __builtin_launder(reinterpret_cast(base + __offset)); 51 | } 52 | 53 | usize __offset; 54 | }; 55 | 56 | #define per_cpu(type, name, ctor, modifiers...) \ 57 | [[gnu::section(".bss.cpu_local")]] alignas(type) modifiers char __cpu_local_ ## name[sizeof(type)]; \ 58 | CpuVar name {sizeof(Cpu) + reinterpret_cast(&__cpu_local_ ##name) - reinterpret_cast(__CPU_LOCAL_START)}; \ 59 | [[gnu::section(".cpu_local_ctors"), gnu::used]] void (*__cpu_local_ ## name ## _ctor)() = []() { ctor(name.__get_unsafe()); } 60 | #define per_cpu_trivial(type, name, value, modifiers...) \ 61 | static_assert(__is_trivially_constructible(type)); \ 62 | per_cpu(type, name, [](void* ptr) { *__builtin_launder(static_cast(ptr)) = value; }, modifiers) 63 | -------------------------------------------------------------------------------- /libs/libwindower/include/windower/protocol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct WindowerProtocolRequest { 8 | enum { 9 | WindowerProtocolRequestCreateWindow, 10 | WindowerProtocolRequestCloseWindow, 11 | WindowerProtocolRequestRedraw 12 | } type; 13 | union { 14 | struct { 15 | uint32_t x; 16 | uint32_t y; 17 | uint32_t width; 18 | uint32_t height; 19 | } create_window; 20 | 21 | struct { 22 | void* window_handle; 23 | } close_window; 24 | 25 | struct { 26 | void* window_handle; 27 | } redraw; 28 | }; 29 | } WindowerProtocolRequest; 30 | 31 | typedef struct WindowerProtocolResponse { 32 | enum { 33 | WindowerProtocolResponseAck, 34 | WindowerProtocolResponseConnected, 35 | WindowerProtocolResponseWindowCreated 36 | } type; 37 | 38 | union { 39 | struct { 40 | CrescentHandle event_handle; 41 | } connected; 42 | 43 | struct { 44 | void* window_handle; 45 | } ack; 46 | 47 | struct { 48 | void* window_handle; 49 | CrescentHandle fb_handle; 50 | } window_created; 51 | }; 52 | } WindowerProtocolResponse; 53 | 54 | typedef struct WindowerProtocolWindowEvent { 55 | enum { 56 | WindowerProtocolWindowEventCloseRequested, 57 | WindowerProtocolWindowEventMouse, 58 | WindowerProtocolWindowEventMouseEnter, 59 | WindowerProtocolWindowEventMouseLeave, 60 | WindowerProtocolWindowEventKey 61 | } type; 62 | 63 | void* window_handle; 64 | 65 | union { 66 | char dummy; 67 | 68 | struct { 69 | uint32_t x; 70 | uint32_t y; 71 | bool left_pressed; 72 | bool right_pressed; 73 | bool middle_pressed; 74 | } mouse; 75 | 76 | struct { 77 | Scancode code; 78 | bool prev_pressed; 79 | bool pressed; 80 | } key; 81 | }; 82 | } WindowerProtocolWindowEvent; 83 | -------------------------------------------------------------------------------- /src/arch/aarch64/interrupts/irq.cpp: -------------------------------------------------------------------------------- 1 | #include "exceptions.hpp" 2 | #include "arch/aarch64/dev/gic.hpp" 3 | #include "arch/irq.hpp" 4 | #include "arch/cpu.hpp" 5 | #include "sched/sched.hpp" 6 | #include "vector.hpp" 7 | #include "stdio.hpp" 8 | 9 | namespace { 10 | ManuallyDestroy>> IRQ_HANDLERS; 11 | Spinlock IRQ_HANDLERS_LOCK {}; 12 | } 13 | 14 | void aarch64_irq_init() { 15 | IRQ_HANDLERS->resize(GIC->num_irqs); 16 | } 17 | 18 | void register_irq_handler(u32 num, IrqHandler* handler) { 19 | IrqGuard irq_guard {}; 20 | auto guard = IRQ_HANDLERS_LOCK.lock(); 21 | if (!(*IRQ_HANDLERS)[num].is_empty()) { 22 | if (!(*IRQ_HANDLERS)[num].front()->can_be_shared || !handler->can_be_shared) { 23 | return; 24 | } 25 | } 26 | (*IRQ_HANDLERS)[num].push(handler); 27 | } 28 | 29 | void deregister_irq_handler(u32 num, IrqHandler* handler) { 30 | IrqGuard irq_guard {}; 31 | auto guard = IRQ_HANDLERS_LOCK.lock(); 32 | if ((*IRQ_HANDLERS)[num].is_empty()) { 33 | return; 34 | } 35 | (*IRQ_HANDLERS)[num].remove(handler); 36 | } 37 | 38 | extern "C" [[gnu::used]] void arch_irq_handler(ExceptionFrame* frame) { 39 | IrqGuard irq_guard {}; 40 | 41 | auto num = GIC->ack(); 42 | if (num >= GIC->num_irqs) { 43 | GIC->eoi(num); 44 | return; 45 | } 46 | 47 | bool handler_found = false; 48 | { 49 | auto guard = IRQ_HANDLERS_LOCK.lock(); 50 | for (auto& handler : (*IRQ_HANDLERS)[num]) { 51 | if (handler.fn(frame)) { 52 | handler_found = true; 53 | break; 54 | } 55 | } 56 | } 57 | 58 | if (!handler_found) { 59 | println("[kernel][x86]: warning: no handler found for irq ", num); 60 | } 61 | 62 | GIC->eoi(num); 63 | 64 | auto* cpu = get_current_thread()->cpu; 65 | for (auto& work : cpu->deferred_work) { 66 | cpu->deferred_work.remove(&work); 67 | work.fn(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/arch/x86/start.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi/acpi.hpp" 2 | #include "arch/x86/dev/hpet.hpp" 3 | #include "arch/x86/dev/ps2.hpp" 4 | #include "arch/x86/dev/rtc.hpp" 5 | #include "assert.hpp" 6 | #include "cpu.hpp" 7 | #include "dev/random.hpp" 8 | #include "loader/info.hpp" 9 | #include "mod.hpp" 10 | #include "smp.hpp" 11 | 12 | [[noreturn]] void kmain(const void* initrd, usize initrd_size); 13 | 14 | extern void x86_madt_parse(); 15 | 16 | u64 arch_get_random_seed() { 17 | if (CPU_FEATURES.rdseed) { 18 | u64 seed; 19 | asm volatile("0: rdseed %0; jnc 0b" : "=r"(seed)); 20 | return seed; 21 | } 22 | else { 23 | u32 tsc_low; 24 | u32 tsc_high; 25 | asm volatile("rdtsc" : "=a"(tsc_low), "=d"(tsc_high)); 26 | return static_cast(tsc_high) << 32 | tsc_low; 27 | } 28 | } 29 | 30 | extern "C" [[noreturn, gnu::used]] void arch_start(BootInfo info) { 31 | acpi::init(info.rsdp); 32 | acpi::sleep_init(); 33 | hpet_init(); 34 | x86_smp_init(); 35 | x86_madt_parse(); 36 | x86_ps2_init(); 37 | x86_rtc_init(); 38 | 39 | Module initrd {}; 40 | assert(x86_get_module(initrd, "initramfs.tar")); 41 | 42 | if (CPU_FEATURES.rdseed) { 43 | u64 data[] { 44 | arch_get_random_seed(), 45 | arch_get_random_seed(), 46 | arch_get_random_seed(), 47 | arch_get_random_seed() 48 | }; 49 | random_add_entropy(data, 4, 256); 50 | println("[kernel][x86]: initial entropy added from rdseed"); 51 | } 52 | else if (CPU_FEATURES.rdrnd) { 53 | auto get_seed = []() { 54 | u64 seed; 55 | asm volatile("0: rdrand %0; jnc 0b" : "=r"(seed)); 56 | return seed; 57 | }; 58 | 59 | u64 data[] { 60 | get_seed(), 61 | get_seed(), 62 | get_seed(), 63 | get_seed() 64 | }; 65 | random_add_entropy(data, 4, 256); 66 | 67 | println("[kernel][x86]: initial entropy added from rdrand"); 68 | } 69 | 70 | kmain(initrd.data, initrd.size); 71 | } 72 | -------------------------------------------------------------------------------- /src/dev/clock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "double_list.hpp" 3 | #include "utils/rw_spinlock.hpp" 4 | #include "string_view.hpp" 5 | #include "types.hpp" 6 | #include "event.hpp" 7 | 8 | struct ClockSource { 9 | constexpr ClockSource(kstd::string_view name, u64 frequency) 10 | : name {name}, frequency {frequency} {} 11 | 12 | DoubleListHook hook; 13 | 14 | virtual u64 get_ns() = 0; 15 | 16 | kstd::string_view name; 17 | u64 frequency; 18 | }; 19 | 20 | struct TickSource { 21 | constexpr TickSource(kstd::string_view name, u64 max_us) : name {name}, max_us {max_us} {} 22 | 23 | virtual void oneshot(u64 us) = 0; 24 | virtual void reset() = 0; 25 | 26 | kstd::string_view name; 27 | u64 max_us; 28 | 29 | CallbackProducer callback_producer {}; 30 | }; 31 | 32 | void clock_source_register(ClockSource* source); 33 | void clock_source_deregister(ClockSource* source); 34 | 35 | void mdelay(usize ms); 36 | void udelay(usize us); 37 | 38 | extern RwSpinlock CLOCK_SOURCE; 39 | 40 | static constexpr u64 NS_IN_US = 1000; 41 | static constexpr u64 US_IN_MS = 1000; 42 | static constexpr u64 NS_IN_MS = NS_IN_US * US_IN_MS; 43 | static constexpr u64 US_IN_S = US_IN_MS * 1000; 44 | static constexpr u64 NS_IN_S = NS_IN_US * US_IN_MS * 1000; 45 | 46 | template requires requires(F f) { 47 | static_cast(f()); 48 | } 49 | inline bool with_timeout(F f, usize us) { 50 | auto guard = CLOCK_SOURCE.lock_read(); 51 | assert(guard && "no clock source available"); 52 | auto source = *guard; 53 | auto start = source->get_ns(); 54 | auto end = start + us * NS_IN_US; 55 | do { 56 | if (f()) { 57 | return true; 58 | } 59 | } while (source->get_ns() < end); 60 | return false; 61 | } 62 | 63 | inline u64 get_current_ns() { 64 | IrqGuard irq_guard {}; 65 | auto guard = CLOCK_SOURCE.lock_read(); 66 | return (*guard)->get_ns(); 67 | } 68 | -------------------------------------------------------------------------------- /src/dev/user_dev.cpp: -------------------------------------------------------------------------------- 1 | #include "user_dev.hpp" 2 | #include "event.hpp" 3 | #include "format.hpp" 4 | #include "list.hpp" 5 | #include "sched/sched.hpp" 6 | #include "sched/process.hpp" 7 | 8 | ManuallyDestroy>>> USER_DEVICES 9 | [CrescentDeviceTypeMax] {}; 10 | 11 | namespace { 12 | struct Change { 13 | ListHook hook; 14 | bool add; 15 | kstd::shared_ptr device; 16 | }; 17 | 18 | Spinlock> CHANGES[CrescentDeviceTypeMax] {}; 19 | Event CHANGE_EVENTS[CrescentDeviceTypeMax] {}; 20 | } 21 | 22 | usize user_dev_add(kstd::shared_ptr device, CrescentDeviceType type) { 23 | auto guard = USER_DEVICES[type]->lock(); 24 | auto index = guard->size(); 25 | 26 | auto* change = new Change { 27 | .hook {}, 28 | .add = true, 29 | .device {device} 30 | }; 31 | 32 | kstd::formatter fmt {device->name}; 33 | fmt << index; 34 | 35 | guard->push(std::move(device)); 36 | CHANGES[type].lock()->push(change); 37 | CHANGE_EVENTS[type].signal_one(); 38 | 39 | return index; 40 | } 41 | 42 | void user_dev_remove(usize index, CrescentDeviceType type) { 43 | auto guard = USER_DEVICES[static_cast(type)]->lock(); 44 | guard->remove(index); 45 | } 46 | 47 | int user_dev_wait_for_change(CrescentDeviceType type, CrescentDeviceChange& ret) { 48 | CHANGE_EVENTS[type].wait(); 49 | auto guard = CHANGES[type].lock(); 50 | auto* change = guard->pop_front(); 51 | assert(change); 52 | 53 | ret.type = change->add ? CrescentDeviceChangeTypeAdd : CrescentDeviceChangeTypeRemove; 54 | 55 | auto proc = get_current_thread()->process; 56 | ret.handle = proc->handles.insert(DeviceHandle {change->device}); 57 | if (ret.handle == INVALID_CRESCENT_HANDLE) { 58 | guard->push_front(change); 59 | return ERR_NO_MEM; 60 | } 61 | 62 | delete change; 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/mem/mmio.cpp: -------------------------------------------------------------------------------- 1 | #include "mmio.hpp" 2 | #include "mem.hpp" 3 | #include "sched/process.hpp" 4 | #include "vspace.hpp" 5 | 6 | MmioMem::~MmioMem() { 7 | if (virt) { 8 | for (usize i = 0; i < size; i += PAGE_SIZE) { 9 | KERNEL_PROCESS->page_map.unmap(reinterpret_cast(virt) + i); 10 | } 11 | 12 | KERNEL_VSPACE.free(virt, size); 13 | 14 | pfree(phys, ALIGNUP(size, PAGE_SIZE) / PAGE_SIZE); 15 | } 16 | } 17 | 18 | MmioMem& MmioMem::operator==(MmioMem&& other) { 19 | if (virt) { 20 | for (usize i = 0; i < size; i += PAGE_SIZE) { 21 | KERNEL_PROCESS->page_map.unmap(reinterpret_cast(virt) + i); 22 | } 23 | 24 | KERNEL_VSPACE.free(virt, size); 25 | 26 | pfree(phys, ALIGNUP(size, PAGE_SIZE) / PAGE_SIZE); 27 | } 28 | 29 | virt = other.virt; 30 | phys = other.phys; 31 | size = other.size; 32 | 33 | other.virt = nullptr; 34 | other.phys = 0; 35 | other.size = 0; 36 | 37 | return *this; 38 | } 39 | 40 | bool MmioMem::map() { 41 | assert(!virt); 42 | assert(!phys); 43 | 44 | virt = KERNEL_VSPACE.alloc(size); 45 | if (!virt) { 46 | return false; 47 | } 48 | 49 | phys = pmalloc(ALIGNUP(size, PAGE_SIZE) / PAGE_SIZE); 50 | if (!phys) { 51 | KERNEL_VSPACE.free(virt, size); 52 | virt = nullptr; 53 | return false; 54 | } 55 | 56 | for (usize i = 0; i < size; i += PAGE_SIZE) { 57 | auto status = KERNEL_PROCESS->page_map.map( 58 | reinterpret_cast(virt) + i, 59 | phys + i, 60 | PageFlags::Read | PageFlags::Write, 61 | CacheMode::WriteBack); 62 | if (!status) { 63 | for (usize j = 0; j < i; j += PAGE_SIZE) { 64 | KERNEL_PROCESS->page_map.unmap(reinterpret_cast(virt) + j); 65 | } 66 | 67 | pfree(phys, ALIGNUP(size, PAGE_SIZE) / PAGE_SIZE); 68 | KERNEL_VSPACE.free(virt, size); 69 | 70 | phys = 0; 71 | virt = nullptr; 72 | return false; 73 | } 74 | } 75 | 76 | return true; 77 | } 78 | -------------------------------------------------------------------------------- /libs/libcxx/include/array: -------------------------------------------------------------------------------- 1 | #ifndef _ARRAY_H 2 | #define _ARRAY_H 3 | 4 | #include 5 | 6 | namespace std { 7 | template 8 | struct array { 9 | using value_type = __T; 10 | using size_type = size_t; 11 | using difference_type = ptrdiff_t; 12 | using reference = value_type&; 13 | using const_reference = const value_type&; 14 | using pointer = value_type*; 15 | using const_pointer = const value_type*; 16 | using iterator = value_type*; 17 | using const_iterator = const value_type*; 18 | 19 | constexpr reference operator[](size_type __index) { 20 | return __data[__index]; 21 | } 22 | 23 | constexpr const_reference operator[](size_type __index) const { 24 | return __data[__index]; 25 | } 26 | 27 | constexpr reference front() { 28 | return __data[0]; 29 | } 30 | 31 | constexpr const_reference front() const { 32 | return __data[0]; 33 | } 34 | 35 | constexpr reference back() { 36 | return __data[_N - 1]; 37 | } 38 | 39 | constexpr const_reference back() const { 40 | return __data[_N - 1]; 41 | } 42 | 43 | constexpr __T* data() noexcept { 44 | return __data; 45 | } 46 | 47 | constexpr const __T* data() const noexcept { 48 | return __data; 49 | } 50 | 51 | constexpr iterator begin() { 52 | return __data; 53 | } 54 | 55 | constexpr const_iterator begin() const { 56 | return __data; 57 | } 58 | 59 | constexpr iterator end() { 60 | return __data + _N; 61 | } 62 | 63 | constexpr const_iterator end() const { 64 | return __data + _N; 65 | } 66 | 67 | constexpr bool empty() const { 68 | return _N; 69 | } 70 | 71 | constexpr size_type size() const { 72 | return _N; 73 | } 74 | 75 | __T __data[_N]; 76 | }; 77 | 78 | template 79 | array(__T, _Args...) -> array<__T, sizeof...(_Args) + 1>; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/sched/thread.cpp: -------------------------------------------------------------------------------- 1 | #include "thread.hpp" 2 | #include "process.hpp" 3 | #include "arch/cpu.hpp" 4 | 5 | Thread::Thread(kstd::string_view name, Cpu* cpu, Process* process, void (*fn)(void *), void *arg) 6 | : ArchThread {fn, arg, process}, name {name}, cpu {cpu}, process {process} { 7 | process->add_thread(this); 8 | } 9 | 10 | Thread::Thread(kstd::string_view name, Cpu* cpu, Process* process, const SysvInfo& sysv) 11 | : ArchThread {sysv, process}, name {name}, cpu {cpu}, process {process} { 12 | process->add_thread(this); 13 | } 14 | 15 | Thread::Thread(kstd::string_view name, Cpu* cpu, Process* process) : ArchThread {}, name {name}, cpu {cpu}, process {process} { 16 | process->add_thread(this); 17 | } 18 | 19 | void Thread::sleep_for(u64 ns) const { 20 | IrqGuard guard {}; 21 | cpu->scheduler.sleep(ns); 22 | } 23 | 24 | void Thread::yield() const { 25 | IrqGuard guard {}; 26 | cpu->scheduler.yield(); 27 | } 28 | 29 | void Thread::add_descriptor(ThreadDescriptor* descriptor) { 30 | IrqGuard irq_guard {}; 31 | descriptors.lock()->push(descriptor); 32 | } 33 | 34 | void Thread::remove_descriptor(ThreadDescriptor* descriptor) { 35 | IrqGuard irq_guard {}; 36 | descriptors.lock()->remove(descriptor); 37 | } 38 | 39 | void Thread::exit(int exit_status, ThreadDescriptor* skip_lock) { 40 | IrqGuard irq_guard {}; 41 | auto guard = descriptors.lock(); 42 | for (auto& desc : *guard) { 43 | if (&desc != skip_lock) { 44 | auto thread_guard = desc.thread.lock(); 45 | assert(thread_guard == this); 46 | *thread_guard = nullptr; 47 | } 48 | else { 49 | assert(desc.thread.get_unsafe() == this); 50 | desc.thread.get_unsafe() = nullptr; 51 | } 52 | 53 | desc.exit_status = exit_status; 54 | } 55 | guard->clear(); 56 | } 57 | 58 | ThreadDescriptor::~ThreadDescriptor() { 59 | auto guard = thread.lock(); 60 | if (guard) { 61 | (*guard)->remove_descriptor(this); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/fs/vfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "string_view.hpp" 3 | #include "shared_ptr.hpp" 4 | #include "utils/flags_enum.hpp" 5 | #include "dev/event.hpp" 6 | 7 | enum class FsStatus { 8 | Success, 9 | Unsupported, 10 | OutOfBounds, 11 | TryAgain 12 | }; 13 | 14 | enum class FileFlags { 15 | None = 0, 16 | NonBlock = 1 << 0 17 | }; 18 | 19 | FLAGS_ENUM(FileFlags); 20 | 21 | struct FsStat { 22 | usize size; 23 | }; 24 | 25 | struct DirEntry { 26 | char name[128]; 27 | usize name_len; 28 | 29 | enum class Type { 30 | File, 31 | Directory 32 | }; 33 | Type type; 34 | }; 35 | 36 | enum class PollEvent { 37 | None, 38 | In = 1 << 0, 39 | Out = 1 << 1, 40 | Hup = 1 << 2, 41 | Err = 1 << 3, 42 | UrgentOut = 1 << 4 43 | }; 44 | FLAGS_ENUM(PollEvent); 45 | 46 | struct VNode { 47 | constexpr explicit VNode(FileFlags flags, bool seekable) 48 | : seekable {seekable}, flags {flags} {} 49 | 50 | virtual ~VNode() = default; 51 | 52 | virtual kstd::shared_ptr lookup(kstd::string_view) { 53 | return nullptr; 54 | } 55 | 56 | virtual FsStatus stat(FsStat& data) { 57 | return FsStatus::Unsupported; 58 | } 59 | 60 | virtual FsStatus list_dir(DirEntry* entries, usize& count, usize& offset) { 61 | return FsStatus::Unsupported; 62 | } 63 | 64 | virtual FsStatus read(void* data, usize& size, usize offset) { 65 | return FsStatus::Unsupported; 66 | } 67 | 68 | virtual FsStatus write(const void* data, usize& size, usize offset) { 69 | return FsStatus::Unsupported; 70 | } 71 | 72 | virtual FsStatus poll(PollEvent& events) { 73 | return FsStatus::Unsupported; 74 | } 75 | 76 | Event poll_event {}; 77 | bool seekable {}; 78 | 79 | protected: 80 | FileFlags flags; 81 | }; 82 | 83 | struct Vfs { 84 | virtual kstd::shared_ptr get_root() = 0; 85 | }; 86 | 87 | kstd::shared_ptr vfs_lookup(kstd::shared_ptr start, kstd::string_view path); 88 | 89 | extern Vfs* INITRD_VFS; 90 | -------------------------------------------------------------------------------- /src/dev/fb/fb.cpp: -------------------------------------------------------------------------------- 1 | #include "fb.hpp" 2 | #include "font.hpp" 3 | #include "cstring.hpp" 4 | 5 | constexpr u32 FONT_WIDTH = 8; 6 | constexpr u32 FONT_HEIGHT = 8; 7 | constexpr u32 LINE_HEIGHT = 12; 8 | 9 | Framebuffer::Framebuffer(usize phys, u32 width, u32 height, usize pitch, u32 bpp) 10 | : phys {phys}, space {phys, pitch * height}, pitch {pitch}, width {width}, height {height}, bpp {bpp} { 11 | assert(space.map(CacheMode::WriteCombine)); 12 | LOG.lock()->register_sink(this); 13 | } 14 | 15 | void Framebuffer::write(kstd::string_view str) { 16 | for (auto c : str) { 17 | if (c == '\n') { 18 | column = 0; 19 | ++row; 20 | continue; 21 | } 22 | else if (c == '\t') { 23 | column += 4 - (column % 4); 24 | continue; 25 | } 26 | 27 | if ((column + 1) * FONT_WIDTH * scale >= width) { 28 | column = 0; 29 | ++row; 30 | } 31 | if (row * LINE_HEIGHT * scale >= height) { 32 | column = 0; 33 | row = 0; 34 | clear(); 35 | } 36 | 37 | auto* ptr = font8x8_basic[static_cast(c)]; 38 | auto start_x = column * FONT_WIDTH * scale; 39 | auto start_y = row * LINE_HEIGHT * scale; 40 | for (u32 y = 0; y < FONT_HEIGHT * scale; ++y) { 41 | auto font_row = ptr[y / scale]; 42 | for (u32 x = 0; x < FONT_WIDTH * scale; ++x) { 43 | auto* pixel_ptr = reinterpret_cast(static_cast(space.mapping()) + (start_y + y) * pitch + (start_x + x) * 4); 44 | if (font_row >> (x / scale) & 1) { 45 | *pixel_ptr = fg_color; 46 | } 47 | } 48 | } 49 | ++column; 50 | } 51 | } 52 | 53 | void Framebuffer::set_color(Color color) { 54 | switch (color) { 55 | case Color::Red: 56 | fg_color = 0xFF0000; 57 | break; 58 | case Color::White: 59 | fg_color = 0xFFFFFF; 60 | break; 61 | case Color::Reset: 62 | fg_color = 0x00FF00; 63 | break; 64 | } 65 | } 66 | 67 | void Framebuffer::clear() { 68 | memset(space.mapping(), 0, pitch * height); 69 | } 70 | 71 | ManuallyInit BOOT_FB; 72 | -------------------------------------------------------------------------------- /apps/console/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "net/dns.hpp" 2 | #include "sys.h" 3 | #include "windower/windower.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace protocol = windower::protocol; 11 | using namespace std::literals; 12 | 13 | int main() { 14 | uint32_t colors[] { 15 | 0xFF0000, 16 | 0x00FF00, 17 | 0x0000FF 18 | }; 19 | int index = 0; 20 | 21 | windower::Windower windower; 22 | if (auto status = windower::Windower::connect(windower); status != 0) { 23 | puts("[console]: failed to connect to window manager"); 24 | return 1; 25 | } 26 | windower::Window window; 27 | if (auto status = windower.create_window(window, 0, 0, 400, 300); status != 0) { 28 | puts("[console]: failed to create window"); 29 | return 1; 30 | } 31 | 32 | if (window.map_fb() != 0) { 33 | puts("[console]: failed to map fb"); 34 | return 1; 35 | } 36 | auto* fb = static_cast(window.get_fb_mapping()); 37 | for (uint32_t y = 0; y < 32; ++y) { 38 | for (uint32_t x = 0; x < 32; ++x) { 39 | fb[y * 400 + x] = colors[index]; 40 | } 41 | } 42 | 43 | window.redraw(); 44 | 45 | while (true) { 46 | auto event = window.wait_for_event(); 47 | if (event.type == protocol::WindowEvent::CloseRequested) { 48 | window.close(); 49 | break; 50 | } 51 | else if (event.type == protocol::WindowEvent::Key) { 52 | printf("[console]: received scan %u pressed %u -> %u\n", event.key.code, event.key.prev_pressed, event.key.pressed); 53 | 54 | if (!event.key.pressed) { 55 | ++index; 56 | if (index == sizeof(colors) / sizeof(*colors)) { 57 | index = 0; 58 | } 59 | for (uint32_t y = 0; y < 32; ++y) { 60 | for (uint32_t x = 0; x < 32; ++x) { 61 | fb[y * 400 + x] = colors[index]; 62 | } 63 | } 64 | } 65 | 66 | window.redraw(); 67 | } 68 | else if (event.type == protocol::WindowEvent::Mouse) { 69 | if (event.mouse.left_pressed) { 70 | printf("[console]: mouse press\n"); 71 | } 72 | } 73 | } 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /apps/evm/src/pci.cpp: -------------------------------------------------------------------------------- 1 | #include "pci.hpp" 2 | #include "vm.hpp" 3 | 4 | std::vector> PCI_DEVICES; 5 | 6 | void pci_add_device(std::unique_ptr device) { 7 | PCI_DEVICES.push_back(std::move(device)); 8 | } 9 | 10 | uint32_t pci_config_read(PciAddress addr, uint16_t offset, uint8_t size) { 11 | for (auto& dev : PCI_DEVICES) { 12 | if (dev->addr == addr) { 13 | uint32_t value = 0; 14 | memcpy(&value, dev->config.ptr.get() + offset, size); 15 | return value; 16 | } 17 | } 18 | 19 | return 0xFFFFFFFF; 20 | } 21 | 22 | void pci_config_write(PciAddress addr, uint16_t offset, uint32_t value, uint8_t size) { 23 | for (auto& dev : PCI_DEVICES) { 24 | if (dev->addr == addr) { 25 | if (offset >= 0x10 && offset <= 0x24) { 26 | uint8_t bar = (offset - 0x10) / 4; 27 | 28 | if (value == 0xFFFFFFFF) { 29 | dev->config.set_bar(bar, -dev->config.bar_sizes[bar]); 30 | return; 31 | } 32 | 33 | if (dev->config.bars[bar]) { 34 | if (dev->config.bar_allocated[bar] != (value & ~0b111)) { 35 | if (dev->config.bar_allocated[bar]) { 36 | VM->unmap_mem(dev->config.bar_allocated[bar], dev->config.bar_sizes[bar]); 37 | } 38 | 39 | VM->map_mem(value & ~0b111, dev->config.bars[bar], dev->config.bar_sizes[bar]); 40 | dev->config.bar_allocated[bar] = value & ~0b111; 41 | } 42 | } 43 | } 44 | else if (offset == 0x30) { 45 | if (value == ~0x7FFU || value == ~0U || value == ~1U) { 46 | dev->config.set_expansion_rom(-dev->config.bar_sizes[6]); 47 | return; 48 | } 49 | 50 | if (dev->config.bars[6]) { 51 | if (dev->config.bar_allocated[6] != (value & ~1)) { 52 | if (dev->config.bar_allocated[6]) { 53 | VM->unmap_mem(dev->config.bar_allocated[6], dev->config.bar_sizes[6]); 54 | } 55 | 56 | VM->map_mem(value & ~1, dev->config.bars[6], dev->config.bar_sizes[6]); 57 | dev->config.bar_allocated[6] = value & ~1; 58 | } 59 | } 60 | } 61 | 62 | memcpy(dev->config.ptr.get() + offset, &value, size); 63 | break; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/acpi/acpi.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi.hpp" 2 | #include "cstring.hpp" 3 | #include "mem/mem.hpp" 4 | #include "stdio.hpp" 5 | #include "assert.hpp" 6 | 7 | namespace acpi { 8 | struct [[gnu::packed]] Rsdt { 9 | SdtHeader hdr; 10 | u32 ptr[]; 11 | }; 12 | struct [[gnu::packed]] Xsdt { 13 | SdtHeader hdr; 14 | u64 ptr[]; 15 | }; 16 | 17 | namespace { 18 | union { 19 | Rsdt* rsdt; 20 | Xsdt* xsdt; 21 | } ROOT {}; 22 | void* GLOBAL_RSDP = nullptr; 23 | bool USE_XSDT = false; 24 | } 25 | 26 | struct [[gnu::packed]] Rsdp { 27 | char signature[8]; 28 | u8 checksum; 29 | char oem_id[6]; 30 | u8 revision; 31 | u32 rsdt_address; 32 | u32 length; 33 | u64 xsdt_address; 34 | u8 extended_checksum; 35 | u8 reserved[3]; 36 | }; 37 | 38 | Fadt* GLOBAL_FADT; 39 | 40 | void init(void* rsdp_ptr) { 41 | Rsdp* rsdp = static_cast(rsdp_ptr); 42 | GLOBAL_RSDP = rsdp; 43 | if (rsdp->revision >= 2) { 44 | ROOT.xsdt = to_virt(rsdp->xsdt_address); 45 | USE_XSDT = true; 46 | println("[acpi]: using XSDT"); 47 | } 48 | else { 49 | ROOT.rsdt = to_virt(rsdp->rsdt_address); 50 | println("[acpi]: using RSDT"); 51 | } 52 | 53 | GLOBAL_FADT = static_cast(acpi::get_table("FACP")); 54 | assert(GLOBAL_FADT); 55 | } 56 | 57 | void* get_rsdp() { 58 | return GLOBAL_RSDP; 59 | } 60 | 61 | void* get_table(const char (&signature)[5], u32 index) { 62 | #if __x86_64__ 63 | if (USE_XSDT) { 64 | u32 count = (ROOT.xsdt->hdr.length - sizeof(Xsdt)) / 8; 65 | for (u32 i = 0; i < count; ++i) { 66 | auto* hdr = to_virt(ROOT.xsdt->ptr[i]); 67 | if (memcmp(hdr->signature, signature, 4) == 0 && index-- == 0) { 68 | return hdr; 69 | } 70 | } 71 | } 72 | else { 73 | u32 count = (ROOT.rsdt->hdr.length - sizeof(Rsdt)) / 4; 74 | for (u32 i = 0; i < count; ++i) { 75 | auto* hdr = to_virt(ROOT.rsdt->ptr[i]); 76 | if (memcmp(hdr->signature, signature, 4) == 0 && index-- == 0) { 77 | return hdr; 78 | } 79 | } 80 | } 81 | #endif 82 | 83 | return nullptr; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /libs/libcxx/include/memory: -------------------------------------------------------------------------------- 1 | #ifndef _MEMORY_H 2 | #define _MEMORY_H 3 | 4 | #include 5 | 6 | namespace std { 7 | template 8 | class unique_ptr { 9 | public: 10 | constexpr unique_ptr() noexcept = default; 11 | constexpr unique_ptr(const unique_ptr&) = delete; 12 | 13 | constexpr unique_ptr(__T* __pointer) { 14 | __ptr = __pointer; 15 | } 16 | 17 | template 18 | constexpr unique_ptr(unique_ptr<__U>&& __other) { 19 | __ptr = __other.__ptr; 20 | __other.__ptr = nullptr; 21 | } 22 | 23 | constexpr unique_ptr(unique_ptr&& __other) { 24 | __ptr = __other.__ptr; 25 | __other.__ptr = nullptr; 26 | } 27 | 28 | constexpr ~unique_ptr() { 29 | if (__ptr) { 30 | delete __ptr; 31 | } 32 | } 33 | 34 | constexpr unique_ptr& operator=(unique_ptr&& __other) noexcept { 35 | if (__ptr) { 36 | delete __ptr; 37 | } 38 | __ptr = __other.__ptr; 39 | __other.__ptr = nullptr; 40 | return *this; 41 | } 42 | 43 | template 44 | constexpr unique_ptr& operator=(unique_ptr<__U>&& __other) noexcept { 45 | if (__ptr) { 46 | delete __ptr; 47 | } 48 | __ptr = __other.__ptr; 49 | __other.__ptr = nullptr; 50 | return *this; 51 | } 52 | 53 | constexpr unique_ptr& operator=(const unique_ptr&) = delete; 54 | 55 | constexpr __T& operator*() { 56 | return *__ptr; 57 | } 58 | 59 | constexpr const __T& operator*() const { 60 | return *__ptr; 61 | } 62 | 63 | constexpr __T* operator->() { 64 | return __ptr; 65 | } 66 | 67 | constexpr const __T* operator->() const { 68 | return __ptr; 69 | } 70 | 71 | constexpr __T* get() { 72 | return __ptr; 73 | } 74 | 75 | constexpr const __T* get() const { 76 | return __ptr; 77 | } 78 | 79 | constexpr operator bool() const { 80 | return __ptr; 81 | } 82 | 83 | __T* __ptr {}; 84 | }; 85 | 86 | template 87 | constexpr unique_ptr<__T> make_unique(__Args&&... __args) { 88 | return unique_ptr<__T> {new __T {forward<__Args>(__args)...}}; 89 | } 90 | } 91 | 92 | #endif 93 | --------------------------------------------------------------------------------