├── .github └── workflows │ └── formatter.yml ├── .vscode ├── c_cpp_properties.json ├── launch.json └── settings.json ├── Makefile ├── README.md ├── assets └── pEpitOS-logo-1.bmp └── src ├── .gitignore ├── Makefile ├── arch └── x86_64 │ ├── include │ ├── SMP │ │ └── SMP.h │ ├── UEFI │ │ ├── ACPI.h │ │ ├── APIC.h │ │ ├── RSDT.h │ │ ├── UEFI.h │ │ └── hpet.h │ ├── arch │ │ ├── arch.h │ │ └── archtypes.h │ ├── intel │ │ ├── asm.h │ │ ├── cpuinfo.h │ │ ├── registers.h │ │ ├── simd.h │ │ └── tss.h │ ├── interrupts │ │ ├── defined_interrupts.h │ │ ├── kernel_exceptions.h │ │ └── stackframe.h │ ├── pmm │ │ └── pmm.h │ ├── serial │ │ └── com.h │ ├── syscall-enabling │ │ └── syscall.h │ ├── tables │ │ ├── gdt.h │ │ ├── idt.h │ │ └── tables.h │ ├── thirdparties │ │ ├── stivale2.h │ │ └── stivalemgr.h │ └── vmm │ │ └── vmm.h │ ├── link.ld │ └── src │ ├── apic.c │ ├── arch.c │ ├── cpuinfo.c │ ├── entry.s │ ├── gdt.c │ ├── hpet.c │ ├── idt.c │ ├── kernel_exceptions.c │ ├── pmm.c │ ├── rsdt.c │ ├── serial.c │ ├── smp.c │ ├── stubs.s │ ├── syscall.c │ ├── syscall_stub.s │ ├── tagmgr.c │ ├── tasking.c │ └── vmm.c ├── limine.cfg └── pEpitOS-kernel ├── include ├── alloc │ ├── alloc.h │ └── liballoc.h ├── freestanding.h ├── init │ └── initfs.h ├── interface_struct │ └── interface_struct.h ├── log │ └── log.h ├── memory │ └── vmmwrapper.h ├── multicore │ ├── common_locks.h │ ├── cpu.h │ ├── interrupt_lock.h │ └── lock.h ├── scheduler │ └── scheduler.h ├── syscall │ └── syscall.h ├── tasking │ └── tasking.h ├── tests │ └── tests.h └── utils │ ├── functions.h │ ├── macros.h │ └── utils.h ├── src ├── alloc.c ├── common_locks.c ├── initfs.c ├── interrupt_lock.c ├── main.c ├── scheduler.c ├── syscall_handler.c ├── tasking.c ├── tests.c ├── utils │ ├── alloc │ │ ├── liballoc.c │ │ └── pEpitOS-liballoc.c │ ├── gcc │ │ └── memory.c │ ├── io │ │ └── print.c │ └── string │ │ ├── convert.c │ │ └── string.c └── vmmwrapper.c └── userspace ├── Makefile ├── link.ld └── tid0.c /.github/workflows/formatter.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: clang-format Code Formatter 3 | jobs: 4 | lint: 5 | name: clang-format Code Formatter 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Clang Code Formatter 9 | uses: antoinealb/clang-format-action@clang9 10 | env: 11 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 12 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | /*{ 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${default}", 7 | "${workspaceFolder}/arch/x86_64/include/", 8 | "${workspaceFolder}/arch/x86_64/include/*" 9 | ], 10 | "defines": [], 11 | "cStandard": "gnu11", 12 | "intelliSenseMode": "clang-x64", 13 | "compilerPath": "/usr/bin/gcc-9", 14 | "browse": { 15 | "path": ["${workspaceFolder}", "${workspaceFolder}/arch/x86_64/include", "${default}"], 16 | "limitSymbolsToIncludedHeaders": true, 17 | "databaseFilename": "" 18 | } 19 | } 20 | ], 21 | "version": 4 22 | }*/{ 23 | "configurations": [ 24 | { 25 | "name": "Linux", 26 | "includePath": [ 27 | "${default}", 28 | "${workspaceFolder}/src/arch/x86_64/include", 29 | "${workspaceFolder}/src/pEpitOS-kernel", 30 | "${workspaceFolder}/src/pEpitOS-kernel/include" 31 | ], 32 | "defines": [], 33 | "compilerPath": "/usr/bin/gcc-9", 34 | "cStandard": "c17" 35 | } 36 | ], 37 | "version": 4 38 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(gdb) Lancer", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/arch/x86_64/pEpitOS.elf", 12 | "miDebuggerServerAddress": "localhost:9000", 13 | "args": [], 14 | "stopAtEntry": false, 15 | "cwd": "${workspaceFolder}", 16 | "environment": [], 17 | "externalConsole": true, 18 | "MIMode": "gdb", 19 | "setupCommands": [ 20 | { 21 | "description": "Activer l'impression en mode Pretty pour gdb", 22 | "text": "-enable-pretty-printing", 23 | "ignoreFailures": true 24 | } 25 | ] 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.s": "platformio-debug.asm", 4 | "queue": "cpp", 5 | "pmm.h": "c", 6 | "vmm.h": "c", 7 | "stdatomic.h": "c", 8 | "locks.h": "c", 9 | "scheduler.C": "cpp", 10 | "arch.h": "c" 11 | } 12 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARCH=x86_64 2 | TARGET=NODEBUG 3 | 4 | all: 5 | @$(MAKE) $(TARGET) -C src -s 6 | @#@$(MAKE) clean -s 7 | 8 | clean: 9 | @$(MAKE) clean -C src -s -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pEpitOS 2 | 3 | pEpitOS is a microkernel under development for amd64. A previous version for i386 is on my gitlab. 4 | 5 | ## Note 6 | 7 | This project is a work in progress. We haven't reached userspace yet, it's our current objective. We finished the arch initialization process. -------------------------------------------------------------------------------- /assets/pEpitOS-logo-1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaemonOnUnix/pEpitOS-x86_64/8a0bd155e7ea7c8b3d6ebebacd5b567353716208/assets/pEpitOS-logo-1.bmp -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | limine/ 2 | 3 | log.txt 4 | 5 | build/ 6 | *.elf 7 | *.iso 8 | 9 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | KERNEL := pEpitOS 2 | 3 | ARCH = x86_64 4 | ARCH_FOLDER = arch 5 | 6 | KERNEL_DIR = pEpitOS-kernel 7 | 8 | CC = gcc-9 9 | LOGS = #-DAPIC_DEBUG -DVMM_DEBUG -DPMM_DEBUG -DIDT_DEBUG -DGDT_DEBUG 10 | CFLAGS = -Wall -Wextra -Ofast -DPTESTS -I$(ARCH_FOLDER)/$(ARCH)/include/ -I$(KERNEL_DIR)/include/ $(LOGS) -g 11 | 12 | ASMPARAM = -f elf64 -F dwarf 13 | 14 | BUILD = build 15 | 16 | ASSETS = ../assets/ 17 | LOGO = $(ASSETS)/pEpitOS-logo-1.bmp 18 | 19 | RAMDISK = pEpitOS-kernel/userspace/build 20 | 21 | ISO_FILES = $(KERNEL).elf limine.cfg limine/limine.sys limine/limine-cd.bin limine/limine-eltorito-efi.bin $(LOGO) $(RAMDISK) 22 | 23 | CORE_NUM = 4 24 | 25 | LINK_SCRIPT = $(ARCH_FOLDER)/$(ARCH)/link.ld 26 | 27 | INTERNALLDFLAGS := \ 28 | -nostdlib \ 29 | -T$(LINK_SCRIPT) \ 30 | -z max-page-size=0x1000\ 31 | #-Wl,-static,-pie,--no-dynamic-linker,-ztext -fno-pic -fpie 32 | 33 | INTERNALCFLAGS := \ 34 | -std=gnu17 \ 35 | -ffreestanding \ 36 | -fno-stack-protector \ 37 | -fno-pic -fno-pie \ 38 | -mno-red-zone \ 39 | -mno-sse \ 40 | -fno-zero-initialized-in-bss \ 41 | -mcmodel=kernel \ 42 | -fno-isolate-erroneous-paths-attribute \ 43 | -fno-delete-null-pointer-checks \ 44 | -masm=intel \ 45 | -m64 46 | 47 | SRCDIRS := $(shell find ./$(ARCH_FOLDER)/$(ARCH) -type d) 48 | SRCDIRS += $(shell find ./$(KERNEL_DIR) -type d) 49 | 50 | CFILES := $(shell find ./$(ARCH_FOLDER)/$(ARCH) -type f -name '*.c') 51 | SFILES := $(shell find ./$(ARCH_FOLDER)/$(ARCH) -type f -name '*.s') 52 | 53 | CFILES += $(shell find ./$(KERNEL_DIR) -type f -name '*.c') 54 | SFILES += $(shell find ./$(KERNEL_DIR) -type f -name '*.s') 55 | 56 | OBJ := $(SFILES:%.s=$(BUILD)/%.o) 57 | OBJ += $(CFILES:%.c=$(BUILD)/%.o) 58 | 59 | QEMU = qemu-system-x86_64 60 | QEMU_PARAMS_NODEBUG = -no-reboot -vga std -D ./log.txt -d int,guest_errors -m 512M -boot d -M q35 -serial mon:stdio -m 1G -smp $(CORE_NUM) -cdrom 61 | QEMU_PARAMS_DEBUG = -S -gdb tcp::9000 62 | 63 | $(shell mkdir -p $(addprefix $(BUILD)/,$(SRCDIRS))) 64 | 65 | all: NODEBUG 66 | 67 | .PHONY: all clean NODEBUG DEBUG clean_deps ramdisk 68 | 69 | NODEBUG: $(KERNEL).iso 70 | @$(QEMU) $(QEMU_PARAMS_NODEBUG) $< 71 | 72 | DEBUG: $(KERNEL).iso 73 | @$(QEMU) $(QEMU_PARAMS_DEBUG) $(QEMU_PARAMS_NODEBUG) $< 74 | 75 | $(KERNEL).iso: ramdisk $(KERNEL).elf limine/Makefile 76 | @mkdir -p iso_root 77 | @cp -v -r $(ISO_FILES) iso_root/ 78 | @xorriso -as mkisofs -b limine-cd.bin \ 79 | -no-emul-boot -boot-load-size 4 -boot-info-table \ 80 | -eltorito-alt-boot -e limine-eltorito-efi.bin \ 81 | -no-emul-boot iso_root -o $(KERNEL).iso 82 | @rm -rf iso_root 83 | 84 | $(KERNEL).elf: $(OBJ) 85 | @ld $(INTERNALLDFLAGS) $(OBJ) -o $@ 86 | 87 | limine/Makefile: 88 | @git clone https://github.com/limine-bootloader/limine.git --branch=v2.0-branch-binary --depth=1 89 | @make -C limine 90 | 91 | $(BUILD)/%.o: %.c 92 | @$(CC) -o $@ $(CFLAGS) $(INTERNALCFLAGS) -c $< 93 | 94 | $(BUILD)/%.o: %.s 95 | @nasm $(ASMPARAM) -o $@ $< 96 | 97 | ramdisk: 98 | @make -C pEpitOS-kernel/userspace 99 | 100 | clean: 101 | @rm -rf $(KERNEL).elf $(OBJ) image.hdd $(KERNEL).iso $(BUILD) log.txt iso_root 102 | @make -C pEpitOS-kernel/userspace clean 103 | 104 | clean_deps: clean 105 | @rm -rf limine 106 | -------------------------------------------------------------------------------- /src/arch/x86_64/include/SMP/SMP.h: -------------------------------------------------------------------------------- 1 | #ifndef SMP_H 2 | #define SMP_H 3 | 4 | #include "freestanding.h" 5 | 6 | uint8_t get_core_id_cpuid(); 7 | void _start_core(); 8 | void launch_APs(struct stivale2_struct_tag_smp* smp_infos, void (*launching_addresses[])()); 9 | bool is_smp_active(); 10 | uint32_t get_core_id_(uint32_t* lapic_id); 11 | uint32_t get_core_id(); 12 | void set_core_id(uint32_t lapic_id); 13 | uint8_t get_booted_cpus_count(); 14 | 15 | #define COREID (get_core_id()) 16 | 17 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/UEFI/ACPI.h: -------------------------------------------------------------------------------- 1 | #ifndef UEFI_ACPI_H 2 | #define UEFI_ACPI_H 3 | 4 | #include "freestanding.h" 5 | 6 | typedef struct { 7 | char Signature[4]; 8 | uint32_t Length; 9 | uint8_t Revision; 10 | uint8_t Checksum; 11 | char OEMID[6]; 12 | char OEMTableID[8]; 13 | uint32_t OEMRevision; 14 | uint32_t CreatorID; 15 | uint32_t CreatorRevision; 16 | } PACKED ACPISDTHeader; 17 | 18 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/UEFI/APIC.h: -------------------------------------------------------------------------------- 1 | #ifndef UEFI_APIC_H 2 | #define UEFI_APIC_H 3 | 4 | #include "freestanding.h" 5 | 6 | #define APIC_REGISTER_TIMER_DIV 0x3e0 7 | #define APIC_REGISTER_TIMER_INITCNT 0x380 8 | #define APIC_REGISTER_LVT_TIMER 0x320 9 | #define APIC_REGISTER_TIMER_CURRCNT 0x390 10 | #define APIC_LVT_INT_MASKED (1 << 16) 11 | 12 | uint32_t cpuReadLAPIC(uint32_t reg); 13 | void cpu_send_EOI(); 14 | void init_APIC_timer(); 15 | void init_APIC_interrupt(); 16 | void map_pics(); 17 | 18 | typedef struct { 19 | uint8_t vector_number : 8; 20 | uint8_t destination_mode : 3; 21 | uint8_t is_destination_log : 1; 22 | uint8_t delivery_status : 1; 23 | uint8_t reserved_1 : 1; 24 | uint8_t INIt_level : 2; 25 | uint8_t destination_type : 2; 26 | uint16_t reserved_2 : 12; 27 | } PACKED interrupt_message; 28 | 29 | typedef union { 30 | interrupt_message bitfield; 31 | uint32_t value; 32 | } int_message; 33 | 34 | void send_interrupt_to_core(uint8_t core_number, uint8_t interrupt_number); 35 | 36 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/UEFI/RSDT.h: -------------------------------------------------------------------------------- 1 | #ifndef UEFI_RSDT_H 2 | #define UEFI_RSDT_H 3 | 4 | #include "freestanding.h" 5 | #include "ACPI.h" 6 | 7 | #define MADT_ENTRY_START 0x2c 8 | #define MAX_CORE 16 9 | typedef struct { 10 | char Signature[8]; 11 | uint8_t Checksum; 12 | char OEMID[6]; 13 | uint8_t Revision; 14 | uint32_t RsdtAddress; 15 | } PACKED RSDPDescriptor; 16 | 17 | typedef struct { 18 | RSDPDescriptor firstPart; 19 | uint32_t Length; 20 | uint64_t XsdtAddress; 21 | uint8_t ExtendedChecksum; 22 | uint8_t reserved[3]; 23 | } PACKED RSDPDescriptor20; 24 | 25 | typedef struct { 26 | ACPISDTHeader h; 27 | uint32_t PointersToOtherSDT[]; 28 | } PACKED RSDT; 29 | 30 | typedef struct{ 31 | ACPISDTHeader h; 32 | uint32_t lapic_addr; 33 | uint32_t flags; 34 | } PACKED MADT; 35 | 36 | typedef enum{ 37 | MADT_LAPIC = 0, 38 | MADT_IOAPIC, 39 | MADT_INT_SRC_OVR, 40 | MADT_NMSK_INT_SRC, 41 | MADT_LAPIC_NNMI, 42 | MADT_LAPIC_ADDR_OVR, 43 | MADT_IOSAPIC, 44 | MADT_LOC_SAPIC, 45 | MADT_PLT_INT_SRC, 46 | MADT_L2APIC 47 | } MADT_ENTRY; 48 | 49 | typedef struct { 50 | RSDPDescriptor20* rsdp; 51 | RSDT* rsdt; 52 | MADT* madt; 53 | } uefi_tables; 54 | 55 | 56 | typedef struct{ 57 | char id; 58 | uint32_t address; 59 | uint32_t base; 60 | size_t max_redirection; 61 | } ioapic_entry_t; 62 | 63 | 64 | typedef struct{ 65 | char bus; 66 | char irq; 67 | uint32_t global_system_interrupt; 68 | uint16_t flags; 69 | } PACKED interrupt_source_override; 70 | 71 | typedef struct { 72 | uint8_t ACPI_processor_id; 73 | uint16_t flags; 74 | uint8_t LINT; 75 | }PACKED LAPIC_NMI; 76 | 77 | typedef struct { 78 | char ACPI_Processor_id; 79 | char ACPI_id; 80 | uint32_t flags; 81 | } PACKED madt_lapic_entry_t; 82 | 83 | typedef struct { 84 | size_t numcore; 85 | madt_lapic_entry_t lapics[MAX_CORE]; 86 | uint64_t lapic_address; 87 | ioapic_entry_t ioapic; 88 | interrupt_source_override interrupt[MAX_CORE]; 89 | size_t interrupt_count; 90 | size_t nmi_count; 91 | LAPIC_NMI nmis[10]; 92 | } apic_info_t; 93 | 94 | typedef struct { 95 | uint8_t interrupt_vector; 96 | char delivery_mode :2; 97 | char destination :1; 98 | char going_to_be_send : 1; 99 | char polarity : 1; 100 | char level_trigger : 1; 101 | char trigger_mode : 1; 102 | char mask : 1; 103 | }PACKED redirection_entry_pt1; 104 | 105 | 106 | 107 | #define LAPIC_LENGTH 0x1000 108 | #define IOAPIC_LENGTH 0x1000 109 | #define IOAPIC_REDIRECTION_OFFSET 0x10 110 | 111 | 112 | #define SPURIOUS_VECTOR_REGISTER 0xf0 113 | #define SPURIOUS_ALL 0Xff 114 | #define SPURIOUS_ENABLE_BIT 0x100 115 | 116 | 117 | void parse_RSDP(uint64_t rsdp_address); 118 | void parse_RSDT(); 119 | void enable_APIC(); 120 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/UEFI/UEFI.h: -------------------------------------------------------------------------------- 1 | #ifndef UEFI_H 2 | #define UEFI_H 3 | 4 | #include "ACPI.h" 5 | #include "RSDT.h" 6 | #include "hpet.h" 7 | 8 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/UEFI/hpet.h: -------------------------------------------------------------------------------- 1 | #ifndef UEFI_HPET_H 2 | #define UEFI_HPET_H 3 | 4 | #include "freestanding.h" 5 | #include "ACPI.h" 6 | 7 | typedef struct{ 8 | uint8_t address_space_id; 9 | uint8_t register_bit_width; 10 | uint8_t register_bit_offset; 11 | uint8_t reserved; 12 | uint64_t address; 13 | }PACKED HPET_address; 14 | 15 | typedef struct{ 16 | ACPISDTHeader h; 17 | uint8_t revision_id; 18 | uint8_t comparator_count : 5; 19 | uint8_t counter_size : 1; 20 | uint8_t reserved : 1; 21 | uint8_t legacy_replacement_irq : 1; 22 | uint16_t pci_vendor_id; 23 | HPET_address address_base; 24 | char hpet_number; 25 | uint16_t main_counter_minimum; 26 | uint8_t page_protection; 27 | } PACKED HPET; 28 | 29 | 30 | #define HPET_General_Configuration 0x10 31 | #define HPET_Main_Counter_Value 0xf0 32 | 33 | void hpet_init(HPET* hpet); 34 | void hpet_reset(); 35 | void hpet_wait(size_t ms); 36 | size_t hpet_ms_to_tick(size_t ms); 37 | void hpet_wait_tick(size_t tick); 38 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/arch/arch.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H 2 | #define ARCH_H 3 | 4 | #define X86_64 1 5 | 6 | #define MULTIBOOT1 0 7 | #define MULTIBOOT2 0 8 | #define TOMATOBOOT 0 9 | #define STIVALE1 0 10 | #define STIVALE2 1 11 | 12 | #include "freestanding.h" 13 | #include "serial/com.h" 14 | #include "thirdparties/stivale2.h" 15 | #include "interrupts/stackframe.h" 16 | #include "SMP/SMP.h" 17 | #include "UEFI/APIC.h" 18 | #include "tables/idt.h" 19 | #include "pmm/pmm.h" 20 | #include "interface_struct/interface_struct.h" 21 | 22 | #define STRINGIFY(...) #__VA_ARGS__ 23 | 24 | // 25 | // virtual memory interface section 26 | // 27 | 28 | /** 29 | * @brief Type for a mapping, for instance a page directory 30 | */ 31 | typedef uint64_t mapping_t; 32 | 33 | /** 34 | * @brief Function to enable a virtual memory mapping 35 | */ 36 | void enable_mapping(mapping_t); 37 | 38 | /** 39 | * @brief Get the current mapping, such as top page level in case of paging 40 | * 41 | * @return mapping_t The interface object describing the mapping, a.d. in arch.h 42 | */ 43 | mapping_t get_current_mapping(); 44 | 45 | /** 46 | * @brief Function to be called each time a virtual memory mapping 47 | * will be created 48 | */ 49 | #define initialize_mapping() map_pics() 50 | 51 | /** 52 | * @brief Gets the first valid address according to arch setup. 53 | */ 54 | #define GET_FIRST_VALID_ADDRESS() (1ull<<40) 55 | 56 | // 57 | // Interrupts interface section 58 | // 59 | 60 | /** 61 | * @brief Type for an interrupt number 62 | */ 63 | typedef int8_t interrupt_t; 64 | 65 | /** 66 | * @brief Type for a stackframe pushed by interrupt handler 67 | */ 68 | #define stackframe stackframe 69 | 70 | /** 71 | * @brief Function to enable interrupts 72 | */ 73 | void enable_ints(); 74 | 75 | /** 76 | * @brief Function to disable interrupts 77 | */ 78 | void disable_ints(); 79 | 80 | /** 81 | * @brief Macro to trigger a specified interrupt number. 82 | * @warning Number should be compile-time. 83 | */ 84 | #define trigger_int(x) asm volatile("int " STRINGIFY(x)) 85 | 86 | /** 87 | * @brief Function ro register an interrupt handler 88 | */ 89 | #define register_custom_int(num, handler) attach_isr(num, handler) 90 | 91 | // 92 | // Multicore section 93 | // 94 | 95 | /** 96 | * @brief Type for a core ID 97 | */ 98 | typedef uint8_t core_id_t; 99 | 100 | #ifndef COREID 101 | /** 102 | * @brief Macro to get the current core ID 103 | */ 104 | #define COREID 105 | #endif 106 | 107 | /** 108 | * @brief Function to get the multicore status of the whole system 109 | */ 110 | #define is_multicore() is_smp_active() 111 | 112 | /** 113 | * @brief A maximum core number, used by static arrays for shared memory 114 | * 115 | */ 116 | #define ARCH_MAX_CORE_NUM 32 117 | 118 | // 119 | // Tasking section 120 | // 121 | 122 | /** 123 | * @brief Type for a context saving 124 | */ 125 | typedef context_save context_save; 126 | 127 | /** 128 | * @brief Member name in the latter type for the stack frame 129 | */ 130 | #define stack_frame stack_save 131 | 132 | /** 133 | * @brief Member name in the latter type for the other saves 134 | */ 135 | #define other_frame simd_save 136 | 137 | // 138 | // Register section (in stackframe) 139 | // 140 | 141 | /** 142 | * @brief Macro for instruction pointer 143 | */ 144 | #define ip rip 145 | 146 | /** 147 | * @brief Macro for stack pointer 148 | */ 149 | #define sp rsp 150 | 151 | /** 152 | * @brief Macro for return stack pointer 153 | */ 154 | #define ret_sp useresp 155 | 156 | 157 | /// 158 | /// Bootstraps section 159 | /// 160 | 161 | /** 162 | * @brief First function to be called after passing hand to kernel 163 | */ 164 | interface_struct *bootstrap_arch(void*); 165 | 166 | 167 | /// 168 | /// Tools section 169 | /// 170 | 171 | /** 172 | * @brief Halts the CPU 173 | */ 174 | void halt(); 175 | 176 | /** 177 | * @brief write a string 178 | */ 179 | #define write_string(x) com_write(COM1, x, (size_t)(-1)) 180 | 181 | // 182 | // Used interrupts section 183 | // 184 | 185 | /** 186 | * @brief Interrupt number for a syscall 187 | */ 188 | #define arch_SYSCALL_INT 128 189 | 190 | /** 191 | * @brief Interrupt number for a manual task switch 192 | */ 193 | #define arch_SWITCH_TASK_INT 129 194 | 195 | // 196 | // Physical memory section 197 | // 198 | 199 | /** 200 | * @brief Requests a page to pmm 201 | */ 202 | #define new_physical_page() get_frame() 203 | 204 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/arch/archtypes.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCHTYPES_H 2 | #define ARCHTYPES_H 3 | 4 | #include 5 | 6 | //type for register 7 | typedef uint64_t register_t; 8 | 9 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/intel/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEL_ASM 2 | #define INTEL_ASM 3 | 4 | #include "freestanding.h" 5 | 6 | static inline uint8_t asm_in8(uint16_t port) 7 | { 8 | uint8_t data; 9 | asm volatile("inb %0, %1" 10 | : "=a"(data) 11 | : "dN"(port)); 12 | return data; 13 | } 14 | 15 | static inline uint16_t asm_in16(uint16_t port) 16 | { 17 | uint16_t data; 18 | asm volatile("inw %0, %1" 19 | : "=a"(data) 20 | : "d"(port)); 21 | return data; 22 | } 23 | 24 | static inline uint32_t asm_in32(uint16_t port) 25 | { 26 | uint32_t data; 27 | asm volatile("inl %0, %1" 28 | : "=a"(data) 29 | : "d"(port)); 30 | return data; 31 | } 32 | 33 | static inline void asm_out8(uint16_t port, uint8_t data) 34 | { 35 | asm volatile("outb %1, %0" 36 | : 37 | : "a"(data), "Nd"(port)); 38 | } 39 | 40 | static inline void asm_out16(uint16_t port, uint16_t data) 41 | { 42 | asm volatile("outw %1, %0" 43 | : 44 | : "a"(data), "d"(port)); 45 | } 46 | 47 | static inline void asm_out32(uint16_t port, uint32_t data) 48 | { 49 | asm volatile("outl %1, %0" 50 | : 51 | : "a"(data), "d"(port)); 52 | } 53 | 54 | enum msr_reg 55 | { 56 | MSR_APIC = 0x1B, 57 | MSR_EFER = 0xC0000080, 58 | MSR_STAR = 0xC0000081, 59 | MSR_LSTAR = 0xC0000082, 60 | MSR_COMPAT_STAR = 0xC0000083, 61 | MSR_SYSCALL_FLAG_MASK = 0xC0000084, 62 | MSR_FS_BASE = 0xC0000100, 63 | MSR_GS_BASE = 0xC0000101, 64 | MSR_KERN_GS_BASE = 0xc0000102, 65 | }; 66 | 67 | enum msr_efer_reg 68 | { 69 | EFER_ENABLE_SYSCALL = 1, 70 | }; 71 | 72 | enum msr_star_reg 73 | { 74 | STAR_KCODE_OFFSET = 32, 75 | STAR_UCODE_OFFSET = 48, 76 | }; 77 | 78 | enum msr_syscall_flag_reg 79 | { 80 | SYSCALL_FLAG_TURN_OFF_INTERRUPT = (1 << 9) 81 | }; 82 | 83 | static inline uint64_t asm_read_msr(enum msr_reg msr) 84 | { 85 | 86 | uint32_t low, high; 87 | asm volatile("rdmsr": "=a"(low), "=d"(high): "c"((uint64_t)msr)); 88 | return ((uint64_t)high << 32) | low; 89 | } 90 | 91 | static inline void asm_write_msr(enum msr_reg msr, uint64_t value) 92 | { 93 | uint32_t low = value & 0xFFFFFFFF; 94 | uint32_t high = value >> 32; 95 | asm volatile("wrmsr":: "c"((uint64_t)msr), "a"(low), "d"(high)); 96 | } 97 | 98 | #define HALT() while(1) asm volatile("hlt") 99 | #define ACTIVE_MAPPING(x) asm volatile("mov cr3, %0" :: "a"(x)) 100 | #define EVAL(...) __VA_ARGS__ 101 | #define STRINGIFY(...) #__VA_ARGS__ 102 | #define TRIGGER_INTERRUPT(x) asm volatile("int " STRINGIFY(x)) 103 | 104 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/intel/cpuinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEL_CPUINFO_H 2 | #define INTEL_CPUINFO_H 3 | 4 | #include "freestanding.h" 5 | 6 | typedef union{ 7 | struct { 8 | bool SSE3 : 1; 9 | bool PCLMUL : 1; 10 | bool DTES64 : 1; 11 | bool MONITOR : 1; 12 | bool DS_CPL : 1; 13 | bool VMX : 1; 14 | bool SMX : 1; 15 | bool EST : 1; 16 | bool TM2 : 1; 17 | bool SSSE3 : 1; 18 | bool CID : 1; 19 | bool FMA : 1; 20 | bool CX16 : 1; 21 | bool ETPRD : 1; 22 | bool PDCM : 1; 23 | bool PCIDE : 1; 24 | bool DCA : 1; 25 | bool SSE4_1 : 1; 26 | bool SSE4_2 : 1; 27 | bool x2APIC : 1; 28 | bool MOVBE : 1; 29 | bool POPCNT : 1; 30 | bool AES : 1; 31 | bool XSAVE : 1; 32 | bool OSXSAVE : 1; 33 | bool AVX : 1; 34 | } parsed; 35 | uint32_t raw; 36 | } cpu_abilities_rcx; 37 | 38 | typedef union{ 39 | struct { 40 | bool FPU : 1; 41 | bool VME : 1; 42 | bool DE : 1; 43 | bool PSE : 1; 44 | bool TSC : 1; 45 | bool MSR : 1; 46 | bool PAE : 1; 47 | bool MCE : 1; 48 | bool CX8 : 1; 49 | bool APIC : 1; 50 | bool SEP : 1; 51 | bool MTRR : 1; 52 | bool PGE : 1; 53 | bool MCA : 1; 54 | bool CMOV : 1; 55 | bool PAT : 1; 56 | bool PSE36 : 1; 57 | bool PSN : 1; 58 | bool CLF : 1; 59 | bool DTES : 1; 60 | bool ACPI : 1; 61 | bool MMX : 1; 62 | bool FXSR : 1; 63 | bool SSE : 1; 64 | bool SSE2 : 1; 65 | bool SS : 1; 66 | bool HTT : 1; 67 | bool TM1 : 1; 68 | bool IA64 : 1; 69 | bool PBE : 1; 70 | } parsed; 71 | uint32_t raw; 72 | } cpu_abilities_rdx; 73 | 74 | typedef struct { 75 | bool SSE1 : 1; 76 | bool SSE2 : 1; 77 | bool SSE3 : 1; 78 | bool SSE4 : 1; 79 | bool XSAVE : 1; 80 | bool HYPERTHREADING : 1; 81 | bool ACPI : 1; 82 | bool APIC : 1; 83 | bool X2APIC : 1; 84 | } cpu_abilities; 85 | 86 | cpu_abilities* get_cpu_info(); 87 | 88 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/intel/registers.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEL_REGISTERS 2 | #define INTEL_REGISTERS 3 | 4 | #include "freestanding.h" 5 | 6 | 7 | #if 0 8 | typedef struct { 9 | uint64_t r15; 10 | uint64_t r14; 11 | uint64_t r13; 12 | uint64_t r12; 13 | uint64_t r11; 14 | uint64_t r10; 15 | uint64_t r9; 16 | uint64_t r8; 17 | uint64_t rbp; 18 | uint64_t rsp; 19 | uint64_t rdi; 20 | uint64_t rsi; 21 | uint64_t rdx; 22 | uint64_t rcx; 23 | uint64_t rbx; 24 | uint64_t rax; 25 | } PACKED stackframe; 26 | #endif 27 | 28 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/intel/simd.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEL_SIMD_H 2 | #define INTEL_SIMD_H 3 | 4 | #include "freestanding.h" 5 | 6 | void save_simd_context(void* addr); 7 | void load_simd_context(void* addr); 8 | 9 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/intel/tss.h: -------------------------------------------------------------------------------- 1 | #ifndef kINTEL_TSS 2 | #define kINTEL_TSS 3 | 4 | #include "freestanding.h" 5 | 6 | struct TssEntry { 7 | uint32_t reserved; 8 | uint64_t rsp[3]; 9 | uint64_t reserved0; 10 | uint64_t ist[7]; 11 | uint32_t reserved1; 12 | uint32_t reserved2; 13 | uint16_t reserved3; 14 | uint16_t iopb_offset; 15 | } __attribute__((packed)); 16 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/interrupts/defined_interrupts.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTS_DEFINED_INTERRUPTS 2 | #define INTERRUPTS_DEFINED_INTERRUPTS 3 | 4 | #define DEBUG_INTERRUPT 127 5 | #define SYSCALL_INTERRUPT 128 6 | #define SWITCH_TASK_INTERRUPT 129 7 | 8 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/interrupts/kernel_exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTS_KERNEL_EXCEPTION_H 2 | #define INTERRUPTS_KERNEL_EXCEPTION_H 3 | 4 | void attach_kernel_exceptions(); 5 | 6 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/interrupts/stackframe.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTS_STACKFRAME_H 2 | #define INTERRUPTS_STACKFRAME_H 3 | 4 | #include "freestanding.h" 5 | 6 | typedef struct { 7 | 8 | uint64_t r15; 9 | uint64_t r14; 10 | uint64_t r13; 11 | uint64_t r12; 12 | uint64_t r11; 13 | uint64_t r10; 14 | uint64_t r9; 15 | uint64_t r8; 16 | 17 | uint64_t rbp; 18 | 19 | uint64_t rdi; 20 | uint64_t rsi; 21 | uint64_t rdx; 22 | uint64_t rcx; 23 | uint64_t rbx; 24 | uint64_t rax; 25 | 26 | // uint64_t rsp; 27 | 28 | uint64_t int_no; 29 | // uint32_t align1; 30 | uint64_t err_code; 31 | // uint32_t align2; 32 | 33 | //uint64_t rsp; 34 | uint64_t rip; 35 | uint16_t cs; 36 | uint16_t align3; 37 | uint32_t align4; 38 | uint64_t rflags; 39 | uint64_t useresp; 40 | uint16_t ss; 41 | 42 | } PACKED stackframe; 43 | 44 | typedef struct { 45 | uint8_t data[512]; 46 | } PACKED fxsaveframe; 47 | 48 | typedef struct { 49 | fxsaveframe simd_save; 50 | stackframe stack_save; 51 | } PACKED context_save; 52 | 53 | #define CONTEXT_FRAME_ADDR ((context_save*)(0x7FFFFFFFF000ull)) 54 | #define FXSAVE_FRAME_ADDR ((fxsaveframe*)(0x7FFFFFFFF000ull)) 55 | 56 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/pmm/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef PMM_H 2 | #define PMM_H 3 | 4 | #include "freestanding.h" 5 | #include "thirdparties/stivale2.h" 6 | 7 | uintptr_t get_frame(); 8 | void init_pmm(uintptr_t virtual_addr); 9 | void set_memory_map(struct stivale2_struct_tag_memmap * memmap_tag); 10 | uint64_t get_size_in_bits(); 11 | void free_frame(uintptr_t address); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/serial/com.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_COM_H 2 | #define LOG_COM_H 3 | 4 | #include "freestanding.h" 5 | 6 | enum com_port 7 | { 8 | COM1 = 0x3F8, 9 | COM2 = 0x2F8, 10 | COM3 = 0x3E8, 11 | COM4 = 0x2E8, 12 | }; 13 | 14 | enum com_register 15 | { 16 | COM_DATA = 0, 17 | COM_INTERRUPT = 1, 18 | COM_BAUD_RATE_LOW = 0, 19 | COM_BAUD_RATE_HIGH = 1, 20 | COM_INTERRUPT_IDENTIFICATOR = 2, 21 | COM_FIFO_CONTROLLER = 2, 22 | COM_LINE_CONTROL = 3, 23 | COM_MODEM_CONTROL = 4, 24 | COM_LINE_STATUS = 5, 25 | COM_MODEM_STATUS = 6, 26 | COM_SCRATCH_REGISTER = 7, 27 | }; 28 | 29 | enum com_line_control_bit 30 | { 31 | COM_DATA_SIZE_5 = 0, 32 | COM_DATA_SIZE_6 = 1, 33 | COM_DATA_SIZE_7 = 2, 34 | COM_DATA_SIZE_8 = 3, 35 | COM_DLAB_STATUS = 1 << 7, 36 | }; 37 | 38 | enum com_modem_bit 39 | { 40 | COM_MODEM_DTR = 1 << 0, 41 | COM_MODEM_RTS = 1 << 1, 42 | COM_MODEM_OUT1 = 1 << 2, 43 | COM_MODEM_OUT2 = 1 << 3, 44 | COM_MODEM_LOOPBACK = 1 << 4, 45 | }; 46 | 47 | enum com_interrupt_enable_bit 48 | { 49 | COM_INTERRUPT_WHEN_DATA_AVAILABLE = 1 << 0, 50 | COM_INTERRUPT_WHEN_TRANSMITTER_EMPTY = 1 << 1, 51 | COM_INTERRUPT_WHEN_BREAK_ERROR = 1 << 2, 52 | COM_INTERRUPT_WHEN_STATUS_UPDATE = 1 << 3, 53 | }; 54 | 55 | enum com_line_status_bit 56 | { 57 | COM_LINE_DATA_READY = 1 << 0, 58 | COM_LINE_OVERRUN_ERROR = 1 << 1, 59 | COM_LINE_PARITY_ERROR = 1 << 2, 60 | COM_LINE_FRAMING_ERROR = 1 << 3, 61 | COM_LINE_BREAK_INDICATOR = 1 << 4, 62 | COM_LINE_TRANSMITTER_BUFFER_EMPTY = 1 << 5, 63 | COM_LINE_TRANSMITTER_EMPTY = 1 << 6, 64 | COM_LINE_IMPENDING_ERROR = 1 << 7, 65 | }; 66 | 67 | void com_initialize(enum com_port port); 68 | size_t com_write(enum com_port port, void const *buffer, size_t size); 69 | 70 | 71 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/syscall-enabling/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALL_H 2 | #define SYSCALL_H 3 | 4 | #include "arch/archtypes.h" 5 | 6 | struct syscall_pack 7 | { 8 | uint64_t syscall_id; 9 | uint64_t arg1; 10 | uint64_t arg2; 11 | uint64_t arg3; 12 | uint64_t arg4; 13 | uint64_t arg5; 14 | uint64_t arg6; 15 | }; 16 | 17 | 18 | void syscall_initialize(void); 19 | 20 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/tables/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef kTABLES_GDT 2 | #define kTABLES_GDT 3 | 4 | #include "freestanding.h" 5 | #include "intel/tss.h" 6 | 7 | #define GDT_KERNEL_CODE (1) 8 | #define GDT_KERNEL_DATA (2) 9 | #define GDT_USER_DATA (4) 10 | #define GDT_USER_CODE (5) 11 | 12 | void setup_gdt(); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/tables/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef kTABLES_IDT 2 | #define kTABLES_IDT 3 | 4 | #include "freestanding.h" 5 | #include "interrupts/stackframe.h" 6 | 7 | static const uint32_t IDT_DESC_PRESENT = 0x80; 8 | 9 | typedef struct 10 | { 11 | uint16_t ie_base_lo; /* The lower 16 bits of the address to jump to when this interrupt fires. */ 12 | uint16_t ie_sel; /* Kernel segment selector. */ 13 | uint8_t ie_always0; /* This must always be zero. */ 14 | uint8_t ie_flags; /* More flags. See documentation. */ 15 | uint16_t ie_base_hi; /* The upper 16 bits of the address to jump to. */ 16 | }__attribute__((packed)) idt_entry_t; 17 | 18 | /** 19 | * @brief pointer to an array of interrupt handlers, suitable for 'lidt' call 20 | * 21 | */ 22 | typedef struct 23 | { 24 | uint16_t limit; 25 | uint32_t base; 26 | }__attribute__((packed)) idt_ptr_t; 27 | 28 | typedef struct{ 29 | uint16_t handlerAddressLowBits; 30 | uint16_t gdt_codeSegmentSelector; 31 | uint8_t reserved; 32 | uint8_t access; 33 | uint16_t handlerAddressHighBits; 34 | } GateDescriptor; 35 | 36 | void setup_idt(void); 37 | 38 | void attach_isr(uint8_t interrupt_number, void(*isr_to_add)(volatile stackframe*)); 39 | void log_stackframe(volatile stackframe* regs); 40 | 41 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/tables/tables.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaemonOnUnix/pEpitOS-x86_64/8a0bd155e7ea7c8b3d6ebebacd5b567353716208/src/arch/x86_64/include/tables/tables.h -------------------------------------------------------------------------------- /src/arch/x86_64/include/thirdparties/stivale2.h: -------------------------------------------------------------------------------- 1 | #ifndef __STIVALE__STIVALE2_H__ 2 | #define __STIVALE__STIVALE2_H__ 3 | 4 | #include 5 | 6 | struct stivale2_tag { 7 | uint64_t identifier; 8 | uint64_t next; 9 | } __attribute__((__packed__)); 10 | 11 | /* --- Header --------------------------------------------------------------- */ 12 | /* Information passed from the kernel to the bootloader */ 13 | 14 | struct stivale2_header { 15 | uint64_t entry_point; 16 | uint64_t stack; 17 | uint64_t flags; 18 | uint64_t tags; 19 | } __attribute__((__packed__)); 20 | 21 | #define STIVALE2_HEADER_TAG_FRAMEBUFFER_ID 0x3ecc1bc43d0f7971 22 | 23 | struct stivale2_header_tag_framebuffer { 24 | struct stivale2_tag tag; 25 | uint16_t framebuffer_width; 26 | uint16_t framebuffer_height; 27 | uint16_t framebuffer_bpp; 28 | } __attribute__((__packed__)); 29 | 30 | #define STIVALE2_HEADER_TAG_FB_MTRR_ID 0x4c7bb07731282e00 31 | 32 | #define STIVALE2_HEADER_TAG_TERMINAL_ID 0xa85d499b1823be72 33 | 34 | struct stivale2_header_tag_terminal { 35 | struct stivale2_tag tag; 36 | uint64_t flags; 37 | } __attribute__((__packed__)); 38 | 39 | #define STIVALE2_HEADER_TAG_SMP_ID 0x1ab015085f3273df 40 | 41 | struct stivale2_header_tag_smp { 42 | struct stivale2_tag tag; 43 | uint64_t flags; 44 | } __attribute__((__packed__)); 45 | 46 | #define STIVALE2_HEADER_TAG_5LV_PAGING_ID 0x932f477032007e8f 47 | 48 | #define STIVALE2_HEADER_TAG_UNMAP_NULL_ID 0x92919432b16fe7e7 49 | 50 | /* --- Struct --------------------------------------------------------------- */ 51 | /* Information passed from the bootloader to the kernel */ 52 | 53 | struct stivale2_struct { 54 | #define STIVALE2_BOOTLOADER_BRAND_SIZE 64 55 | char bootloader_brand[STIVALE2_BOOTLOADER_BRAND_SIZE]; 56 | 57 | #define STIVALE2_BOOTLOADER_VERSION_SIZE 64 58 | char bootloader_version[STIVALE2_BOOTLOADER_VERSION_SIZE]; 59 | 60 | uint64_t tags; 61 | } __attribute__((__packed__)); 62 | 63 | #define STIVALE2_STRUCT_TAG_CMDLINE_ID 0xe5e76a1b4597a781 64 | 65 | struct stivale2_struct_tag_cmdline { 66 | struct stivale2_tag tag; 67 | uint64_t cmdline; 68 | } __attribute__((__packed__)); 69 | 70 | #define STIVALE2_STRUCT_TAG_MEMMAP_ID 0x2187f79e8612de07 71 | 72 | #define STIVALE2_MMAP_USABLE 1 73 | #define STIVALE2_MMAP_RESERVED 2 74 | #define STIVALE2_MMAP_ACPI_RECLAIMABLE 3 75 | #define STIVALE2_MMAP_ACPI_NVS 4 76 | #define STIVALE2_MMAP_BAD_MEMORY 5 77 | #define STIVALE2_MMAP_BOOTLOADER_RECLAIMABLE 0x1000 78 | #define STIVALE2_MMAP_KERNEL_AND_MODULES 0x1001 79 | #define STIVALE2_MMAP_FRAMEBUFFER 0x1002 80 | 81 | struct stivale2_mmap_entry { 82 | uint64_t base; 83 | uint64_t length; 84 | uint32_t type; 85 | uint32_t unused; 86 | } __attribute__((__packed__)); 87 | 88 | struct stivale2_struct_tag_memmap { 89 | struct stivale2_tag tag; 90 | uint64_t entries; 91 | struct stivale2_mmap_entry memmap[]; 92 | } __attribute__((__packed__)); 93 | 94 | #define STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID 0x506461d2950408fa 95 | 96 | #define STIVALE2_FBUF_MMODEL_RGB 1 97 | 98 | struct stivale2_struct_tag_framebuffer { 99 | struct stivale2_tag tag; 100 | uint64_t framebuffer_addr; 101 | uint16_t framebuffer_width; 102 | uint16_t framebuffer_height; 103 | uint16_t framebuffer_pitch; 104 | uint16_t framebuffer_bpp; 105 | uint8_t memory_model; 106 | uint8_t red_mask_size; 107 | uint8_t red_mask_shift; 108 | uint8_t green_mask_size; 109 | uint8_t green_mask_shift; 110 | uint8_t blue_mask_size; 111 | uint8_t blue_mask_shift; 112 | } __attribute__((__packed__)); 113 | 114 | #define STIVALE2_STRUCT_TAG_EDID_ID 0x968609d7af96b845 115 | 116 | struct stivale2_struct_tag_edid { 117 | struct stivale2_tag tag; 118 | uint64_t edid_size; 119 | uint8_t edid_information[]; 120 | } __attribute__((__packed__)); 121 | 122 | #define STIVALE2_STRUCT_TAG_FB_MTRR_ID 0x6bc1a78ebe871172 123 | 124 | #define STIVALE2_STRUCT_TAG_TERMINAL_ID 0xc2b3f4c3233b0974 125 | 126 | struct stivale2_struct_tag_terminal { 127 | struct stivale2_tag tag; 128 | uint32_t flags; 129 | uint16_t cols; 130 | uint16_t rows; 131 | uint64_t term_write; 132 | } __attribute__((__packed__)); 133 | 134 | #define STIVALE2_STRUCT_TAG_MODULES_ID 0x4b6fe466aade04ce 135 | 136 | struct stivale2_module { 137 | uint64_t begin; 138 | uint64_t end; 139 | 140 | #define STIVALE2_MODULE_STRING_SIZE 128 141 | char string[STIVALE2_MODULE_STRING_SIZE]; 142 | } __attribute__((__packed__)); 143 | 144 | struct stivale2_struct_tag_modules { 145 | struct stivale2_tag tag; 146 | uint64_t module_count; 147 | struct stivale2_module modules[]; 148 | } __attribute__((__packed__)); 149 | 150 | #define STIVALE2_STRUCT_TAG_RSDP_ID 0x9e1786930a375e78 151 | 152 | struct stivale2_struct_tag_rsdp { 153 | struct stivale2_tag tag; 154 | uint64_t rsdp; 155 | } __attribute__((__packed__)); 156 | 157 | #define STIVALE2_STRUCT_TAG_EPOCH_ID 0x566a7bed888e1407 158 | 159 | struct stivale2_struct_tag_epoch { 160 | struct stivale2_tag tag; 161 | uint64_t epoch; 162 | } __attribute__((__packed__)); 163 | 164 | #define STIVALE2_STRUCT_TAG_FIRMWARE_ID 0x359d837855e3858c 165 | 166 | #define STIVALE2_FIRMWARE_BIOS (1 << 0) 167 | 168 | struct stivale2_struct_tag_firmware { 169 | struct stivale2_tag tag; 170 | uint64_t flags; 171 | } __attribute__((__packed__)); 172 | 173 | #define STIVALE2_STRUCT_TAG_EFI_SYSTEM_TABLE_ID 0x4bc5ec15845b558e 174 | 175 | struct stivale2_struct_tag_efi_system_table { 176 | struct stivale2_tag tag; 177 | uint64_t system_table; 178 | } __attribute__((__packed__)); 179 | 180 | #define STIVALE2_STRUCT_TAG_KERNEL_FILE_ID 0xe599d90c2975584a 181 | 182 | struct stivale2_struct_tag_kernel_file { 183 | struct stivale2_tag tag; 184 | uint64_t kernel_file; 185 | } __attribute__((__packed__)); 186 | 187 | #define STIVALE2_STRUCT_TAG_KERNEL_SLIDE_ID 0xee80847d01506c57 188 | 189 | struct stivale2_struct_tag_kernel_slide { 190 | struct stivale2_tag tag; 191 | uint64_t kernel_slide; 192 | } __attribute__((packed)); 193 | 194 | #define STIVALE2_STRUCT_TAG_SMBIOS_ID 0x274bd246c62bf7d1 195 | 196 | struct stivale2_struct_tag_smbios { 197 | struct stivale2_tag tag; 198 | uint64_t flags; 199 | uint64_t smbios_entry_32; 200 | uint64_t smbios_entry_64; 201 | } __attribute__((packed)); 202 | 203 | #define STIVALE2_STRUCT_TAG_SMP_ID 0x34d1d96339647025 204 | 205 | struct stivale2_smp_info { 206 | uint32_t processor_id; 207 | uint32_t lapic_id; 208 | uint64_t target_stack; 209 | uint64_t goto_address; 210 | uint64_t extra_argument; 211 | } __attribute__((__packed__)); 212 | 213 | struct stivale2_struct_tag_smp { 214 | struct stivale2_tag tag; 215 | uint64_t flags; 216 | uint32_t bsp_lapic_id; 217 | uint32_t unused; 218 | uint64_t cpu_count; 219 | struct stivale2_smp_info smp_info[]; 220 | } __attribute__((__packed__)); 221 | 222 | #define STIVALE2_STRUCT_TAG_PXE_SERVER_INFO 0x29d1e96239247032 223 | 224 | struct stivale2_struct_tag_pxe_server_info { 225 | struct stivale2_tag tag; 226 | uint32_t server_ip; 227 | } __attribute__((__packed__)); 228 | 229 | #define STIVALE2_STRUCT_TAG_MMIO32_UART 0xb813f9b8dbc78797 230 | 231 | struct stivale2_struct_tag_mmio32_uart { 232 | struct stivale2_tag tag; 233 | uint64_t addr; 234 | } __attribute__((__packed__)); 235 | 236 | #define STIVALE2_STRUCT_TAG_DTB 0xabb29bd49a2833fa 237 | 238 | struct stivale2_struct_tag_dtb { 239 | struct stivale2_tag tag; 240 | uint64_t addr; 241 | uint64_t size; 242 | } __attribute__((__packed__)); 243 | 244 | #define STIVALE2_STRUCT_TAG_VMAP 0xb0ed257db18cb58f 245 | 246 | struct stivale2_struct_vmap { 247 | struct stivale2_tag tag; 248 | uint64_t addr; 249 | } __attribute__((__packed__)); 250 | 251 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/thirdparties/stivalemgr.h: -------------------------------------------------------------------------------- 1 | #ifndef kSTIVALE_MGR_H 2 | #define kSTIVALE_MGR_H 3 | 4 | #include "stivale2.h" 5 | 6 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id); 7 | 8 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/include/vmm/vmm.h: -------------------------------------------------------------------------------- 1 | #ifndef kVMM 2 | #define kVMM 3 | 4 | #include "freestanding.h" 5 | #include "utils/macros.h" 6 | 7 | #define mask_l0 MASK(12) 8 | #define mask_l1 MASK_SHIFT(9, (12)) 9 | #define mask_l2 MASK_SHIFT(9, (21)) 10 | #define mask_l3 MASK_SHIFT(9, (30)) 11 | #define mask_l4 MASK_SHIFT(9, (39)) 12 | #define ARCH_PAGE_SIZE 0x1000 13 | #define ARCH_N_ENTRY 512 14 | #define CLEAN_BITS_MASK (~ (0xFFFull)) 15 | #define RECURSIVE_MAPPING_ENTRY 50 16 | 17 | size_t virtual_to_physical(size_t addr); 18 | 19 | #define stivale_to_physical(x) (void*)(((uint64_t)x) - 0xffffffff80000000ull) 20 | #define physical_to_stivale(x) (void*)(((uint64_t)(x)) + 0xffffffff80000000ull) 21 | 22 | uint64_t create_page_directory(); 23 | void init_vmm(); 24 | void kmmap(uintptr_t addr, size_t size, uint64_t flags); 25 | uint64_t craft_addr(uint64_t offset_l4, uint64_t offset_l3, uint64_t offset_l2, uint64_t offset_l1, uint64_t offset_l0); 26 | 27 | typedef enum { 28 | MEM_TO_UPPER, 29 | MEM_TO_LOWER 30 | } mem_direction; 31 | 32 | typedef struct { 33 | 34 | uint16_t plm0 : 12; 35 | uint16_t plm1 : 9; 36 | uint16_t plm2 : 9; 37 | uint16_t plm3 : 9; 38 | uint16_t plm4 : 9; 39 | uint16_t unused; 40 | }PACKED address_offset_64; 41 | 42 | typedef union { 43 | uint64_t address; 44 | address_offset_64 offset; 45 | } address_64_bits; 46 | 47 | void kmunmap(uint64_t addr, size_t size, mem_direction direction); 48 | void setup_context_frame(); 49 | void kmmap_physical(uint64_t addr, uint64_t physical_addr, size_t size, uint64_t flags); 50 | void* map_physical(uint64_t physical_addr, size_t size); 51 | uint64_t search_available(uintptr_t base_addr, size_t size); 52 | uintptr_t convert_to_arch_flags(uintptr_t flags); 53 | 54 | #endif -------------------------------------------------------------------------------- /src/arch/x86_64/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | SECTIONS 3 | { 4 | /* HIGHER HALF KERNEL */ 5 | 6 | /* We wanna be placed in the higher half, 2MiB above 0 in physical memory. */ 7 | /* Since we are going to use PIE, this is just the base load address, but the */ 8 | /* bootloader will be able to relocate us as it sees fit. */ 9 | . = 0xffffffff80200000; 10 | 11 | /* We place the .stivale2hdr section containing the header in its own section, */ 12 | /* and we use the KEEP directive on it to make sure it doesn't get discarded. */ 13 | .stivale2hdr : { 14 | KEEP(*(.stivale2hdr)) 15 | } 16 | 17 | /* Then let's place all the other traditional executable sections afterwards. */ 18 | .text : { 19 | *(.text*) 20 | } 21 | 22 | .rodata : { 23 | *(.rodata*) 24 | } 25 | 26 | .data : { 27 | *(.data*) 28 | } 29 | 30 | .bss : { 31 | *(COMMON) 32 | *(.bss*) 33 | } 34 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/apic.c: -------------------------------------------------------------------------------- 1 | #include "UEFI/RSDT.h" 2 | #include "UEFI/APIC.h" 3 | #include "UEFI/hpet.h" 4 | #include "freestanding.h" 5 | #include "log/log.h" 6 | #include "utils/macros.h" 7 | #include "vmm/vmm.h" 8 | #include "intel/asm.h" 9 | static uintptr_t LAPIC_VIRTUAL_ADDRESS = 0; 10 | static uintptr_t IOAPIC_VIRTUAL_ADDRESS = 0; 11 | 12 | #ifndef APIC_DEBUG 13 | #undef LOG_OK 14 | #define LOG_OK(...) 15 | #undef LOG_INFO 16 | #define LOG_INFO(...) 17 | #endif 18 | 19 | extern apic_info_t apic_info; 20 | 21 | void map_pics(){ 22 | if(!LAPIC_VIRTUAL_ADDRESS || !IOAPIC_VIRTUAL_ADDRESS){ 23 | LOG_PANIC("Can't map PICs with unitialized data."); 24 | HALT(); 25 | } 26 | // Should desactivate caching for this memory region 27 | kmmap_physical(IOAPIC_VIRTUAL_ADDRESS, apic_info.ioapic.address, IOAPIC_LENGTH*2, 2); 28 | kmmap_physical(LAPIC_VIRTUAL_ADDRESS, apic_info.lapic_address, LAPIC_LENGTH*2, 2); 29 | } 30 | 31 | void cpuWriteIoAPIC(uint32_t reg, uint32_t value){ 32 | uint32_t volatile *ioapic = (uint32_t volatile *)IOAPIC_VIRTUAL_ADDRESS; 33 | ioapic[0] = (reg & 0xff); 34 | ioapic[4] = value; 35 | } 36 | 37 | uint32_t cpuReadIoAPIC(uint32_t reg){ 38 | uint32_t volatile *ioapic = (uint32_t volatile *)IOAPIC_VIRTUAL_ADDRESS; 39 | ioapic[0] = (reg & 0xff); 40 | return ioapic[4]; 41 | } 42 | 43 | uint32_t cpuReadLAPIC(uint32_t reg){ 44 | char volatile *lapic = (char volatile *)LAPIC_VIRTUAL_ADDRESS; 45 | return *(uint32_t *)(lapic + reg); 46 | } 47 | 48 | void cpuWriteLAPIC(uint32_t reg, uint32_t value){ 49 | char volatile *lapic = (char volatile *)LAPIC_VIRTUAL_ADDRESS; 50 | *(uint32_t*)(lapic + reg) = value; 51 | } 52 | 53 | void cpu_send_EOI(){ 54 | cpuWriteLAPIC(0xB0,0); 55 | } 56 | 57 | #define PIC1 0x20 58 | #define PIC1_COMMAND PIC1 59 | #define PIC1_OFFSET 0x20 60 | #define PIC1_DATA (PIC1 + 1) 61 | 62 | #define PIC2 0xA0 63 | #define PIC2_COMMAND PIC2 64 | #define PIC2_OFFSET 0x28 65 | #define PIC2_DATA (PIC2 + 1) 66 | 67 | void disable_pic() { 68 | asm_out8(PIC2_DATA, 0xff); 69 | asm_out8(PIC1_DATA, 0xff); 70 | } 71 | 72 | void redirect_interrupts(){ 73 | ioapic_entry_t ioapic = apic_info.ioapic; 74 | for(size_t i = 0; i < apic_info.interrupt_count; i++){ 75 | interrupt_source_override interrupt = apic_info.interrupt[i]; 76 | if(ioapic.base < interrupt.global_system_interrupt && (size_t)interrupt.irq <= ioapic.max_redirection){ 77 | LOG_INFO("can redirect interrupt: {d}",interrupt.irq); 78 | uint32_t value = (interrupt.irq + 32) | (0 << 8) | (0 << 11) | (1 << 13) | (0 << 15); 79 | cpuWriteIoAPIC(IOAPIC_REDIRECTION_OFFSET + ((interrupt.irq - ioapic.base)*2), value); 80 | cpuWriteIoAPIC(IOAPIC_REDIRECTION_OFFSET + ((interrupt.irq - ioapic.base)*2)+1, apic_info.lapics[0].ACPI_id); 81 | } else { 82 | LOG_ERR("can't redirect interrupt: {x}",interrupt.irq); 83 | } 84 | } 85 | } 86 | 87 | void map_APIC(){ 88 | ONCE(); 89 | IOAPIC_VIRTUAL_ADDRESS = (uintptr_t)map_physical(apic_info.ioapic.address, IOAPIC_LENGTH*2); 90 | LAPIC_VIRTUAL_ADDRESS = (uintptr_t)map_physical(apic_info.lapic_address, LAPIC_LENGTH*2); 91 | LOG_INFO("IOAPIC mapped at address: {x} | LAPIC mapped at address: {x}", IOAPIC_VIRTUAL_ADDRESS, LAPIC_VIRTUAL_ADDRESS); 92 | 93 | uint32_t info = cpuReadIoAPIC(1); 94 | apic_info.ioapic.max_redirection = SHIFTR(info,8,16); 95 | 96 | LOG_INFO("I/O APIC Version: {x}, Maximum redirection is: {x}", SHIFTR(info, 8, 0), SHIFTR(info, 8, 16)); 97 | LOG_INFO("APIC version: {x}",cpuReadLAPIC(0x30)); 98 | LOG_INFO("Setting the spurious interrupt vector register"); 99 | } 100 | 101 | void enable_APIC(){ 102 | map_APIC(); 103 | cpuWriteLAPIC(SPURIOUS_VECTOR_REGISTER, cpuReadLAPIC(SPURIOUS_VECTOR_REGISTER) | SPURIOUS_ALL); 104 | redirect_interrupts(); 105 | } 106 | 107 | void init_APIC_timer(){ 108 | ONCE(); 109 | hpet_reset(); 110 | size_t tick_to_wait = hpet_ms_to_tick(10); 111 | 112 | cpuWriteLAPIC(APIC_REGISTER_TIMER_DIV, 0x3); 113 | cpuWriteLAPIC(APIC_REGISTER_TIMER_INITCNT, (uint32_t)-1); 114 | 115 | hpet_wait_tick(tick_to_wait); 116 | 117 | cpuWriteLAPIC(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED); 118 | uint32_t ticksIn10ms = 0xFFFFFFFF - cpuReadLAPIC(APIC_REGISTER_TIMER_CURRCNT); 119 | LOG_INFO("There is {x} | {d} ticks in 10 ms", ticksIn10ms,ticksIn10ms); 120 | cpuWriteLAPIC(APIC_REGISTER_LVT_TIMER, 32 | 0x20000); 121 | cpuWriteLAPIC(APIC_REGISTER_TIMER_DIV, 0x3); 122 | cpuWriteLAPIC(APIC_REGISTER_TIMER_INITCNT, ticksIn10ms*300); 123 | } 124 | 125 | 126 | 127 | void init_APIC_interrupt(){ 128 | LOG_INFO("Configuring non maskable interrupt") 129 | for(size_t i = 0; i < apic_info.nmi_count;i++){ 130 | if(apic_info.nmis[i].ACPI_processor_id == 0xFF){ 131 | size_t lint_registers = 0x350 + (0x10 * apic_info.nmis[i].LINT); 132 | size_t flags = apic_info.nmis[i].flags; 133 | cpuWriteLAPIC(lint_registers,((flags & 2) << 13) | ((flags & 8) << 15)); 134 | } 135 | } 136 | 137 | disable_pic(); 138 | LOG_INFO("Enabling APIC"); 139 | cpuWriteLAPIC(SPURIOUS_VECTOR_REGISTER, cpuReadLAPIC(SPURIOUS_VECTOR_REGISTER) | SPURIOUS_ENABLE_BIT); 140 | } 141 | 142 | void send_interrupt_to_core(uint8_t core_number, uint8_t interrupt_number){ 143 | cpuWriteLAPIC(0x310, core_number << 24); 144 | int_message to_send; 145 | to_send.bitfield.vector_number = interrupt_number; 146 | //to_send.bitfield.INIt_level = 1; 147 | // to_send.bitfield.destination_type = 2; 148 | cpuWriteLAPIC(0x300, to_send.value); 149 | volatile interrupt_message* result = (void*)(LAPIC_VIRTUAL_ADDRESS + 0x300); 150 | while(result->delivery_status); 151 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/arch.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | 3 | #include "thirdparties/stivale2.h" 4 | #include "freestanding.h" 5 | #include "log/log.h" 6 | #include "thirdparties/stivalemgr.h" 7 | #include "tables/gdt.h" 8 | #include "tables/idt.h" 9 | #include "interrupts/kernel_exceptions.h" 10 | #include "pmm/pmm.h" 11 | #include "vmm/vmm.h" 12 | #include "intel/cpuinfo.h" 13 | #include "intel/asm.h" 14 | #include "UEFI/RSDT.h" 15 | #include "SMP/SMP.h" 16 | #include "UEFI/APIC.h" 17 | #include "tasking/tasking.h" 18 | #include "interrupts/defined_interrupts.h" 19 | #include "interface_struct/interface_struct.h" 20 | #include "syscall-enabling/syscall.h" 21 | #include "init/initfs.h" 22 | 23 | void enable_ints(){ 24 | asm volatile("sti"); 25 | } 26 | 27 | void disable_ints(){ 28 | asm volatile("cli"); 29 | } 30 | 31 | void halt(){ 32 | HALT(); 33 | } 34 | 35 | void enable_mapping(mapping_t mapping){ 36 | asm volatile("mov cr3, %0" :: "a"(mapping)); 37 | } 38 | 39 | mapping_t get_current_mapping(){ 40 | uint64_t to_return; 41 | asm volatile("mov %0, cr3" : "=a"(to_return) :); 42 | return (mapping_t)to_return; 43 | } 44 | 45 | static interface_struct interface = {0}; 46 | 47 | interface_struct *bootstrap_arch(void* structure){ 48 | 49 | struct stivale2_struct* stivale2_struct = (struct stivale2_struct*)structure; 50 | 51 | struct stivale2_struct_tag_framebuffer *framebuffer_tag; 52 | framebuffer_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID); 53 | 54 | LOG_OK("Booted successfully.") 55 | LOG_INFO("Stivale2 struct at {x}", stivale2_struct); 56 | LOG_INFO("Size of Framebuffer : {d} x {d}", framebuffer_tag->framebuffer_width, framebuffer_tag->framebuffer_height); 57 | LOG_INFO("Framebuffer at {x}", framebuffer_tag->framebuffer_addr); 58 | 59 | struct stivale2_struct_tag_memmap * memmap_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_MEMMAP_ID); 60 | LOG_INFO("Memory map at {x}, has {d} entries.", memmap_tag, memmap_tag->entries); 61 | 62 | struct stivale2_struct_tag_smp* smp_infos; 63 | smp_infos = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_SMP_ID); 64 | smp_infos = physical_to_stivale(smp_infos); 65 | 66 | ASSERT(smp_infos->cpu_count > 0, "CPU count is {d}, at addr {x}", "CPU count is {d}, at addr {x}", smp_infos->cpu_count, (uintptr_t)smp_infos); 67 | 68 | struct stivale2_struct_tag_modules* modules_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_MODULES_ID); 69 | LOG_OK("Modules at {x}, has {d} entries.", modules_tag, modules_tag->module_count); 70 | for(size_t i = 0; i < modules_tag->module_count; i++){ 71 | struct stivale2_module* module = modules_tag->modules + i; 72 | LOG_INFO("Module {d} : {s}", i, module->string); 73 | // for(volatile size_t i = 0; i < 0x20; i++) 74 | // LOG_OK("{x}", *(uint8_t*)(module->begin + i)); 75 | // PANIC(""); 76 | register_new_file(physical_to_stivale(module->string), (uintptr_t)physical_to_stivale(module->begin), (uintptr_t)physical_to_stivale(module->end)); 77 | } 78 | 79 | struct stivale2_struct_tag_rsdp * rsdp_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_RSDP_ID); 80 | parse_RSDP(rsdp_tag->rsdp); 81 | setup_gdt(); 82 | setup_idt(); 83 | 84 | attach_kernel_exceptions(); 85 | 86 | cpu_abilities* cpuinfos = get_cpu_info(); 87 | UNUSED_VAR(cpuinfos); 88 | 89 | set_memory_map(memmap_tag); 90 | 91 | uint64_t size = get_size_in_bits(ARCH_PAGE_SIZE); 92 | 93 | uintptr_t first_frame = get_frame(); 94 | 95 | for(size_t i = 0; i < size/ARCH_PAGE_SIZE; i++) 96 | get_frame(); 97 | 98 | init_pmm((uintptr_t)physical_to_stivale(first_frame)); 99 | init_vmm(); 100 | LOG_ERR("plouf"); 101 | 102 | asm volatile("mov cr3, %0"::"a"(create_page_directory())); 103 | LOG_OK("Page directory created and loaded successfully."); 104 | 105 | setup_context_frame(); 106 | 107 | extern void enable_sse(void); 108 | enable_sse(); 109 | 110 | 111 | parse_RSDT(); 112 | enable_APIC(); 113 | init_APIC_interrupt(); // I don't know why it is working, but it is working. 114 | init_APIC_timer(); 115 | 116 | asm volatile("sti"); 117 | 118 | syscall_initialize(); 119 | 120 | launch_APs(smp_infos, interface.launching_addresses); 121 | 122 | while (get_booted_cpus_count() != smp_infos->cpu_count); 123 | LOG_OK("All CPUs booted successfully ! ({d} cores)", get_booted_cpus_count()); 124 | 125 | interface.core_number = smp_infos->cpu_count; 126 | for(size_t i = 0; i < 32; i++) 127 | interface.launching_addresses[i] = (void*)1; 128 | 129 | return &interface; 130 | 131 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/cpuinfo.c: -------------------------------------------------------------------------------- 1 | #include "intel/cpuinfo.h" 2 | #include "log/log.h" 3 | 4 | static cpu_abilities cpuinfo = {0}; 5 | static cpu_abilities_rcx cpuinfo_rcx = {0}; 6 | static cpu_abilities_rdx cpuinfo_rdx = {0}; 7 | 8 | enum { 9 | CPUID_FEAT_ECX_SSE3 = 1 << 0, 10 | CPUID_FEAT_ECX_PCLMUL = 1 << 1, 11 | CPUID_FEAT_ECX_DTES64 = 1 << 2, 12 | CPUID_FEAT_ECX_MONITOR = 1 << 3, 13 | CPUID_FEAT_ECX_DS_CPL = 1 << 4, 14 | CPUID_FEAT_ECX_VMX = 1 << 5, 15 | CPUID_FEAT_ECX_SMX = 1 << 6, 16 | CPUID_FEAT_ECX_EST = 1 << 7, 17 | CPUID_FEAT_ECX_TM2 = 1 << 8, 18 | CPUID_FEAT_ECX_SSSE3 = 1 << 9, 19 | CPUID_FEAT_ECX_CID = 1 << 10, 20 | CPUID_FEAT_ECX_FMA = 1 << 12, 21 | CPUID_FEAT_ECX_CX16 = 1 << 13, 22 | CPUID_FEAT_ECX_ETPRD = 1 << 14, 23 | CPUID_FEAT_ECX_PDCM = 1 << 15, 24 | CPUID_FEAT_ECX_PCIDE = 1 << 17, 25 | CPUID_FEAT_ECX_DCA = 1 << 18, 26 | CPUID_FEAT_ECX_SSE4_1 = 1 << 19, 27 | CPUID_FEAT_ECX_SSE4_2 = 1 << 20, 28 | CPUID_FEAT_ECX_x2APIC = 1 << 21, 29 | CPUID_FEAT_ECX_MOVBE = 1 << 22, 30 | CPUID_FEAT_ECX_POPCNT = 1 << 23, 31 | CPUID_FEAT_ECX_AES = 1 << 25, 32 | CPUID_FEAT_ECX_XSAVE = 1 << 26, 33 | CPUID_FEAT_ECX_OSXSAVE = 1 << 27, 34 | CPUID_FEAT_ECX_AVX = 1 << 28, 35 | 36 | CPUID_FEAT_EDX_FPU = 1 << 0, 37 | CPUID_FEAT_EDX_VME = 1 << 1, 38 | CPUID_FEAT_EDX_DE = 1 << 2, 39 | CPUID_FEAT_EDX_PSE = 1 << 3, 40 | CPUID_FEAT_EDX_TSC = 1 << 4, 41 | CPUID_FEAT_EDX_MSR = 1 << 5, 42 | CPUID_FEAT_EDX_PAE = 1 << 6, 43 | CPUID_FEAT_EDX_MCE = 1 << 7, 44 | CPUID_FEAT_EDX_CX8 = 1 << 8, 45 | CPUID_FEAT_EDX_APIC = 1 << 9, 46 | CPUID_FEAT_EDX_SEP = 1 << 11, 47 | CPUID_FEAT_EDX_MTRR = 1 << 12, 48 | CPUID_FEAT_EDX_PGE = 1 << 13, 49 | CPUID_FEAT_EDX_MCA = 1 << 14, 50 | CPUID_FEAT_EDX_CMOV = 1 << 15, 51 | CPUID_FEAT_EDX_PAT = 1 << 16, 52 | CPUID_FEAT_EDX_PSE36 = 1 << 17, 53 | CPUID_FEAT_EDX_PSN = 1 << 18, 54 | CPUID_FEAT_EDX_CLF = 1 << 19, 55 | CPUID_FEAT_EDX_DTES = 1 << 21, 56 | CPUID_FEAT_EDX_ACPI = 1 << 22, 57 | CPUID_FEAT_EDX_MMX = 1 << 23, 58 | CPUID_FEAT_EDX_FXSR = 1 << 24, 59 | CPUID_FEAT_EDX_SSE = 1 << 25, 60 | CPUID_FEAT_EDX_SSE2 = 1 << 26, 61 | CPUID_FEAT_EDX_SS = 1 << 27, 62 | CPUID_FEAT_EDX_HTT = 1 << 28, 63 | CPUID_FEAT_EDX_TM1 = 1 << 29, 64 | CPUID_FEAT_EDX_IA64 = 1 << 30, 65 | CPUID_FEAT_EDX_PBE = 1 << 31 66 | }; 67 | 68 | cpu_abilities* get_cpu_info(){ 69 | 70 | ONCE(&cpuinfo); 71 | 72 | LOG_INFO("Getting processor infos..."); 73 | 74 | uint32_t rbx, rcx, rdx; 75 | 76 | asm volatile("cpuid": "=b"(rbx), "=c"(rcx), "=d"(rdx) : "a"(1)); 77 | // while(1) asm volatile("hlt"); 78 | 79 | LOG_INFO("Got { rbx:= {x}, rcx:= {x}, rdx:= {x} } as results of cpuid", rbx, rcx, rdx); 80 | 81 | cpuinfo_rcx.raw = (uint32_t)rcx; 82 | cpuinfo_rdx.raw = (uint32_t)rdx; 83 | 84 | cpuinfo = (cpu_abilities){ 85 | .HYPERTHREADING = 0, 86 | .SSE1 = (CPUID_FEAT_EDX_SSE) & rdx, 87 | .SSE2 = (CPUID_FEAT_EDX_SSE2) & rdx, 88 | .SSE3 = (CPUID_FEAT_ECX_SSE3) & rcx, 89 | .SSE4 = (CPUID_FEAT_ECX_SSE4_1) & rcx, 90 | .XSAVE = (CPUID_FEAT_ECX_XSAVE) & rcx, 91 | .ACPI = (CPUID_FEAT_EDX_ACPI) & rdx, 92 | .APIC = (CPUID_FEAT_EDX_APIC) & rdx, 93 | .X2APIC = (CPUID_FEAT_ECX_x2APIC) & rcx 94 | }; 95 | 96 | LOG_INFO("Checked features :"); 97 | 98 | CHECK(cpuinfo_rdx.parsed.SSE,"SSE1 detected","SSE1 unavailable"); 99 | 100 | CHECK(cpuinfo_rdx.parsed.SSE2,"SSE2 detected","SSE2 unavailable"); 101 | 102 | CHECK(cpuinfo_rcx.parsed.SSE3,"SSE3 detected","SSE3 unavailable"); 103 | 104 | CHECK(cpuinfo_rcx.parsed.SSE4_1,"SSE4.1 detected","SSE4.1 unavailable"); 105 | 106 | CHECK(cpuinfo_rdx.parsed.ACPI,"ACPI detected","ACPI unavailable"); 107 | 108 | CHECK(cpuinfo_rdx.parsed.APIC,"APIC detected","APIC unavailable"); 109 | 110 | CHECK(cpuinfo_rcx.parsed.x2APIC,"x2APIC detected","x2APIC unavailable"); 111 | 112 | return &cpuinfo; 113 | 114 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/entry.s: -------------------------------------------------------------------------------- 1 | extern kernel_main 2 | 3 | global _start 4 | _start: 5 | jmp kernel_main -------------------------------------------------------------------------------- /src/arch/x86_64/src/gdt.c: -------------------------------------------------------------------------------- 1 | #include "tables/gdt.h" 2 | #include "freestanding.h" 3 | #include "log/log.h" 4 | 5 | #ifndef GDT_DEBUG 6 | #undef LOG_INFO 7 | #define LOG_INFO(...) 8 | #endif 9 | 10 | #define nGDT_ENTRIES 6 11 | 12 | #define GDT_SEGMENT (0b00010000) 13 | #define GDT_PRESENT (0b10000000) 14 | #define GDT_USER (0b01100000) 15 | #define GDT_EXECUTABLE (0b00001000) 16 | #define GDT_READWRITE (0b00000010) 17 | #define GDT_LONG_MODE_GRANULARITY 0b0010 18 | #define GDT_FLAGS 0b1100 19 | 20 | #define GDT_RING_3 (3) 21 | 22 | 23 | typedef struct { 24 | uint16_t limit0_15; 25 | uint16_t base0_15; 26 | uint8_t base16_23; 27 | uint8_t flags; 28 | uint8_t limit16_19 : 4; 29 | uint8_t granularity : 4; 30 | uint8_t base24_31; 31 | } PACKED gdt_entry; 32 | 33 | typedef struct { 34 | gdt_entry entries[nGDT_ENTRIES]; 35 | } PACKED gdt_t; 36 | 37 | typedef struct { 38 | uint16_t size; 39 | uint64_t offset; 40 | } PACKED gdt_descriptor; 41 | 42 | gdt_entry create_gdt_entry(uint32_t base, uint32_t limit, uint8_t granularity, uint8_t flags){ 43 | return (gdt_entry){ 44 | .limit0_15 = (uint16_t)((limit)&0xFFFF), 45 | .base0_15 = (uint16_t)((base)&0xFFFF), 46 | .base16_23 = (uint8_t)(((base) >> 16) & 0xFF), 47 | .flags = (flags), 48 | .limit16_19 = ((limit) >> 16) & 0x0F, 49 | .granularity = (granularity), 50 | .base24_31 = (uint8_t)(((base) >> 24) & 0xFF), 51 | }; 52 | } 53 | 54 | #define quick_entry(flags, granularity) (create_gdt_entry(0, 0, granularity, flags)) 55 | 56 | static gdt_t gdt; 57 | static gdt_descriptor gdt_d; 58 | /* 59 | struct PACKED tss 60 | { 61 | uint32_t reserved; 62 | 63 | uint64_t rsp[3]; 64 | uint8_t granularity : 4; 65 | uint8_t base24_31; 66 | }; 67 | 68 | static struct tss _tss = { 69 | .reserved = 0, 70 | .rsp = {}, 71 | .reserved0 = 0, 72 | .ist = {}, 73 | .reserved1 = 0, 74 | .reserved2 = 0, 75 | .reserved3 = 0, 76 | .iopb_offset = 0, 77 | };*/ 78 | 79 | void setup_gdt(){ 80 | LOG_INFO("Initializing GDT..."); 81 | gdt.entries[0] = create_gdt_entry(0, 0, 0, 0); 82 | LOG_INFO("Null descriptor created, at offset {x}.", 0); 83 | 84 | gdt.entries[GDT_KERNEL_CODE] = quick_entry(GDT_PRESENT | GDT_SEGMENT | GDT_READWRITE | GDT_EXECUTABLE, GDT_LONG_MODE_GRANULARITY); 85 | LOG_INFO("Kernel code descriptor created, at offset {x}.", GDT_KERNEL_CODE*sizeof(gdt_entry)); 86 | 87 | gdt.entries[GDT_KERNEL_DATA] = quick_entry(GDT_PRESENT | GDT_SEGMENT | GDT_READWRITE, 0); 88 | LOG_INFO("Kernel data descriptor created, at offset {x}.", GDT_KERNEL_DATA*sizeof(gdt_entry)); 89 | 90 | gdt.entries[3] = create_gdt_entry(0, 0, 0, 0); 91 | LOG_INFO("Null descriptor created, at offset {x}.", 3*sizeof(gdt_entry)); 92 | 93 | gdt.entries[GDT_USER_DATA] = quick_entry(GDT_PRESENT | GDT_SEGMENT | GDT_READWRITE | GDT_USER, 0); 94 | LOG_INFO("User data descriptor created, at offset {x}.", GDT_USER_DATA*sizeof(gdt_entry)); 95 | 96 | gdt.entries[GDT_USER_CODE] = quick_entry(GDT_PRESENT | GDT_SEGMENT | GDT_READWRITE | GDT_EXECUTABLE | GDT_USER, GDT_LONG_MODE_GRANULARITY); 97 | LOG_INFO("User code descriptor created, at offset {x}.", GDT_USER_CODE*sizeof(gdt_entry)); 98 | 99 | gdt_d.offset = (uint64_t)(&gdt); 100 | gdt_d.size = sizeof(gdt_t) -1; 101 | LOG_INFO("GDT Descriptor created, at {x}. GDT at {x} with size {d}.", (uint64_t)(&gdt_d), gdt_d.offset, gdt_d.size); 102 | 103 | extern void load_gdt(gdt_descriptor* desc); 104 | load_gdt(&gdt_d); 105 | 106 | LOG_OK("GDT loaded successfully."); 107 | 108 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/hpet.c: -------------------------------------------------------------------------------- 1 | #include "UEFI/hpet.h" 2 | #include "UEFI/RSDT.h" 3 | #include "log/log.h" 4 | #include "utils/macros.h" 5 | #include "vmm/vmm.h" 6 | #include "intel/asm.h" 7 | 8 | #ifndef HPET_DEBUG 9 | #undef LOG_INFO 10 | #define LOG_INFO(...) 11 | #endif 12 | 13 | static uintptr_t hpet_register_address = 0; 14 | static size_t period = 0; 15 | 16 | void hpet_init(HPET* hpet){ 17 | ONCE(); 18 | 19 | if(hpet->address_base.address_space_id){ 20 | LOG_PANIC("HPET is system I/o"); 21 | HALT(); 22 | } 23 | else{ 24 | LOG_INFO("HPET is memory mapped at address {x} with register offset {x}",hpet->address_base.address ,hpet->address_base.register_bit_width); 25 | } 26 | 27 | hpet_register_address = (uintptr_t)map_physical(hpet->address_base.address, 4096); 28 | LOG_INFO("HPET found at address: {x} and mapped at address {x}", hpet->address_base.address, hpet_register_address); 29 | 30 | uint64_t value = read_mem64(hpet_register_address); 31 | LOG_INFO("HPET main counter is {d} bits, vendor id: {x}",32 + (32* ((value >> 13)&1)), SHIFTR(value, 16, 16)); 32 | period = (SHIFTR(value, 32, 32)); 33 | LOG_INFO("HPET counter period is: {d} femtoseconds", period); 34 | 35 | } 36 | 37 | void hpet_reset(){ 38 | LOG_INFO("Resetting hpet timer"); 39 | volatile char* ptr = (char*)hpet_register_address; 40 | write_mem64(ptr+HPET_General_Configuration, read_mem64(ptr+HPET_General_Configuration) & (~1ull)); 41 | write_mem64(ptr+HPET_Main_Counter_Value,0); 42 | } 43 | 44 | void hpet_start(){ 45 | char* ptr = (char*)hpet_register_address; 46 | write_mem64(ptr+HPET_General_Configuration, read_mem64(ptr+HPET_General_Configuration) | 1); 47 | } 48 | 49 | 50 | void hpet_wait(size_t ms){ 51 | char* ptr = (char*)hpet_register_address; 52 | size_t tick_to_wait = (ms * 1000000000000) / period; 53 | LOG_INFO("HPET waiting {d} ticks", tick_to_wait); 54 | hpet_reset(); 55 | hpet_start(); 56 | while (read_mem64(ptr+HPET_Main_Counter_Value) < tick_to_wait); 57 | } 58 | 59 | size_t hpet_ms_to_tick(size_t ms){ 60 | return (ms * 1000000000000) / period; 61 | } 62 | 63 | void hpet_wait_tick(size_t tick){ 64 | char* ptr = (char*)hpet_register_address; 65 | hpet_start(); 66 | while (read_mem64(ptr+HPET_Main_Counter_Value) < tick); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/arch/x86_64/src/idt.c: -------------------------------------------------------------------------------- 1 | #include "freestanding.h" 2 | #include "tables/gdt.h" 3 | #include "log/log.h" 4 | #include "interrupts/stackframe.h" 5 | #include "UEFI/APIC.h" 6 | #define nIDT_ENTRY 256 7 | 8 | #ifndef IDT_DEBUG 9 | #undef LOG_INFO 10 | #define LOG_INFO(...) 11 | #endif 12 | 13 | typedef struct { 14 | uint16_t size; 15 | uintptr_t offset; 16 | } PACKED idt_descriptor_t; 17 | 18 | typedef struct { 19 | uint16_t offset_0_16; 20 | uint16_t code_segment; 21 | uint8_t ist; 22 | uint8_t attributes; 23 | uint16_t offset_16_32; 24 | uint32_t offset_32_63; 25 | uint32_t _zero; 26 | } PACKED idt_entry; 27 | 28 | typedef struct { 29 | idt_entry entries[nIDT_ENTRY]; 30 | } PACKED idt_t; 31 | 32 | idt_entry create_idt_entry(uintptr_t handler, uint8_t ist, uint8_t idt_flags) { 33 | return (idt_entry){ 34 | .attributes = idt_flags, 35 | .ist = ist, 36 | 37 | .offset_0_16 = (handler), 38 | .offset_16_32 = (handler >> 16), 39 | .offset_32_63 = (handler >> 32), 40 | 41 | .code_segment = GDT_KERNEL_CODE * 8, 42 | ._zero = 0 43 | }; 44 | } 45 | 46 | static idt_t idt = {}; 47 | static idt_descriptor_t idt_descriptor = { 48 | .size = sizeof(idt_entry) * nIDT_ENTRY, 49 | .offset = (uintptr_t)(&idt) 50 | }; 51 | 52 | void(*isr[256])(volatile stackframe*); 53 | 54 | extern void isr0(void); 55 | extern void isr1(void); 56 | extern void isr2(void); 57 | extern void isr3(void); 58 | extern void isr4(void); 59 | extern void isr5(void); 60 | extern void isr6(void); 61 | extern void isr7(void); 62 | extern void isr8(void); 63 | extern void isr9(void); 64 | extern void isr10(void); 65 | extern void isr11(void); 66 | extern void isr12(void); 67 | extern void isr13(void); 68 | extern void isr14(void); 69 | extern void isr15(void); 70 | extern void isr16(void); 71 | extern void isr17(void); 72 | extern void isr18(void); 73 | extern void isr19(void); 74 | extern void isr20(void); 75 | extern void isr21(void); 76 | extern void isr22(void); 77 | extern void isr23(void); 78 | extern void isr24(void); 79 | extern void isr25(void); 80 | extern void isr26(void); 81 | extern void isr27(void); 82 | extern void isr28(void); 83 | extern void isr29(void); 84 | extern void isr30(void); 85 | extern void isr31(void); 86 | extern void irq0(void); 87 | extern void irq1(void); 88 | extern void irq2(void); 89 | extern void irq3(void); 90 | extern void irq4(void); 91 | extern void irq5(void); 92 | extern void irq6(void); 93 | extern void irq7(void); 94 | extern void irq8(void); 95 | extern void irq9(void); 96 | extern void irq10(void); 97 | extern void irq11(void); 98 | extern void irq12(void); 99 | extern void irq13(void); 100 | extern void irq14(void); 101 | extern void irq15(void); 102 | extern void isr127(void); 103 | extern void isr129(void); 104 | 105 | #define IDT_PRESENT (0b10000000) 106 | #define IDT_INTERRUPT (0b00001110) 107 | #define IDT_TRAP (0b00001111) 108 | 109 | #define set_isr_entry(n) idt.entries[n] = create_idt_entry((uintptr_t)isr## n, 0, IDT_PRESENT | IDT_INTERRUPT) 110 | #define set_irq_entry(n) idt.entries[n+32] = create_idt_entry((uintptr_t)irq## n, 0, IDT_PRESENT | IDT_INTERRUPT) 111 | 112 | extern void load_idt(idt_descriptor_t*); 113 | 114 | void setup_idt(void) { 115 | 116 | LOG_INFO("Setting up IDT..."); 117 | 118 | set_isr_entry(0); 119 | set_isr_entry(1); 120 | set_isr_entry(2); 121 | set_isr_entry(3); 122 | set_isr_entry(4); 123 | set_isr_entry(5); 124 | set_isr_entry(6); 125 | set_isr_entry(7); 126 | set_isr_entry(8); 127 | set_isr_entry(9); 128 | set_isr_entry(10); 129 | set_isr_entry(11); 130 | set_isr_entry(12); 131 | set_isr_entry(13); 132 | set_isr_entry(14); 133 | set_isr_entry(15); 134 | set_isr_entry(16); 135 | 136 | set_isr_entry(17); 137 | set_isr_entry(18); 138 | set_isr_entry(19); 139 | 140 | asm volatile("push rax; mov rax, cr4; or rax, (1<<10); mov cr4, rax; pop rax"); 141 | LOG_OK("Added SIMD exception handler..."); 142 | 143 | set_isr_entry(20); 144 | set_isr_entry(21); 145 | set_isr_entry(22); 146 | set_isr_entry(23); 147 | set_isr_entry(24); 148 | set_isr_entry(25); 149 | set_isr_entry(26); 150 | set_isr_entry(27); 151 | set_isr_entry(28); 152 | set_isr_entry(29); 153 | set_isr_entry(30); 154 | set_isr_entry(31); 155 | set_irq_entry(0); 156 | 157 | 158 | set_isr_entry(127); 159 | set_isr_entry(129); 160 | 161 | 162 | load_idt(&idt_descriptor); 163 | 164 | LOG_OK("IDT loaded, IDT descriptor at {x}, IDT at {x} of size {d}", &idt_descriptor, idt_descriptor.offset, idt_descriptor.size); 165 | } 166 | 167 | void log_stackframe(volatile stackframe* regs){ 168 | LOG_PANIC("Stackframe :\nr15 : {x}\tr14 : {x}\tr13 : {x}\tr12 : {x}\nr11 : {x}\tr10 : {x}\tr9 : {x}\tr8 : {x}\nrbp : {x}\t" 169 | "rdi : {x}\trsi : {x}\nrdx : {x}\trcx : {x}\trbx : {x}\nrax : {x}\tint_no : {x}\t err_code : {x}\nrip : {x}\tcs : {x}\trflags : {x}\nprev. rsp : {x} \tss : {x}", 170 | regs->r15, 171 | regs->r14, 172 | regs->r13, 173 | regs->r12, 174 | regs->r11, 175 | regs->r10, 176 | regs->r9, 177 | regs->r8, 178 | regs->rbp, 179 | regs->rdi, 180 | regs->rsi, 181 | regs->rdx, 182 | regs->rcx, 183 | regs->rbx, 184 | regs->rax, 185 | regs->int_no, 186 | regs->err_code, 187 | regs->rip, 188 | regs->cs, 189 | regs->rflags, 190 | regs->useresp, 191 | regs->ss 192 | ); 193 | } 194 | 195 | void isr_handler(volatile stackframe regs) { 196 | 197 | // LOG_INFO("ISR handler called..."); 198 | // log_stackframe(®s); 199 | // LOG_INFO("Interrupt number : {d}.", regs.int_no); 200 | void(*cur_isr)(volatile stackframe*) = isr[regs.int_no]; 201 | 202 | LOG_INFO("Interrupt number {d}, ISR to call at : {x}", regs.int_no, cur_isr); 203 | 204 | 205 | if (cur_isr != 0){ 206 | cur_isr(®s); 207 | } else { 208 | LOG_PANIC("Calling null isr"); 209 | log_stackframe(®s); 210 | while(1) asm volatile("hlt"); 211 | } 212 | } 213 | void irq_handler(volatile stackframe regs) { 214 | 215 | // LOG_INFO("ISR handler called..."); 216 | // log_stackframe(®s); 217 | // LOG_INFO("Interrupt number : {d}.", regs.int_no); 218 | void(*cur_isr)(volatile stackframe*) = isr[regs.int_no]; 219 | 220 | LOG_INFO("Interrupt number {d}, ISR to call at : {x}", regs.int_no, cur_isr); 221 | 222 | 223 | if (cur_isr != 0){ 224 | cur_isr(®s); 225 | } else { 226 | LOG_PANIC("Calling null isr"); 227 | log_stackframe(®s); 228 | while(1) asm volatile("hlt"); 229 | } 230 | cpu_send_EOI(); 231 | } 232 | 233 | void attach_isr(uint8_t interrupt_number, void(*isr_to_add)(volatile stackframe*)) { 234 | isr[interrupt_number] = isr_to_add; 235 | LOG_INFO("Attached isr at {x} to interrupt number {d}.", isr_to_add, interrupt_number); 236 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/kernel_exceptions.c: -------------------------------------------------------------------------------- 1 | #include "freestanding.h" 2 | #include "tables/idt.h" 3 | #include "log/log.h" 4 | #include "intel/simd.h" 5 | #include "interrupts/stackframe.h" 6 | 7 | void panic_common_stub(volatile stackframe* regs){ 8 | LOG_PANIC("Keep kalm, don't panik. Here is a dump of the registers :"); 9 | log_stackframe(regs); 10 | while(1) asm volatile("hlt"); 11 | } 12 | 13 | void k_div_by_zero(volatile stackframe* regs){ 14 | LOG_PANIC("Interrupt number : {d} (Div by 0)", regs->int_no); 15 | panic_common_stub(regs); 16 | } 17 | 18 | void k_gpf(volatile stackframe* regs){ 19 | LOG_PANIC("Interrupt number : {d} (GPF)", regs->int_no); 20 | panic_common_stub(regs); 21 | } 22 | 23 | void k_page_fault(volatile stackframe* regs){ 24 | LOG_PANIC("Interrupt number : {d} (Page Fault)", regs->int_no); 25 | LOG_PANIC("Page Fault due to: {s} | {s} | {s}", 26 | (regs->err_code & 0b0001 ? "Page protection violation" : "Not present page"), 27 | (regs->err_code & 0b0010 ? "Write access" : "Read Access"), 28 | (regs->err_code & 0b0100 ? "Fault in userspace" : "Fault in privileged segment")); 29 | uint64_t faulty_address; 30 | asm volatile("mov %0, cr2" : "=a"(faulty_address) :); 31 | LOG_PANIC("Faulty address is {x}", faulty_address); 32 | panic_common_stub(regs); 33 | } 34 | 35 | void k_debug(volatile stackframe* regs){ 36 | LOG_INFO("Debugging instruction {x}", regs->rip); 37 | log_stackframe(regs); 38 | LOG_INFO("End of Debug"); 39 | } 40 | 41 | void k_breakpoint(volatile stackframe* regs){ 42 | LOG_INFO("Breakpoint at {x}", regs->rip); 43 | log_stackframe(regs); 44 | LOG_INFO("End of breakpoint"); 45 | } 46 | 47 | void change_debug_mode(volatile stackframe* regs){ 48 | LOG_ERR("Switching debug mode. Current is {s}", (regs->rflags & (1 << 8) ? "enabled" : "disabled")); 49 | regs->rflags ^= (1 << 8); 50 | } 51 | 52 | void k_invalid_opcode(volatile stackframe* regs){ 53 | LOG_PANIC("Invalid opcode at {x}", regs->rip); 54 | panic_common_stub(regs); 55 | } 56 | void timer(volatile stackframe* regs){ 57 | 58 | UNUSED_VAR(regs); 59 | 60 | save_simd_context(CONTEXT_FRAME_ADDR); 61 | LOG_INFO("timer plouf"); 62 | } 63 | 64 | void switch_task_from_interrupt(volatile stackframe* regs); 65 | 66 | void attach_kernel_exceptions(){ 67 | attach_isr(0, &k_div_by_zero); 68 | attach_isr(1, &k_debug); 69 | attach_isr(3, &k_breakpoint); 70 | attach_isr(6, &k_invalid_opcode); 71 | attach_isr(13, &k_gpf); 72 | attach_isr(14, &k_page_fault); 73 | attach_isr(32, &switch_task_from_interrupt); 74 | attach_isr(127, &change_debug_mode); 75 | LOG_OK("Kernel exceptions attached to ISRs."); 76 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/pmm.c: -------------------------------------------------------------------------------- 1 | #include "pmm/pmm.h" 2 | #include "log/log.h" 3 | #include "vmm/vmm.h" 4 | 5 | #ifndef PMM_DEBUG 6 | #undef LOG_INFO 7 | #define LOG_INFO(...) 8 | #endif 9 | 10 | typedef struct { 11 | uint64_t aligned_base; 12 | uint64_t length; 13 | uint64_t first_frame_number; 14 | } localisation_data; 15 | 16 | static struct stivale2_mmap_entry * memmap = 0; 17 | static uint64_t entry_number = 0; 18 | static uint64_t pg_size = 0; 19 | static bool is_bitmap_set = 0; 20 | static uint64_t nframes = 0; 21 | static uint64_t number_of_frames_without_bitmap = 0; 22 | static uint64_t number_of_frames_without_bitmap_in_c = 0; 23 | static struct stivale2_mmap_entry available[20] = {0}; 24 | static localisation_data loc_datas[20] = {0}; 25 | static uint64_t* bitmap_addr = 0; 26 | 27 | uint64_t align(uint64_t addr){ 28 | uint64_t temp = addr & (((uint64_t)-1ll) * pg_size); 29 | if(temp == addr) 30 | return temp; 31 | return temp + pg_size; 32 | } 33 | 34 | void set_frame(uint64_t frame){ 35 | bitmap_addr[frame/64] |= (1ull << (frame%64)); 36 | } 37 | 38 | 39 | void flip_frame(uint64_t frame){ 40 | // LOG_INFO("Flipping frame number {d}", frame); 41 | bitmap_addr[frame/64] ^= (1ull << (frame%64)); 42 | } 43 | 44 | uint64_t read_frame(uint64_t frame){ 45 | return (bitmap_addr[frame/64] >> (frame%64))&1; 46 | } 47 | 48 | 49 | uintptr_t get_frame(){ 50 | static size_t prev_i = 0; 51 | if(!is_bitmap_set) { 52 | for(size_t i = prev_i; available[i].length; i++) { 53 | if(i > prev_i) 54 | number_of_frames_without_bitmap_in_c = 0; 55 | // LOG_INFO("page size : {x}", pg_size); 56 | // LOG_INFO("align of {x} : {x}", available[i].base, align(available[i].base)); 57 | uint64_t current_frame = align(available[i].base) + ((number_of_frames_without_bitmap_in_c) * pg_size); 58 | if(current_frame < align(available[i].base) + available[i].length - pg_size){ 59 | number_of_frames_without_bitmap_in_c++; 60 | number_of_frames_without_bitmap++; 61 | LOG_INFO("PMM : allocating frame without bitmap, number {d} at {x}.", number_of_frames_without_bitmap, current_frame); 62 | //LOG_ERR("TODO : clean the allocated frames."); 63 | for(uint64_t* i = physical_to_stivale(current_frame); (uintptr_t)i < (uintptr_t)physical_to_stivale(current_frame + pg_size); i++) 64 | *i = 0; 65 | prev_i = i; 66 | return current_frame; 67 | } 68 | } 69 | } else{ 70 | size_t i = 0; 71 | while(i < nframes/64 && bitmap_addr[i] == 0xffffffffffffffff) //== (uint64_t)-1) 72 | i++; 73 | 74 | if(i != nframes/64){ 75 | size_t j = 0; 76 | while(bitmap_addr[i] & (1ull << (j))) 77 | j++; 78 | size_t z = 0; 79 | uint64_t cur_frame_n = i * 64 + j; 80 | // LOG_INFO("i = {x}, j = {x}", i, j) 81 | const uint64_t CUR_FRAME_N = cur_frame_n; 82 | while(available[z].length){ 83 | uint64_t current_frame = align(available[z].base) + ((cur_frame_n) * pg_size); 84 | // LOG_INFO("Current frame to check : {x} = align({x}) + {x} * {x}", current_frame, available[z].base, cur_frame_n, pg_size); 85 | if(current_frame <= align(available[z].base) + available[z].length - pg_size){ 86 | flip_frame(CUR_FRAME_N); 87 | for(uint64_t* i = physical_to_stivale(current_frame); (uintptr_t)i < (uintptr_t)physical_to_stivale(current_frame + pg_size); i++) 88 | *i = 0; 89 | return current_frame; 90 | } 91 | // LOG_INFO("{x} -= {x} / {x} ({x})", cur_frame_n, available[z].length, pg_size, available[z].length / pg_size); 92 | cur_frame_n -= available[z].length / pg_size; 93 | z++; 94 | } 95 | } 96 | } 97 | LOG_PANIC("Not enough memory for allocation."); 98 | asm volatile ("cli"); 99 | while(1) asm volatile("hlt"); 100 | } 101 | 102 | 103 | void init_pmm(uintptr_t virtual_addr){ 104 | 105 | ONCE(); 106 | 107 | is_bitmap_set = 1; 108 | bitmap_addr = (uint64_t*)virtual_addr; 109 | 110 | LOG_INFO("Got virtual memory address of bitmap at {x}", bitmap_addr); 111 | 112 | for(size_t i = 0; i < (nframes/64)+1; i++) 113 | bitmap_addr[i] = 0; 114 | 115 | LOG_INFO("{d} frames set to unused (0)...", ((nframes/64)+1)*64); 116 | 117 | LOG_INFO("Number of frames previously allocated (without bitmap): {d}", number_of_frames_without_bitmap); 118 | 119 | for(uint64_t i = 0; i < number_of_frames_without_bitmap; i++) 120 | flip_frame(i); 121 | 122 | LOG_INFO("{d} frames set to used due to bitmap...", number_of_frames_without_bitmap); 123 | 124 | uint64_t i = 0; 125 | uint64_t current_nframes = 0; 126 | for(; available[i].length; i++){ 127 | 128 | uint64_t base = align(available[i].base); 129 | 130 | loc_datas[i] = (localisation_data){ 131 | .aligned_base = base, 132 | .first_frame_number = current_nframes, 133 | .length = available[i].length - (base - available[i].base) 134 | }; 135 | 136 | current_nframes += loc_datas[i].length / 0x1000; 137 | 138 | LOG_INFO("Chunk informations : Created entry {d} { base:= {x}, start frame index:= {x}, length := {x}", 139 | i, loc_datas[i].aligned_base, loc_datas[i].first_frame_number, loc_datas[i].length); 140 | } 141 | 142 | LOG_OK("Physical Memory Manager initialized successfully."); 143 | } 144 | 145 | void set_memory_map(struct stivale2_struct_tag_memmap * memmap_tag){ 146 | LOG_INFO("PMM : got the memory map at {x}, of size {d}", memmap_tag->memmap, memmap_tag->entries); 147 | memmap = memmap_tag->memmap; 148 | entry_number = memmap_tag->entries; 149 | for(size_t i = 0; i < entry_number; i++){ 150 | struct stivale2_mmap_entry x = memmap[i]; 151 | if(x.type & 1 && !(x.type ^ 1)) 152 | { 153 | LOG_INFO("Entry {d} := Base : {x}, Length : {d}, Type : {x}, Unused : {d}", i, x.base, x.length, x.type, x.unused); 154 | } 155 | } 156 | LOG_OK("Memory map dump done."); 157 | } 158 | 159 | uint64_t get_size_in_bits(uint64_t page_size){ 160 | pg_size = page_size; 161 | uint64_t total_frames = 0; 162 | uint16_t available_entries = 0; 163 | for(size_t i = 0; i < entry_number; i++){ 164 | struct stivale2_mmap_entry x = memmap[i]; 165 | if(x.type & 1 && !(x.type ^ 1)){ 166 | total_frames += x.length / page_size; 167 | available[available_entries++] = x; 168 | } 169 | } 170 | LOG_INFO("PMM : {d} usable frames of {x} bits.", total_frames, page_size); 171 | nframes = total_frames; 172 | return total_frames; 173 | } 174 | 175 | void free_frame(uintptr_t address) { 176 | 177 | uintptr_t addr = address & CLEAN_BITS_MASK; 178 | 179 | LOG_INFO("PMM : Asking to free address {x}, freeing frame at {x}", address, addr); 180 | 181 | size_t i = 0; 182 | while(loc_datas[i].length){ 183 | 184 | LOG_INFO("Chunk informations : Examining entry {d} { base:= {x}, start frame index:= {x}, length := {x}", 185 | i, loc_datas[i].aligned_base, loc_datas[i].first_frame_number, loc_datas[i].length); 186 | 187 | if(addr >= loc_datas[i].aligned_base + loc_datas[i].length || addr < loc_datas[i].aligned_base){ 188 | i++; 189 | continue; 190 | } 191 | 192 | uint64_t frame_number = loc_datas[i].first_frame_number + (addr - loc_datas[i].aligned_base) / pg_size; 193 | LOG_INFO("PMM : Freed frame number {d} matching address {x} in block number {d}.", frame_number, addr, i); 194 | // LOG_INFO("{d} + ({x} - {x}) / {d} = {d};", loc_datas[i].first_frame_number, addr, loc_datas[i].aligned_base, pg_size, frame_number); 195 | 196 | flip_frame(frame_number); 197 | 198 | 199 | i++; 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/rsdt.c: -------------------------------------------------------------------------------- 1 | #include "UEFI/RSDT.h" 2 | #include "log/log.h" 3 | #include "vmm/vmm.h" 4 | #include "UEFI/hpet.h" 5 | 6 | #ifndef RSDT_DEBUG 7 | #undef LOG_INFO 8 | #define LOG_INFO(...) 9 | #endif 10 | 11 | //static RSDPDescriptor20 RSDP_desc = {0}; 12 | 13 | static RSDPDescriptor20* desc_rsdp_20 = 0; 14 | uint64_t io_apic_register = 0; 15 | uint64_t lapic_register = 0; 16 | apic_info_t apic_info = {0}; 17 | 18 | // this function gets the RSDT from the RSDP passed in parameter 19 | void parse_RSDP(uint64_t rsdp_address){ 20 | 21 | ONCE(); 22 | 23 | if(desc_rsdp_20->firstPart.Revision) 24 | desc_rsdp_20 = (RSDPDescriptor20*)rsdp_address; 25 | 26 | volatile char rsdp_string[9] = {0}; 27 | memcpy(rsdp_string , (volatile void*)rsdp_address, 8); 28 | LOG_INFO("RSDP is located at {x}, rsdp string is \"{s}\"", rsdp_address, rsdp_string); 29 | 30 | ASSERT(!strcmp(rsdp_string,"RSD PTR "), "Got RSDP successfully at address {x}", "Error while getting RSDP at address {x}", rsdp_address); 31 | 32 | LOG_INFO("RSDP Version {d}.0 detected", desc_rsdp_20->firstPart.Revision+1); 33 | 34 | desc_rsdp_20 = (RSDPDescriptor20*)physical_to_stivale((uint64_t)desc_rsdp_20); 35 | 36 | LOG_INFO("Virtual RSDP address at {x}", desc_rsdp_20); 37 | 38 | } 39 | 40 | bool checksum(ACPISDTHeader* header){ 41 | uint8_t sum = 0; 42 | for(size_t i = 0; i < header->Length; i++){ 43 | sum += ((char*)header)[i]; 44 | } 45 | return sum == 0; 46 | } 47 | 48 | 49 | void parse_MADT(MADT* madt){ 50 | LOG_INFO("Parsing the MADT table"); 51 | char* ptr = (char*)madt + MADT_ENTRY_START; 52 | LOG_INFO("LAPIC address is: {x}", madt->lapic_addr); 53 | apic_info.lapic_address = madt->lapic_addr; 54 | 55 | while (ptr < (char*)madt + madt->h.Length) 56 | { 57 | switch (ptr[0]) 58 | { 59 | case MADT_LAPIC: 60 | { 61 | if (ptr[4] & 1) 62 | { 63 | apic_info.lapics[apic_info.numcore++] = *(madt_lapic_entry_t *)(ptr + 2); 64 | LOG_INFO("Processor {x} is {s}", ptr[2], (ptr[4] & 0) ? "enable" : "disable"); 65 | } 66 | else 67 | { 68 | LOG_INFO("Processor {x} can't be enable", ptr[2]); 69 | } 70 | } 71 | break; 72 | case MADT_IOAPIC: 73 | { 74 | LOG_INFO("local I/O apic, id: {x} register: {x}, Global system interrupt base: {x}", ptr[1], *((uint32_t *)(ptr + 4)), *((uint32_t *)(ptr + 8))); 75 | apic_info.ioapic = (ioapic_entry_t){.id = ptr[1], .address = *((uint32_t *)(ptr + 4)), .base = *((uint32_t *)(ptr + 8))}; 76 | } 77 | break; 78 | case MADT_INT_SRC_OVR: 79 | { 80 | LOG_INFO("Interrupt Source Override, Bus: {d} | IRQ: {d} | Global system interrupt {x}", ptr[2], ptr[3], *((uint32_t *)(ptr + 4))); 81 | apic_info.interrupt[apic_info.interrupt_count++] = *(interrupt_source_override *)(ptr + 2); 82 | } 83 | break; 84 | case MADT_LAPIC_ADDR_OVR: 85 | { 86 | LOG_INFO("Local APIC address is: {x}", *((uint64_t *)(ptr + 4))); 87 | apic_info.lapic_address = *((uint64_t *)(ptr + 4)); 88 | } 89 | break; 90 | case MADT_LAPIC_NNMI: 91 | { 92 | LOG_INFO("Non maskable int for processor: {x} | flags: {x} | LINT: {x}", ptr[2], *(uint16_t*)(ptr+3), ptr[5]); 93 | apic_info.nmis[apic_info.nmi_count++] = *(LAPIC_NMI*)(ptr+2); 94 | } 95 | break; 96 | default: 97 | LOG_INFO("MADT entry {x} is not yet implemented", *ptr) 98 | break; 99 | } 100 | ptr += ptr[1]; 101 | } 102 | LOG_INFO("{d} core(s) detected", apic_info.numcore); 103 | } 104 | 105 | void parse_RSDT(){ 106 | RSDT *rsdt = (RSDT*)physical_to_stivale(desc_rsdp_20->firstPart.RsdtAddress); 107 | size_t entries = (rsdt->h.Length - sizeof(ACPISDTHeader)) / 4; 108 | for (size_t i = 0; i < entries; i++) 109 | { 110 | char name[5] = {0}; 111 | ACPISDTHeader *h = (ACPISDTHeader *)physical_to_stivale(rsdt->PointersToOtherSDT[i]); 112 | memcpy(name, h->Signature,4); 113 | ASSERT(checksum(h), "Table {s} is valid", "Table {s} is invalid", name); 114 | 115 | if(!strcmp(name,"APIC")){ 116 | parse_MADT((MADT*)h); 117 | } 118 | else if(!strcmp(name,"HPET")){ 119 | hpet_init((HPET*)h); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/arch/x86_64/src/serial.c: -------------------------------------------------------------------------------- 1 | #include "serial/com.h" 2 | #include "intel/asm.h" 3 | #include "utils/functions.h" 4 | 5 | void com_write_reg(enum com_port port, enum com_register reg, uint8_t value){ 6 | asm_out8(port + reg, value); 7 | } 8 | 9 | uint8_t com_read_reg(enum com_port port, enum com_register reg) 10 | { 11 | return asm_in8(port + reg); 12 | } 13 | 14 | bool com_can_write(enum com_port port){ 15 | return (com_read_reg(port, COM_LINE_STATUS) & COM_LINE_TRANSMITTER_BUFFER_EMPTY); 16 | } 17 | 18 | void com_wait_write(enum com_port port){ 19 | while(!com_can_write(port)); 20 | } 21 | 22 | void com_putc(enum com_port port, char c){ 23 | com_wait_write(port); 24 | com_write_reg(port, COM_DATA, c); 25 | } 26 | 27 | size_t com_write(enum com_port port, void const *buffer, size_t size) { 28 | for (size_t i = 0; i < size && ((char const *)buffer)[i]; i++) 29 | com_putc(port, ((char const *)buffer)[i]); 30 | 31 | return size; 32 | } 33 | 34 | void com_initialize(enum com_port port) 35 | { 36 | com_write_reg(port, COM_INTERRUPT_IDENTIFICATOR, 0); 37 | 38 | // Turn on dlab for setting baud rate 39 | com_write_reg(port, COM_LINE_CONTROL, COM_DLAB_STATUS); 40 | 41 | // Set bauds 42 | com_write_reg(port, COM_BAUD_RATE_LOW, 115200 / 9600); 43 | com_write_reg(port, COM_BAUD_RATE_HIGH, 0); 44 | 45 | // we want 8bit caracters + clear dlab 46 | com_write_reg(port, COM_LINE_CONTROL, COM_DATA_SIZE_8); 47 | 48 | // turn on communication + redirect UART interrupt into ICU 49 | com_write_reg(port, COM_MODEM_CONTROL, COM_MODEM_DTR | COM_MODEM_RTS | COM_MODEM_OUT2); 50 | com_write_reg(port, COM_INTERRUPT, COM_INTERRUPT_WHEN_DATA_AVAILABLE); 51 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/smp.c: -------------------------------------------------------------------------------- 1 | #include "freestanding.h" 2 | #include "thirdparties/stivale2.h" 3 | #include "freestanding.h" 4 | #include "log/log.h" 5 | #include "thirdparties/stivalemgr.h" 6 | #include "tables/gdt.h" 7 | #include "tables/idt.h" 8 | #include "interrupts/kernel_exceptions.h" 9 | #include "pmm/pmm.h" 10 | #include "vmm/vmm.h" 11 | #include "intel/cpuinfo.h" 12 | #include "intel/asm.h" 13 | #include "UEFI/RSDT.h" 14 | #include "SMP/SMP.h" 15 | #include 16 | #include "multicore/lock.h" 17 | #include "UEFI/APIC.h" 18 | #include "syscall-enabling/syscall.h" 19 | 20 | 21 | // static uint8_t value = 0; 22 | static bool smp_status = 0; 23 | static uint8_t booted_cpus_count = 1; 24 | 25 | uint8_t get_booted_cpus_count(){ 26 | return booted_cpus_count; 27 | } 28 | 29 | uint32_t get_core_id_(uint32_t* lapic_id){ 30 | static uint32_t id = 0; 31 | 32 | ONCE (id); 33 | 34 | LOG_PANIC("PLOUFFFFF"); 35 | 36 | id = *lapic_id; 37 | 38 | return id; 39 | } 40 | 41 | uint32_t id = 0; 42 | void set_core_id(uint32_t lapic_id){ 43 | id = lapic_id; 44 | } 45 | 46 | uint32_t get_core_id(){ 47 | if(smp_status) 48 | return cpuReadLAPIC(0x20) >> 24; 49 | return 0; 50 | } 51 | 52 | CREATE_LOCK(1) 53 | CREATE_LOCK(Bootstrap) 54 | 55 | typedef void (*launching_address)(); 56 | launching_address *launching_addresses; 57 | 58 | void _start_core(struct stivale2_smp_info* smp_info){ 59 | 60 | GRAB_LOCK(LOCK_NAME(Bootstrap)); 61 | RELEASE_LOCK(LOCK_NAME(Bootstrap)); 62 | 63 | BEGIN_BOTTLENECK(1); 64 | 65 | smp_status = 0; 66 | 67 | LOG_INFO("Booting an AP."); 68 | 69 | setup_gdt(); 70 | setup_idt(); 71 | attach_kernel_exceptions(); 72 | 73 | asm volatile("mov cr3, %0"::"a"(create_page_directory())); 74 | setup_context_frame(); 75 | extern void enable_sse(void); 76 | enable_sse(); 77 | LOG_OK("Page directory created and loaded successfully."); 78 | 79 | // parse_RSDT(); 80 | map_pics(); 81 | enable_APIC(); 82 | init_APIC_interrupt(); 83 | init_APIC_timer(); 84 | syscall_initialize(); 85 | 86 | smp_status = 1; 87 | smp_info = physical_to_stivale(smp_info); 88 | 89 | booted_cpus_count++; 90 | 91 | LOG_OK("Halting CPU {d}. Initialization successful.", COREID); 92 | 93 | END_BOTTLENECK(1); 94 | 95 | asm volatile("sti"); 96 | 97 | while(1) 98 | { 99 | launching_addresses[COREID] = NULL; 100 | while(!launching_addresses[COREID] || launching_addresses[COREID] == (void*)1) 101 | ; 102 | launching_addresses[COREID](); 103 | } 104 | 105 | HALT(); 106 | 107 | } 108 | 109 | void launch_APs(struct stivale2_struct_tag_smp* smp_infos, void (*_launching_addresses[])()){ 110 | if(smp_infos->cpu_count) 111 | smp_status = 1; 112 | launching_addresses = _launching_addresses; 113 | GRAB_LOCK(LOCK_NAME(Bootstrap)); 114 | for(size_t i = 0; i < smp_infos->cpu_count;i++){ 115 | if(smp_infos->bsp_lapic_id == smp_infos->smp_info[i].lapic_id){ 116 | set_core_id(smp_infos->smp_info[i].lapic_id); 117 | continue; 118 | } 119 | LOG_ERR("Launching AP. Id {d}", smp_infos->smp_info[i].lapic_id); 120 | smp_infos->smp_info[i].target_stack = (uint64_t)physical_to_stivale(get_frame()) + 4096-64; 121 | LOG_INFO("Target stack {x}", smp_infos->smp_info[i].target_stack); 122 | smp_infos->smp_info[i].goto_address = (uint64_t)_start_core; 123 | } 124 | RELEASE_LOCK(LOCK_NAME(Bootstrap)); 125 | } 126 | 127 | bool is_smp_active(){ 128 | return smp_status; 129 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/stubs.s: -------------------------------------------------------------------------------- 1 | section .text 2 | 3 | extern isr_handler 4 | 5 | global load_gdt 6 | load_gdt: 7 | lgdt [rdi] 8 | mov ax, 0x10 9 | mov ss, ax 10 | mov ds, ax 11 | mov es, ax 12 | mov rax, qword .trampoline 13 | push qword 0x8 14 | push rax 15 | o64 retf 16 | .trampoline: 17 | ret 18 | 19 | global load_idt 20 | load_idt: 21 | lidt [rdi] 22 | ret 23 | 24 | %macro ISR_NOERRCODE 1 25 | [GLOBAL isr%1] 26 | isr%1: 27 | push QWORD 128 28 | push QWORD %1 29 | jmp isr_common_stub 30 | %endmacro 31 | 32 | %macro ISR_ERRCODE 1 33 | [GLOBAL isr%1] 34 | isr%1: 35 | push QWORD %1 36 | jmp isr_common_stub 37 | %endmacro 38 | 39 | %macro save_context 0 40 | push rax 41 | push rbx 42 | push rcx 43 | push rdx 44 | push rsi 45 | push rdi 46 | push rbp 47 | push r8 48 | push r9 49 | push r10 50 | push r11 51 | push r12 52 | push r13 53 | push r14 54 | push r15 55 | %endmacro 56 | 57 | %macro load_context 0 58 | pop r15 59 | pop r14 60 | pop r13 61 | pop r12 62 | pop r11 63 | pop r10 64 | pop r9 65 | pop r8 66 | pop rbp 67 | pop rdi 68 | pop rsi 69 | pop rdx 70 | pop rcx 71 | pop rbx 72 | pop rax 73 | %endmacro 74 | 75 | ISR_NOERRCODE 0 76 | ISR_NOERRCODE 1 77 | ISR_NOERRCODE 2 78 | ISR_NOERRCODE 3 79 | ISR_NOERRCODE 4 80 | ISR_NOERRCODE 5 81 | ISR_NOERRCODE 6 82 | ISR_NOERRCODE 7 83 | ISR_ERRCODE 8 84 | ISR_NOERRCODE 9 85 | ISR_ERRCODE 10 86 | ISR_ERRCODE 11 87 | ISR_ERRCODE 12 88 | ISR_ERRCODE 13 89 | ISR_ERRCODE 14 90 | ISR_NOERRCODE 15 91 | ISR_NOERRCODE 16 92 | ISR_NOERRCODE 17 93 | ISR_NOERRCODE 18 94 | ISR_NOERRCODE 19 95 | ISR_NOERRCODE 20 96 | ISR_NOERRCODE 21 97 | ISR_NOERRCODE 22 98 | ISR_NOERRCODE 23 99 | ISR_NOERRCODE 24 100 | ISR_NOERRCODE 25 101 | ISR_NOERRCODE 26 102 | ISR_NOERRCODE 27 103 | ISR_NOERRCODE 28 104 | ISR_NOERRCODE 29 105 | ISR_NOERRCODE 30 106 | ISR_NOERRCODE 31 107 | ISR_NOERRCODE 127 108 | ISR_NOERRCODE 128 109 | ISR_NOERRCODE 129 110 | 111 | global save_simd_context 112 | save_simd_context: 113 | fxsave64 [rdi] 114 | ret 115 | 116 | global load_simd_context 117 | load_simd_context: 118 | fxrstor64 [rdi] 119 | ret 120 | 121 | isr_common_stub: 122 | save_context 123 | call isr_handler 124 | load_context 125 | add rsp, 16 126 | iretq 127 | 128 | %macro IRQ 2 129 | [GLOBAL irq%1] 130 | irq%1: 131 | push 0 132 | push %2 133 | jmp irq_common_stub 134 | %endmacro 135 | 136 | IRQ 0, 32 137 | IRQ 1, 33 138 | IRQ 2, 34 139 | IRQ 3, 35 140 | IRQ 4, 36 141 | IRQ 5, 37 142 | IRQ 6, 38 143 | IRQ 7, 39 144 | IRQ 8, 40 145 | IRQ 9, 41 146 | IRQ 10, 42 147 | IRQ 11, 43 148 | IRQ 12, 44 149 | IRQ 13, 45 150 | IRQ 14, 46 151 | IRQ 15, 47 152 | 153 | extern irq_handler 154 | irq_common_stub: 155 | save_context 156 | call irq_handler 157 | load_context 158 | add rsp, 16 159 | sti 160 | iretq 161 | 162 | global enable_sse 163 | enable_sse: 164 | push rbp 165 | mov rbp, rsp 166 | mov rax, cr0 167 | or rax, 2 168 | mov cr0, rax 169 | mov eax, 0 170 | pop rbp 171 | ret 172 | -------------------------------------------------------------------------------- /src/arch/x86_64/src/syscall.c: -------------------------------------------------------------------------------- 1 | #include "intel/asm.h" 2 | #include "log/log.h" 3 | #include "tables/gdt.h" 4 | #include "syscall-enabling/syscall.h" 5 | #include "syscall/syscall.h" 6 | 7 | extern void syscall_stub(void); 8 | 9 | void syscall_initialize(void) 10 | { 11 | asm_write_msr(MSR_EFER, asm_read_msr(MSR_EFER) | EFER_ENABLE_SYSCALL); 12 | asm_write_msr(MSR_STAR, ((uint64_t)(GDT_KERNEL_CODE * 8) << STAR_KCODE_OFFSET) | ((uint64_t)(((GDT_USER_DATA - 1) * 8) | GDT_USER_CODE) << STAR_UCODE_OFFSET)); 13 | asm_write_msr(MSR_LSTAR, (uint64_t)syscall_stub); 14 | asm_write_msr(MSR_SYSCALL_FLAG_MASK, 0); 15 | } 16 | 17 | struct syscall_frame { 18 | uint64_t r15; 19 | uint64_t r14; 20 | uint64_t r13; 21 | uint64_t r12; 22 | uint64_t r11; 23 | uint64_t r10; 24 | uint64_t r9; 25 | uint64_t r8; 26 | uint64_t rbp; 27 | uint64_t rdi; 28 | uint64_t rsi; 29 | uint64_t rdx; 30 | uint64_t rcx; 31 | uint64_t rbx; 32 | // uint64_t rax; 33 | }; 34 | 35 | void arch_syscall_handler(volatile struct syscall_frame frame) 36 | { 37 | struct syscall_pack pack; 38 | 39 | asm volatile("mov %0, r15" : "=r"(pack.syscall_id)); 40 | asm volatile("mov %0, rdi" : "=r"(pack.arg1)); 41 | asm volatile("mov %0, rsi" : "=r"(pack.arg2)); 42 | asm volatile("mov %0, r8" : "=r"(pack.arg3)); 43 | asm volatile("mov %0, r9" : "=r"(pack.arg4)); 44 | asm volatile("mov %0, r10" : "=r"(pack.arg5)); 45 | 46 | LOG_INFO("syscall_handler called"); 47 | 48 | asm volatile("mov rax, %0" : : "r"(syscall_handler(&pack))); 49 | 50 | UNUSED_VAR(frame); 51 | } -------------------------------------------------------------------------------- /src/arch/x86_64/src/syscall_stub.s: -------------------------------------------------------------------------------- 1 | %macro save_regs 0 2 | ; push rax 3 | push rbx 4 | push rcx 5 | push rdx 6 | push rsi 7 | push rdi 8 | push rbp 9 | push r8 10 | push r9 11 | push r10 12 | push r11 13 | push r12 14 | push r13 15 | push r14 16 | push r15 17 | %endmacro 18 | 19 | %macro pop_regs 0 20 | pop r15 21 | pop r14 22 | pop r13 23 | pop r12 24 | pop r11 25 | pop r10 26 | pop r9 27 | pop r8 28 | pop rbp 29 | pop rdi 30 | pop rsi 31 | pop rdx 32 | pop rcx 33 | pop rbx 34 | %endmacro 35 | 36 | extern arch_syscall_handler 37 | global syscall_stub 38 | syscall_stub: 39 | sub rsp, 128 ;red zone skipping 40 | save_regs 41 | call arch_syscall_handler 42 | pop_regs 43 | add rsp, 128 44 | o64 sysret 45 | -------------------------------------------------------------------------------- /src/arch/x86_64/src/tagmgr.c: -------------------------------------------------------------------------------- 1 | #include "thirdparties/stivale2.h" 2 | #include "freestanding.h" 3 | 4 | static uint8_t stack[8192]; 5 | void _start(struct stivale2_struct *stivale2_struct); 6 | 7 | //extern void* _start; 8 | 9 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) { 10 | struct stivale2_tag *current_tag = (void *)stivale2_struct->tags; 11 | for (;;) { 12 | // If the tag pointer is NULL (end of linked list), we did not find 13 | // the tag. Return NULL to signal this. 14 | if (current_tag == NULL) { 15 | return NULL; 16 | } 17 | 18 | // Check whether the identifier matches. If it does, return a pointer 19 | // to the matching tag. 20 | if (current_tag->identifier == id) { 21 | return current_tag; 22 | } 23 | 24 | // Get a pointer to the next tag in the linked list and repeat. 25 | current_tag = (void *)current_tag->next; 26 | } 27 | } 28 | 29 | /* 30 | static struct stivale2_header_tag_terminal terminal_hdr_tag = { 31 | .tag = { 32 | .identifier = STIVALE2_HEADER_TAG_TERMINAL_ID, 33 | .next = 0 34 | }, 35 | .flags = 0 36 | };*/ 37 | 38 | static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = { 39 | // Same as above. 40 | /*.tag = { 41 | .identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID, 42 | .next = (uint64_t)&terminal_hdr_tag 43 | }, 44 | .framebuffer_width = 0, 45 | .framebuffer_height = 0, 46 | .framebuffer_bpp = 0*/ 47 | .tag = 48 | { 49 | .identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID, 50 | .next = 0 // fin de la liste 51 | }, 52 | .framebuffer_width = 1440, 53 | .framebuffer_height = 900, 54 | .framebuffer_bpp = 32 55 | }; 56 | 57 | static struct stivale2_struct_tag_memmap memmap_tag = { 58 | .tag = { 59 | .identifier = STIVALE2_STRUCT_TAG_MEMMAP_ID, 60 | .next = (uint64_t)&framebuffer_hdr_tag 61 | }, 62 | .entries = 0, 63 | .memmap = {{0}} 64 | }; 65 | 66 | static struct stivale2_struct_tag_rsdp rsdp_tag = { 67 | .tag = { 68 | .identifier = STIVALE2_STRUCT_TAG_RSDP_ID, 69 | .next = (uint64_t)&memmap_tag 70 | }, 71 | .rsdp = 0 72 | }; 73 | 74 | static struct stivale2_struct_tag_smp smp_result = { 75 | .tag = { 76 | .identifier = STIVALE2_STRUCT_TAG_SMP_ID, 77 | .next = (uint64_t)&rsdp_tag 78 | }, 79 | .flags = 0 80 | }; 81 | 82 | static struct stivale2_header_tag_smp smp_tag = { 83 | .tag = { 84 | .identifier = STIVALE2_HEADER_TAG_SMP_ID, 85 | .next = (uint64_t)&smp_result 86 | }, 87 | .flags = 0 88 | }; 89 | 90 | static struct stivale2_struct_tag_modules mod_tag = { 91 | .tag = { 92 | .identifier = STIVALE2_STRUCT_TAG_MODULES_ID, 93 | .next = (uint64_t)&smp_tag 94 | }, 95 | .module_count = 0 96 | }; 97 | 98 | 99 | __attribute__((section(".stivale2hdr"), used)) 100 | static struct stivale2_header stivale_hdr = { 101 | .entry_point = (uint64_t)(_start), 102 | .stack = (uintptr_t)stack + sizeof(stack), 103 | .flags = 0, 104 | .tags = (uintptr_t)&mod_tag 105 | }; 106 | -------------------------------------------------------------------------------- /src/arch/x86_64/src/tasking.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaemonOnUnix/pEpitOS-x86_64/8a0bd155e7ea7c8b3d6ebebacd5b567353716208/src/arch/x86_64/src/tasking.c -------------------------------------------------------------------------------- /src/arch/x86_64/src/vmm.c: -------------------------------------------------------------------------------- 1 | #include "vmm/vmm.h" 2 | #include "pmm/pmm.h" 3 | #include "log/log.h" 4 | #include "interrupts/stackframe.h" 5 | 6 | #ifndef VMM_DEBUG 7 | #undef LOG_INFO 8 | #define LOG_INFO(...) 9 | #endif 10 | 11 | static uint64_t* limine_page_directory_addr = 0; 12 | 13 | void init_vmm(){ 14 | LOG_INFO("Initialising Virtual Memory Manager..."); 15 | asm volatile("mov %0, cr3" : "=a"(limine_page_directory_addr) :); 16 | limine_page_directory_addr = physical_to_stivale(limine_page_directory_addr); 17 | uint64_t* new_pdp = (uint64_t*)get_frame(); 18 | uint64_t* new_pd = physical_to_stivale(new_pdp); 19 | for(uint32_t i = 0; i < 512; i++) 20 | new_pd[i] = limine_page_directory_addr[i]; 21 | LOG_OK("Got stivale2 page directory at {x}", limine_page_directory_addr); 22 | 23 | } 24 | 25 | uint64_t craft_addr(uint64_t offset_l4, uint64_t offset_l3, uint64_t offset_l2, uint64_t offset_l1, uint64_t offset_l0){ 26 | return offset_l0 | (offset_l1 << 12 ) | (offset_l2 << 21) | (offset_l3 << 30 ) | (offset_l4 << 39); 27 | } 28 | 29 | void kmmap(uint64_t addr, size_t size, uint64_t flags){ 30 | // TODO: Kernel panic when unmap non mapped frame. 31 | uint64_t offset_l4 = SHIFTR(addr,9,39); 32 | uint64_t offset_l3 = SHIFTR(addr,9,30); 33 | uint64_t offset_l2 = SHIFTR(addr,9,21); 34 | uint64_t offset_l1 = SHIFTR(addr,9,12); 35 | uint64_t offset_l0 = (addr & mask_l0); 36 | 37 | uint64_t* entry; 38 | 39 | for (; offset_l4 < ARCH_N_ENTRY; offset_l4++){ 40 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4 * 8)); 41 | if (*entry == 0) 42 | *entry = get_frame() | flags | 1; 43 | 44 | for (; offset_l3 < ARCH_N_ENTRY; offset_l3++){ 45 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3 * 8)); 46 | LOG_INFO("Entry 1: {x}", *entry); 47 | if (*entry == 0) 48 | *entry = get_frame() | flags | 1; 49 | LOG_INFO("Entry 1: {x}", *entry); 50 | 51 | for (; offset_l2 < ARCH_N_ENTRY; offset_l2++){ 52 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2 * 8); 53 | LOG_INFO("Entry 2: {x}", *entry); 54 | if (*entry == 0) 55 | *entry = get_frame() | flags | 1; 56 | LOG_INFO("Entry 2: {x}", *entry); 57 | 58 | for (; offset_l1 < ARCH_N_ENTRY; offset_l1++){ 59 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2, offset_l1 * 8); 60 | uint64_t space_left = ARCH_PAGE_SIZE - (uint64_t)offset_l0; 61 | if (*entry == 0){ 62 | *entry = get_frame() | flags | 1; 63 | LOG_INFO("Mapping physical page {x} at address {x} ( {d} | {d} | {d} | {d} | {d} ), remaining size on frame: {x}", *entry, craft_addr(offset_l4, offset_l3, offset_l2, offset_l1, 0),offset_l4,offset_l3,offset_l2,offset_l1,offset_l0, space_left); 64 | } 65 | if (space_left >= size) 66 | return; 67 | size -= space_left; 68 | offset_l0 = 0; 69 | } 70 | offset_l1 = 0; 71 | } 72 | offset_l2 = 0; 73 | } 74 | offset_l3 = 0; 75 | } 76 | LOG_PANIC("Unable to map {d} bytes", size); 77 | } 78 | 79 | bool is_frame_empty(uint64_t* frame){ 80 | uintptr_t plouf = (uintptr_t)frame; 81 | plouf &= CLEAN_BITS_MASK; 82 | frame = (uint64_t*)plouf; 83 | size_t i = 0; 84 | while(frame[i] == 0 && i < ARCH_N_ENTRY) 85 | i++; 86 | return i == ARCH_N_ENTRY; 87 | } 88 | 89 | void kmunmap(uint64_t addr, size_t size, mem_direction direction){ 90 | if(direction == MEM_TO_LOWER) 91 | addr -= size; 92 | uint64_t offset_l4 = SHIFTR(addr, 9, 39); 93 | uint64_t offset_l3 = SHIFTR(addr, 9, 30); 94 | uint64_t offset_l2 = SHIFTR(addr, 9, 21); 95 | uint64_t offset_l1 = SHIFTR(addr, 9, 12); 96 | uint64_t offset_l0 = SHIFTR(addr, 12, 0); 97 | uint64_t* entry; 98 | 99 | LOG_INFO("Asking to unmap {d} bytes at base (virtual) {x} to {s} addresses", size, addr, (direction == MEM_TO_LOWER ? "lower" : "upper")); 100 | 101 | size_t number_of_page_freed = 0; 102 | if(offset_l0) 103 | size -= ARCH_PAGE_SIZE - offset_l0; 104 | if(size <= ARCH_PAGE_SIZE-1 || size <= offset_l0){ 105 | LOG_INFO("No frame will be freed"); 106 | return; 107 | } 108 | 109 | for (; offset_l4 < ARCH_N_ENTRY; offset_l4++){ 110 | for (; offset_l3 < ARCH_N_ENTRY; offset_l3++){ 111 | for (; offset_l2 < ARCH_N_ENTRY; offset_l2++){ 112 | for (; offset_l1 < ARCH_N_ENTRY; offset_l1++){ 113 | 114 | if (offset_l0 == 0) 115 | { 116 | entry = (void *)craft_addr(RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2, offset_l1 * 8); 117 | free_frame((uintptr_t)(*entry)); 118 | *entry = 0; 119 | 120 | size -= ARCH_PAGE_SIZE; 121 | number_of_page_freed++; 122 | } 123 | if (size < ARCH_PAGE_SIZE) 124 | { 125 | LOG_INFO("{d} pages have been freed", number_of_page_freed); 126 | return; 127 | } 128 | offset_l0 = 0; 129 | } 130 | entry = (void *)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2 * 8)); 131 | if (is_frame_empty((uint64_t *)(*entry))) 132 | { 133 | LOG_ERR("Freeing were performed on plm2"); 134 | *entry = 0; 135 | free_frame((uintptr_t)entry); 136 | } 137 | offset_l1 = 0; 138 | } 139 | entry = (void *)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3 * 8)); 140 | if (is_frame_empty((uint64_t *)(*entry))) 141 | { 142 | LOG_ERR("Freeing were performed on plm3"); 143 | *entry = 0; 144 | free_frame((uintptr_t)entry); 145 | } 146 | 147 | offset_l2 = 0; 148 | } 149 | offset_l3 = 0; 150 | entry = (void *)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4 * 8)); 151 | if (is_frame_empty((uint64_t *)(*entry))) 152 | { 153 | LOG_ERR("Freeing were performed on plm4"); 154 | *entry = 0; 155 | free_frame((uintptr_t)entry); 156 | } 157 | } 158 | } 159 | 160 | uintptr_t create_page_directory() { 161 | uint64_t* new_pdp = (uint64_t*)get_frame(); 162 | uint64_t* new_pd = physical_to_stivale(new_pdp); 163 | 164 | LOG_INFO("Created new page directory on frame {x} (manipulation address at {x})", new_pdp, new_pd); 165 | 166 | for(uint32_t i = 0; i < 512; i++) 167 | new_pd[i] = limine_page_directory_addr[i]; 168 | 169 | new_pd[RECURSIVE_MAPPING_ENTRY] = (uint64_t)new_pdp | 3; 170 | new_pd[0] = 0; 171 | 172 | return (uintptr_t)new_pdp; 173 | } 174 | 175 | void setup_context_frame(){ 176 | 177 | LOG_INFO("Setting up context frame in current virtual address space..."); 178 | 179 | uintptr_t context_save_addr = 0x7FFFFFFFF000ull; 180 | 181 | LOG_INFO("Without masking : {x} | with masking : {x}", context_save_addr, context_save_addr & CLEAN_BITS_MASK); 182 | 183 | kmmap(context_save_addr, 512, 2); 184 | 185 | LOG_INFO("Current task currently supporting context frame.") 186 | 187 | asm volatile( 188 | " \ 189 | push rax; mov rax, cr4; or rax, (1<<9); mov cr4, rax; pop rax \ 190 | " 191 | ); 192 | 193 | LOG_OK("Context frame successfully setup at address {x}", context_save_addr); 194 | } 195 | 196 | 197 | /** 198 | * Compute the amount of free "virtual byte" available at the specified address 199 | * The count stop when the size reached the value of "stop_value" 200 | **/ 201 | size_t get_size(uintptr_t base_addr, size_t stop_value){ 202 | uint64_t* entry = 0; 203 | address_64_bits address = {.address=base_addr}; 204 | 205 | size_t size = 0; 206 | for (; address.offset.plm4 < ARCH_N_ENTRY; address.offset.plm4++){ 207 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4 * 8)); 208 | if (*entry == 0){ 209 | if((size += (1ull<<39)) >= stop_value) 210 | return size; 211 | continue; 212 | } 213 | 214 | for (; address.offset.plm3 < ARCH_N_ENTRY; address.offset.plm3++){ 215 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3 * 8)); 216 | if (*entry == 0){ 217 | if((size += (1ull << 30)) >= stop_value) 218 | return size; 219 | continue; 220 | } 221 | 222 | for (; address.offset.plm2 < ARCH_N_ENTRY; address.offset.plm2++){ 223 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2 * 8); 224 | if (*entry == 0){ 225 | if((size += (1ull << 21)) >= stop_value) 226 | return size; 227 | continue; 228 | } 229 | 230 | for (; address.offset.plm1 < ARCH_N_ENTRY; address.offset.plm1++){ 231 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2, address.offset.plm1 * 8); 232 | 233 | if (*entry == 0){ 234 | size += (1ull << 12); 235 | if(size >= stop_value) 236 | return size; 237 | } 238 | else 239 | return size; 240 | } 241 | address.offset.plm1 = 0; 242 | } 243 | address.offset.plm2 = 0; 244 | } 245 | address.offset.plm3 = 0; 246 | } 247 | return size; 248 | } 249 | /** 250 | * Search the first non-mapped address beginning at base_addr 251 | * Return first non mapped address found. 252 | * Return 0 when none address are found. 253 | **/ 254 | uint64_t search_empty_space(uintptr_t base_addr){ 255 | uint64_t* entry = 0; 256 | address_64_bits address = {.address=base_addr}; 257 | 258 | for (; address.offset.plm4 < ARCH_N_ENTRY; address.offset.plm4++){ 259 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4 * 8)); 260 | if (*entry == 0) 261 | return address.address; 262 | 263 | for (; address.offset.plm3 < ARCH_N_ENTRY; address.offset.plm3++){ 264 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3 * 8)); 265 | if (*entry == 0) 266 | return address.address; 267 | 268 | for (; address.offset.plm2 < ARCH_N_ENTRY; address.offset.plm2++){ 269 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2 * 8); 270 | if (*entry == 0) 271 | return address.address; 272 | 273 | for (; address.offset.plm1 < ARCH_N_ENTRY; address.offset.plm1++){ 274 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2, address.offset.plm1 * 8); 275 | if (*entry == 0) 276 | return address.address; 277 | } 278 | address.offset.plm1 = 0; 279 | } 280 | address.offset.plm2 = 0; 281 | } 282 | address.offset.plm3 = 0; 283 | } 284 | LOG_ERR("There is no free space after the address {x}", base_addr); 285 | return 0; 286 | } 287 | 288 | void* map_physical(uint64_t physical_addr, size_t size){ 289 | uint64_t address = search_empty_space(craft_addr(1,0,0,0,0)); 290 | size_t space = 0; 291 | while(address != 0 && (space = get_size(address, size)) < size){ 292 | address = search_empty_space(address + space); 293 | } 294 | if(address == 0){ 295 | LOG_PANIC("Unable to find {d} free contiuous byte", size); 296 | } 297 | kmmap_physical(address, physical_addr, size, 2); 298 | 299 | return (void*)address; 300 | } 301 | 302 | void kmmap_physical(uint64_t addr, uint64_t physical_addr, size_t size, uint64_t flags){ 303 | uint64_t offset_l4 = SHIFTR(addr, 9, 39); 304 | uint64_t offset_l3 = SHIFTR(addr, 9, 30); 305 | uint64_t offset_l2 = SHIFTR(addr, 9, 21); 306 | uint64_t offset_l1 = SHIFTR(addr, 9, 12); 307 | uint64_t offset_l0 = SHIFTR(addr, 12, 0); 308 | uint64_t* entry; 309 | 310 | for (; offset_l4 < ARCH_N_ENTRY; offset_l4++){ 311 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4 * 8)); 312 | if (*entry == 0) 313 | *entry = get_frame() | flags | 1; 314 | 315 | for (; offset_l3 < ARCH_N_ENTRY; offset_l3++){ 316 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3 * 8)); 317 | if (*entry == 0) 318 | *entry = get_frame() | flags | 1; 319 | 320 | for (; offset_l2 < ARCH_N_ENTRY; offset_l2++){ 321 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2 * 8); 322 | if (*entry == 0) 323 | *entry = get_frame() | flags | 1; 324 | 325 | for (; offset_l1 < ARCH_N_ENTRY; offset_l1++){ 326 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, offset_l4, offset_l3, offset_l2, offset_l1 * 8); 327 | uint64_t space_left = ARCH_PAGE_SIZE - (uint64_t)offset_l0; 328 | if (*entry != 0){ 329 | // LOG_ERR("Physical page {x} at logical address {x} will be replace", *entry, entry); 330 | } 331 | *entry = physical_addr | flags | 1; 332 | // LOG_INFO("Mapping physical page {x} at address {x} ( {d} | {d} | {d} | {d} | {d} ), remaining size on frame: {x}", *entry, craft_addr(offset_l4, offset_l3, offset_l2, offset_l1, 0),offset_l4,offset_l3,offset_l2,offset_l1,offset_l0, space_left); 333 | if (space_left >= size) 334 | return; 335 | 336 | physical_addr += space_left; 337 | size -= space_left; 338 | offset_l0 = 0; 339 | } 340 | offset_l1 = 0; 341 | } 342 | offset_l2 = 0; 343 | } 344 | offset_l3 = 0; 345 | } 346 | } 347 | 348 | uint64_t search_available(uintptr_t base_addr, size_t size){ 349 | LOG_INFO("Searching for {d} bytes at {x}", size, base_addr); 350 | uint64_t* entry = 0; 351 | address_64_bits address = {.address=base_addr}; 352 | size_t page_num = size / ARCH_PAGE_SIZE; 353 | size_t space_left = size % ARCH_PAGE_SIZE; 354 | if(space_left) 355 | page_num++; 356 | 357 | size_t temp_page_num = page_num; 358 | address_64_bits beginning_address = address; 359 | 360 | for (; address.offset.plm4 < ARCH_N_ENTRY; address.offset.plm4++){ 361 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4 * 8)); 362 | if (*entry == 0) 363 | return address.address; 364 | 365 | for (; address.offset.plm3 < ARCH_N_ENTRY; address.offset.plm3++){ 366 | entry = (void*)(craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3 * 8)); 367 | if (*entry == 0) 368 | return address.address; 369 | 370 | for (; address.offset.plm2 < ARCH_N_ENTRY; address.offset.plm2++){ 371 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2 * 8); 372 | if (*entry == 0) 373 | return address.address; 374 | 375 | for (; address.offset.plm1 < ARCH_N_ENTRY; address.offset.plm1++){ 376 | entry = (void*)craft_addr(RECURSIVE_MAPPING_ENTRY, address.offset.plm4, address.offset.plm3, address.offset.plm2, address.offset.plm1 * 8); 377 | if (*entry == 0) 378 | { 379 | if(temp_page_num == 0) 380 | return beginning_address.address; 381 | temp_page_num--; 382 | } else { 383 | temp_page_num = page_num; 384 | beginning_address = address; 385 | } 386 | } 387 | address.offset.plm1 = 0; 388 | } 389 | address.offset.plm2 = 0; 390 | } 391 | address.offset.plm3 = 0; 392 | } 393 | LOG_ERR("There is no free space after the address {x}", base_addr); 394 | return 0; 395 | } 396 | 397 | #include 398 | 399 | /** 400 | * @brief Mandatory interface function to get the granularity flags 401 | * 402 | * @param flags the generic flags to convert 403 | * @return uintptr_t the converted flags, to be ored 404 | */ 405 | uintptr_t convert_to_arch_flags(uintptr_t flags) 406 | { 407 | uintptr_t to_return = 0; 408 | if (flags & MAP_PRESENT) 409 | to_return |= 1; 410 | if (flags & MAP_WRITE) 411 | to_return |= 2; 412 | if (flags & MAP_USER) 413 | to_return |= 4; 414 | if (flags & MAP_COPY_ON_WRITE) 415 | to_return |= (1ull << 9); 416 | if (flags & MAP_EXECUTE) 417 | to_return |= (1ull << 63); 418 | if (flags & MAP_SWAPPED) 419 | to_return |= (1ull << 10); 420 | return to_return; 421 | } -------------------------------------------------------------------------------- /src/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=0 2 | VERBOSE=yes 3 | GRAPHICS=yes 4 | 5 | THEME_BACKGROUND=50000000 6 | BACKGROUND_PATH=boot:///pEpitOS-logo-1.bmp 7 | BACKGROUND_STYLE=stretched 8 | BACKDROP_COLOUR=008080 9 | 10 | :pEpitOS 11 | PROTOCOL=stivale2 12 | KERNEL_PATH=boot:///pEpitOS.elf 13 | KASLR=no 14 | 15 | MODULE_PATH=boot:///build/tid0.so 16 | MODULE_STRING=pid0 17 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/alloc/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef ALLOC_H 2 | #define ALLOC_H 3 | 4 | #include "arch/arch.h" 5 | 6 | void* malloc(size_t size); 7 | void* calloc(size_t num, size_t size); 8 | void free(void* ptr); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/alloc/liballoc.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBALLOC_H 2 | #define _LIBALLOC_H 3 | 4 | #include 5 | 6 | /** This is a boundary tag which is prepended to the 7 | * page or section of a page which we have allocated. It is 8 | * used to identify valid memory blocks that the 9 | * application is trying to free. 10 | */ 11 | struct boundary_tag 12 | { 13 | unsigned int magic; //< It's a kind of ... 14 | unsigned int size; //< Requested size. 15 | unsigned int real_size; //< Actual size. 16 | int index; //< Location in the page table. 17 | 18 | struct boundary_tag *split_left; //< Linked-list info for broken pages. 19 | struct boundary_tag *split_right; //< The same. 20 | 21 | struct boundary_tag *next; //< Linked list info. 22 | struct boundary_tag *prev; //< Linked list info. 23 | }; 24 | 25 | /** This function is supposed to lock the memory data structures. It 26 | * could be as simple as disabling interrupts or acquiring a spinlock. 27 | * It's up to you to decide. 28 | * 29 | * \return 0 if the lock was acquired successfully. Anything else is 30 | * failure. 31 | */ 32 | extern int liballoc_lock(); 33 | 34 | /** This function unlocks what was previously locked by the liballoc_lock 35 | * function. If it disabled interrupts, it enables interrupts. If it 36 | * had acquiried a spinlock, it releases the spinlock. etc. 37 | * 38 | * \return 0 if the lock was successfully released. 39 | */ 40 | extern int liballoc_unlock(); 41 | 42 | /** This is the hook into the local system which allocates pages. It 43 | * accepts an integer parameter which is the number of pages 44 | * required. The page size was set up in the liballoc_init function. 45 | * 46 | * \return NULL if the pages were not allocated. 47 | * \return A pointer to the allocated memory. 48 | */ 49 | extern void* liballoc_alloc(int); 50 | 51 | /** This frees previously allocated memory. The void* parameter passed 52 | * to the function is the exact same value returned from a previous 53 | * liballoc_alloc call. 54 | * 55 | * The integer value is the number of pages to free. 56 | * 57 | * \return 0 if the memory was successfully freed. 58 | */ 59 | extern int liballoc_free(void*,int); 60 | 61 | 62 | 63 | void *malloc(size_t n); //< The standard function. 64 | void *realloc(void *p, size_t n); //< The standard function. 65 | void *calloc(size_t nmemb, size_t size); //< The standard function. 66 | void free(void *p); //< The standard function. 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/freestanding.h: -------------------------------------------------------------------------------- 1 | #ifndef kFREESTANDING_H 2 | #define kFREESTANDING_H 3 | 4 | // #pragma GCC diagnostic ignored "-Wint-conversion" 5 | // #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 6 | // #pragma GCC diagnostic ignored "-Wunused-function" 7 | // #pragma GCC diagnostic ignored "-Wunused-parameter" 8 | // #pragma GCC diagnostic ignored "-Wunused-variable" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "utils/utils.h" 20 | 21 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/init/initfs.h: -------------------------------------------------------------------------------- 1 | #ifndef INITFS_H 2 | #define INITFS_H 3 | 4 | #include 5 | #include 6 | 7 | #define MAX_FILES_IN_INITRD 32 8 | #define MAX_FILENAME_SIZE 128 9 | 10 | struct file 11 | { 12 | char name[128]; 13 | uintptr_t begin; 14 | uintptr_t end; 15 | }; 16 | 17 | void register_new_file(char* name, uintptr_t begin, uintptr_t end); 18 | struct file *get_files(); 19 | struct file *get_file(char *name); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/interface_struct/interface_struct.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERFACE_STRUCT_H 2 | #define INTERFACE_STRUCT_H 3 | 4 | #define MAX_CORES 32 5 | 6 | #include "freestanding.h" 7 | 8 | typedef void (*launching_address)(); 9 | typedef struct { 10 | unsigned char core_number; 11 | launching_address launching_addresses[MAX_CORES]; 12 | } interface_struct; 13 | 14 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/log/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include "freestanding.h" 5 | #include "arch/arch.h" 6 | #include "multicore/lock.h" 7 | #include "multicore/interrupt_lock.h" 8 | #include "multicore/common_locks.h" 9 | 10 | #define roprint(x) write_string(x) 11 | 12 | void sprintf(char *format, char *buff, va_list args); 13 | void printf(char *format, ...); 14 | 15 | #define COL_DEFAULT "\033[39m" 16 | #define COL_RED "\033[31m" 17 | #define COL_GREEN "\033[32m" 18 | #define COL_ORANGE "\033[33m" 19 | #define COL_BLUE "\033[34m" 20 | #define COL_MAGENTA "\033[35m" 21 | #define COL_CYAN "\033[36m" 22 | #define COL_GREY "\033[37m" 23 | 24 | #define OK_STRING COL_GREEN "[OK ] " COL_DEFAULT 25 | #define ERR_STRING COL_ORANGE "[WARN ] " COL_DEFAULT 26 | #define INFO_STRING COL_CYAN "[INFO ] " COL_DEFAULT 27 | #define PANIC_STRING COL_RED "[PANIC] " COL_DEFAULT 28 | 29 | #define LINE_STRING log(__FILE__); \ 30 | log(" : "); \ 31 | log(__func__); \ 32 | log(" l. "); \ 33 | log(__LINE__); \ 34 | log(" -> "); 35 | 36 | CREATE_PROTOS(print); 37 | 38 | #define LOG_OK(...) {lock_ints(); get_lock_print(); roprint(OK_STRING); if(is_multicore()) { printf( COL_CYAN "(core {d}) ", COREID);} printf(COL_BLUE "{s}:{d} f. {s} -> " COL_DEFAULT, __FILE__, __LINE__, __func__); printf(__VA_ARGS__); roprint("\n"); set_lock_print(); unlock_ints();} 39 | #define LOG_SECTION(...) {lock_ints(); get_lock_print(); roprint(OK_STRING); if(is_multicore()) { printf( COL_CYAN "(core {d}) ", COREID);} printf(COL_BLUE "{s}:{d} f. {s} -> " COL_DEFAULT, __FILE__, __LINE__, __func__); printf(__VA_ARGS__); roprint("\n"); set_lock_print(); unlock_ints();} 40 | #define LOG_ERR(...) {lock_ints(); get_lock_print(); roprint(ERR_STRING); if(is_multicore()) { printf( COL_CYAN "(core {d}) ", COREID);} printf(COL_BLUE "{s}:{d} f. {s} -> " COL_DEFAULT, __FILE__, __LINE__, __func__); printf(__VA_ARGS__); roprint("\n"); set_lock_print(); unlock_ints();} 41 | #define LOG_INFO(...) {lock_ints(); get_lock_print(); roprint(INFO_STRING); if(is_multicore()) { printf( COL_CYAN "(core {d}) ", COREID);} printf(COL_BLUE "{s}:{d} f. {s} -> " COL_DEFAULT, __FILE__, __LINE__, __func__); printf(__VA_ARGS__); roprint("\n"); set_lock_print(); unlock_ints();} 42 | #define LOG_PANIC(...) {lock_ints(); get_lock_print(); roprint(PANIC_STRING); if(is_multicore()) { printf( COL_CYAN "(core {d}) ", COREID);} printf(COL_BLUE "{s}:{d} f. {s} -> " COL_DEFAULT, __FILE__, __LINE__, __func__); printf(__VA_ARGS__); roprint("\n"); set_lock_print(); unlock_ints();} 43 | #define PANIC(...) {LOG_PANIC(__VA_ARGS__); while(1);} 44 | 45 | #define ASSERT(C, __TRUE, __FALSE, ...) {if(C){ LOG_OK(__TRUE, ##__VA_ARGS__); } else { LOG_PANIC(__FALSE, ##__VA_ARGS__); disable_ints(); halt();}} 46 | #define CHECK(C, __TRUE, __FALSE, ...) {if(C){ LOG_OK(__TRUE, ##__VA_ARGS__); } else { LOG_ERR(__FALSE, ##__VA_ARGS__);}} 47 | 48 | #define qASSERT(C) {if(C){ LOG_OK(#C); } else { LOG_PANIC(#C); disable_ints(); halt();}} 49 | #define qCHECK(C) {if(C){ LOG_OK(#C); } else { LOG_ERR(#C);}} 50 | 51 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/memory/vmmwrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef VMM_WRAPPER_H 2 | #define VMM_WRAPPER_H 3 | 4 | #include 5 | #include 6 | 7 | enum map_flags { 8 | 9 | MAP_PRESENT = 1, 10 | MAP_WRITE = 2, 11 | MAP_USER = 4, 12 | MAP_COPY_ON_WRITE = 8, 13 | MAP_EXECUTE = 16, 14 | MAP_SWAPPED = 32, 15 | }; 16 | 17 | uintptr_t space_alloc(size_t size, uintptr_t flags); 18 | void space_free(uintptr_t addr, size_t size); 19 | 20 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/multicore/common_locks.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_LOCKS_H 2 | #define COMMON_LOCKS_H 3 | 4 | #include "lock.h" 5 | 6 | CREATE_PROTOS(print) 7 | 8 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/multicore/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTICORE_CPU_H 2 | #define MULTICORE_CPU_H 3 | 4 | #include 5 | #include 6 | 7 | typedef uint16_t pid_t; 8 | 9 | struct task { 10 | pid_t pid; 11 | pid_t tid; 12 | int32_t priority; 13 | char state; 14 | context_save regs; 15 | }; 16 | 17 | struct cpu { 18 | char is_present; 19 | char is_bsp; 20 | char id; 21 | 22 | struct task *current_task; 23 | struct task *next_task; 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/multicore/interrupt_lock.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTICORE_INTS_LOCKS_H 2 | #define MULTICORE_INTS_LOCKS_H 3 | 4 | void unlock_ints(); 5 | void lock_ints(); 6 | void set_ints(uint8_t int_level); 7 | 8 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/multicore/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCK_H 2 | #define LOCK_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | atomic_char16_t lock; 8 | } lock; 9 | 10 | #define WAIT_LOCK(x) while(!__sync_bool_compare_and_swap(&(x.lock), 0, 1)); __sync_synchronize(); 11 | #define GRAB_LOCK_f(x) 12 | #define GRAB_LOCK(x) WAIT_LOCK(x); GRAB_LOCK_f(x) 13 | #define RELEASE_LOCK_f(x) __sync_synchronize(); ((x).lock--) 14 | #define RELEASE_LOCK(x) RELEASE_LOCK_f(x) 15 | 16 | #define BEGIN_BOTTLENECK(name) GRAB_LOCK(_lock_##name); 17 | #define END_BOTTLENECK(name) RELEASE_LOCK(_lock_##name); 18 | 19 | #define CREATE_LOCK(name) static lock _lock_##name; 20 | #define LOCK_NAME(x) _lock_##x 21 | 22 | #define CREATE_GET(name) void get_lock_##name () { GRAB_LOCK(_lock_ ##name); } 23 | #define CREATE_SET_SYNC(name) void set_lock_##name () { RELEASE_LOCK(_lock_ ##name); } 24 | #define CREATE_COMMON(name) CREATE_LOCK(name) CREATE_GET(name) CREATE_SET_SYNC(name) 25 | #define CREATE_GET_PROTO(name) void get_lock_##name (); 26 | #define CREATE_SET_PROTO(name) void set_lock_##name (); 27 | #define CREATE_PROTOS(name) CREATE_GET_PROTO(name) CREATE_SET_PROTO(name) 28 | 29 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/scheduler/scheduler.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaemonOnUnix/pEpitOS-x86_64/8a0bd155e7ea7c8b3d6ebebacd5b567353716208/src/pEpitOS-kernel/include/scheduler/scheduler.h -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/syscall/syscall.h: -------------------------------------------------------------------------------- 1 | #include "arch/archtypes.h" 2 | #include "syscall-enabling/syscall.h" 3 | 4 | register_t syscall_handler(struct syscall_pack *pack); -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/tasking/tasking.h: -------------------------------------------------------------------------------- 1 | #ifndef TASKING_H 2 | #define TASKING_H 3 | 4 | #include "arch/arch.h" 5 | 6 | typedef struct { 7 | mapping_t page_directory; 8 | } task; 9 | 10 | void switch_task_stackframe(volatile stackframe* regs, volatile stackframe* to_inject); 11 | void switch_task_mapped(); 12 | void switch_task_from_interrupt(volatile stackframe* regs); 13 | void enable_preemption(); 14 | void disable_preemption(); 15 | task create_task(); 16 | void register_this_context(); 17 | void modify_target_task(core_id_t core_id, task* target_task); 18 | 19 | void enable_tasking(); 20 | 21 | /** 22 | * @brief Create a task from func object 23 | * 24 | * @param func_ptr PC to load 25 | * @param stack_size Size of stack 26 | * @param stack_virtual_addr Virtual address of stack 27 | * @param is_userspace Determines if stack should be userspace 28 | * @param cs Code segment if available in arch 29 | * @param ss Stack segment if available in arch 30 | * @param rflags RFLAGS if available in arch 31 | * @return task The created task 32 | */ 33 | task create_task_from_func(uintptr_t func_ptr, 34 | uintptr_t stack_size, uintptr_t stack_virtual_addr, bool is_userspace, 35 | uint16_t cs, uint16_t ss, uint64_t rflags); 36 | 37 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/tests/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTS_H 2 | #define TESTS_H 3 | 4 | void launch_tests(); 5 | 6 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/utils/functions.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_FUNCTIONS_H 2 | #define HELPERS_FUNCTIONS_H 3 | 4 | char* dec(unsigned long long x, char *s); 5 | char* decX(unsigned long long x, char *s); 6 | 7 | void* memset(volatile void* b, int c, size_t len); 8 | void* memcpy(volatile void* dest, volatile const void* src, size_t n); 9 | 10 | bool strcmp(volatile char* str1, volatile char* str2); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/utils/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_MACROS_H 2 | #define HELPERS_MACROS_H 3 | 4 | #define PACKED __attribute__((packed)) 5 | #define ONCE(...) {static char once = 0; if(once) return __VA_ARGS__; once = 1;} 6 | #define UNUSED_VAR(...) (void)(__VA_ARGS__) 7 | 8 | // 9 | // volatile RW section 10 | // 11 | #define write_mem64(addr, value) ((*((uint64_t*)(addr))) = (value)) 12 | #define read_mem64(addr) (*(volatile uint64_t*)(addr)) 13 | 14 | // 15 | // Bitmanip section 16 | // 17 | #define MASK(n) ((1ull << (n)) -1) 18 | #define MASK_SHIFT(n, shift) (MASK(n) << (shift)) 19 | #define SHIFTR(x, n, shift) (((x) >> (shift)) & MASK(n)) 20 | #define SHIFTL(x, n, shift) (((x) & MASK(n)) << (shift)) 21 | 22 | 23 | // 24 | // Maybe section 25 | // 26 | #define sizeof_maybe(T) (sizeof(struct PACKED { char some; T val; })) 27 | #define Maybe(T) volatile char* 28 | #define Some(T, V) ({\ 29 | static volatile char v[sizeof_maybe(T)];\ 30 | *(volatile T*)(v + 1) = V;\ 31 | v[0] = 1;\ 32 | v;\ 33 | }) 34 | #define None(T) ({\ 35 | static volatile char v[sizeof_maybe(T)];\ 36 | v[0] = 0;\ 37 | v;\ 38 | }) 39 | #define MAYBE_IF(COND, T, V) if(COND) {return Some(T, V);} return None(T); 40 | #define GET_STATUS(V) ((V)[0]) 41 | #define GET_VALUE(T, V) (*((T*)((V + 1)))) 42 | #define UNWRAP(T, V) ({Maybe(T) ___val = V; if(!GET_STATUS(___val)) PANIC("Unwrap failed."); GET_VALUE(T, ___val);}) 43 | 44 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/include/utils/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_H 2 | #define HELPERS_H 3 | 4 | #include "macros.h" 5 | #include "functions.h" 6 | 7 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/alloc.c: -------------------------------------------------------------------------------- 1 | #include "alloc/alloc.h" 2 | #include "arch/arch.h" 3 | #include "vmm/vmm.h" 4 | #include "log/log.h" 5 | 6 | #if 0 7 | 8 | #define new_page_in_higherhalf() physical_to_stivale(new_physical_page()) 9 | 10 | typedef struct malloc_header{ 11 | size_t size; 12 | struct malloc_header* prev; 13 | struct malloc_header* next; 14 | uint8_t data[]; 15 | } malloc_header; 16 | 17 | #define MALLOC_HEADER(_addr, _size, _prev, _next) ({\ 18 | malloc_header* r = (malloc_header*)_addr;\ 19 | r->size = (size_t)_size;\ 20 | r->prev = (void*)_prev;\ 21 | r->next = (void*)_next;\ 22 | r;}) 23 | #if 0 24 | void* malloc(size_t size){ 25 | static malloc_header* previous_header = 0; 26 | static size_t remaining_size_on_page = ARCH_PAGE_SIZE; 27 | 28 | if(!previous_header){ 29 | previous_header = MALLOC_HEADER(new_page_in_higherhalf(), size, 0, 0); 30 | } else{ 31 | if(remaining_size_on_page < sizeof(malloc_header) + size){ 32 | uintptr_t current_header = (uintptr_t)previous_header; 33 | size_t accumulated_size = remaining_size_on_page; 34 | size_t current_goal = size; 35 | while(accumulated_size < sizeof(malloc_header) + size){ 36 | uintptr_t next = new_page_in_higherhalf(); 37 | if(next > current_header && next - current_header <= ARCH_PAGE_SIZE){ 38 | accumulated_size += ARCH_PAGE_SIZE; 39 | 40 | } else{ 41 | 42 | } 43 | } 44 | } 45 | ASSERT(remaining_size_on_page >= sizeof(malloc_header) + size, "Remaining size : {d}", "Remaining size : {d}", remaining_size_on_page); 46 | previous_header = MALLOC_HEADER(previous_header->next, size, previous_header, 0); 47 | } 48 | 49 | remaining_size_on_page -= (sizeof(malloc_header) + size); 50 | malloc_header* prev = previous_header; 51 | previous_header = (malloc_header*)(previous_header->data + previous_header->size); 52 | previous_header->prev = prev; 53 | 54 | return previous_header->data; 55 | } 56 | #endif 57 | 58 | #ifndef X86_64 59 | #error You should adapt the bits flags for the other architectures at the moment. 60 | #else 61 | 62 | #include "vmm/vmm.h" 63 | 64 | void* malloc(size_t size){ 65 | static uintptr_t program_break = GET_FIRST_VALID_ADDRESS(); 66 | static bool is_initialized = 0; 67 | static malloc_header* last_header = (void*)0; 68 | 69 | if(!is_initialized){ 70 | kmmap(program_break, size + sizeof(malloc_header), 1); 71 | 72 | } 73 | 74 | 75 | 76 | } 77 | #endif 78 | 79 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/common_locks.c: -------------------------------------------------------------------------------- 1 | #include "multicore/lock.h" 2 | 3 | CREATE_COMMON(print) -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/initfs.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | #include "init/initfs.h" 3 | #include "log/log.h" 4 | 5 | static struct file initrd_files[MAX_FILES_IN_INITRD]; 6 | static size_t file_count = 0; 7 | 8 | //my_strncpy 9 | static void my_strncpy(volatile char *dest, volatile const char *src, size_t n) 10 | { 11 | size_t i; 12 | for (i = 0; i < n-1 && src[i]; i++) 13 | dest[i] = src[i]; 14 | dest[i] = 0; 15 | } 16 | 17 | void register_new_file(char* name, uintptr_t begin, uintptr_t end) 18 | { 19 | if (file_count >= MAX_FILES_IN_INITRD) 20 | PANIC("Too many files in initrd"); 21 | 22 | initrd_files[file_count].begin = begin; 23 | initrd_files[file_count].end = end; 24 | my_strncpy(initrd_files[file_count].name, name, MAX_FILENAME_SIZE); 25 | 26 | } 27 | 28 | static char my_strcmp(char* a, char* b) 29 | { 30 | while (*a && *b) 31 | if (*a++ != *b++) 32 | return 0; 33 | return *a == *b; 34 | } 35 | struct file *get_files() 36 | { 37 | return initrd_files; 38 | } 39 | struct file *get_file(char *name) 40 | { 41 | for (size_t i = 0; i < file_count; i++) 42 | { 43 | if (!my_strcmp(initrd_files[i].name, name)) 44 | return initrd_files + i; 45 | } 46 | return NULL; 47 | } 48 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/interrupt_lock.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | #include "log/log.h" 3 | 4 | #ifndef DEBUG_INTERRUPT_LOCK 5 | #undef LOG_INFO 6 | #define LOG_INFO(...) 7 | #undef LOG_OK 8 | #define LOG_OK(...) 9 | #endif 10 | 11 | static uint8_t lock_level[ARCH_MAX_CORE_NUM] = {0}; 12 | 13 | void unlock_ints(){ 14 | ASSERT(lock_level[COREID], "Unlocking ints", "lock_level already at 0"); 15 | if(!(--(lock_level[COREID]))) { 16 | enable_ints(); 17 | LOG_INFO("Interrupts enabled."); 18 | } 19 | LOG_INFO("Lock level at {d}", lock_level[COREID]); 20 | } 21 | 22 | void lock_ints(){ 23 | ASSERT(lock_level[COREID] != 255, "Locking ints", "Lock_levels at 255"); 24 | lock_level[COREID]++; 25 | if(lock_level[COREID] == 1){ 26 | disable_ints(); 27 | LOG_INFO("Interrupts disabled."); 28 | } 29 | LOG_INFO("Lock level at {d}", lock_level[COREID]); 30 | } 31 | 32 | void set_ints(uint8_t int_level){ 33 | LOG_INFO("Setting ints to level {d}.", int_level); 34 | lock_level[COREID] = int_level; 35 | if(!lock_level[COREID]){ 36 | enable_ints(); 37 | LOG_INFO("Inerrupts enabled through set_ints."); 38 | } else { 39 | disable_ints(); 40 | LOG_INFO("Interrupts disabled through set_ints."); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/main.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | #include "interface_struct/interface_struct.h" 3 | #include "log/log.h" 4 | #include "tests/tests.h" 5 | #include "vmm/vmm.h" 6 | 7 | #include "multicore/interrupt_lock.h" 8 | 9 | #include "init/initfs.h" 10 | #include "tasking/tasking.h" 11 | 12 | #include "vmm/vmm.h" 13 | 14 | 15 | void hello() 16 | { 17 | LOG_OK("Hello"); 18 | } 19 | 20 | void launch_hell() 21 | { 22 | lock_ints(); 23 | LOG_OK("Launching hell"); 24 | //enable_mapping(create_page_directory()); 25 | //setup_context_frame(); 26 | //map_pics(); 27 | struct file first = *get_files(); 28 | //LOG_PANIC("PLOUF"); 29 | kmmap(0, first.end - first.begin, 7); 30 | memcpy(0, (void*)first.begin, first.end - first.begin); 31 | //LOG_OK("plouf"); 32 | kmmap(0x10000, 0x2000, 7); 33 | asm volatile("movq rsp, %0" : : "r"(0x11000ll)); 34 | asm volatile ("mov rcx, 0x1000"); 35 | asm volatile ("mov r11, 0x002"); 36 | asm volatile ("sysretq"); 37 | } 38 | 39 | void kernel_main(void* generic_structure) { 40 | 41 | interface_struct *interface = bootstrap_arch(generic_structure); 42 | 43 | lock_ints(); 44 | 45 | // unlock_ints(); 46 | # ifdef X86_64 47 | LOG_OK("x86_64 bootstrap finished !"); 48 | # endif 49 | 50 | // launch_tests(); 51 | interface->launching_addresses[1] = launch_hell; 52 | // for(volatile size_t i = 0; i < 100000000; i++); 53 | // interface->launching_addresses[1] = hello; 54 | interface->launching_addresses[2] = launch_hell; 55 | interface->launching_addresses[3] = launch_hell; 56 | interface->launching_addresses[4] = launch_hell; 57 | 58 | LOG_OK("All work finished."); 59 | 60 | LOG_INFO("Loading first elf"); 61 | struct file first = *get_files(); 62 | // PANIC("{s}", first.name); 63 | 64 | // enable_tasking(); 65 | // task plouf = create_task_from_func(0x1000, 0x1000, 0x50000, true, 0x20, 0x28, (1<<12)); 66 | // //enable_mapping(plouf.page_directory); 67 | kmmap(0, first.end - first.begin, 7); 68 | memcpy(0, (void*)first.begin, first.end - first.begin); 69 | LOG_OK("plouf"); 70 | kmmap(0x10000, 0x2000, 7); 71 | asm volatile("movq rsp, %0" : : "r"(0x11000ll)); 72 | asm volatile ("mov rcx, 0x1000"); 73 | asm volatile ("mov r11, 0x002"); 74 | asm volatile ("sysretq"); 75 | 76 | // unlock_ints(); 77 | 78 | halt(); 79 | } 80 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/scheduler.c: -------------------------------------------------------------------------------- 1 | #include "scheduler/scheduler.h" 2 | #include "arch/arch.h" 3 | #include "tasking/tasking.h" 4 | 5 | 6 | void schedule_next(volatile stackframe* to_inject) { 7 | UNUSED_VAR(to_inject); 8 | } 9 | 10 | void init_scheduler(){ 11 | register_custom_int(31, &schedule_next); 12 | } 13 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/syscall_handler.c: -------------------------------------------------------------------------------- 1 | #include "syscall/syscall.h" 2 | 3 | #include "vmm/vmm.h" 4 | #include "memory/vmmwrapper.h" 5 | #include "log/log.h" 6 | 7 | 8 | 9 | register_t syscall_handler(struct syscall_pack *pack) 10 | { 11 | LOG_INFO("syscall_id: {x}\nfirst parameter: {x}\nsecond parameter: {x}\nthird parameter: {x}\n", pack->syscall_id, pack->arg1, pack->arg2, pack->arg3); 12 | switch (pack->syscall_id) { 13 | case 1: 14 | { 15 | LOG_INFO("mmap syscall called"); 16 | kmmap(pack->arg1, pack->arg2, convert_to_arch_flags(pack->arg3) | MAP_PRESENT); 17 | return pack->arg1; 18 | } 19 | } 20 | return 0x8442; 21 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/tasking.c: -------------------------------------------------------------------------------- 1 | #if 0 2 | #include "tasking/tasking.h" 3 | #include "log/log.h" 4 | #include "interrupts/defined_interrupts.h" 5 | #include "intel/asm.h" 6 | #include "vmm/vmm.h" 7 | #include "tables/idt.h" 8 | #include "SMP/SMP.h" 9 | #endif 10 | 11 | #include "tasking/tasking.h" 12 | #include "arch/arch.h" 13 | #include "log/log.h" 14 | #include "vmm/vmm.h" 15 | #include "multicore/interrupt_lock.h" 16 | #define ACTIVE_MAPPING(...) enable_mapping(__VA_ARGS__) 17 | 18 | task* target_tasks[32] = {0}; 19 | 20 | void enable_tasking(){ 21 | register_custom_int(arch_SWITCH_TASK_INT, switch_task_from_interrupt); 22 | } 23 | 24 | void switch_task_stackframe(volatile stackframe* regs, volatile stackframe* to_inject){ 25 | LOG_INFO("Injecting registers..."); 26 | LOG_INFO("IP before : {x}, after : {x}", regs->rip, to_inject->rip); 27 | log_stackframe(regs); 28 | *regs = *to_inject; 29 | log_stackframe(regs); 30 | } 31 | 32 | context_save* get_context(){ 33 | return (context_save*)CONTEXT_FRAME_ADDR; 34 | } 35 | 36 | void switch_task_mapped(task* to_enable){ 37 | LOG_INFO("Enabling task at {x}", (uintptr_t)to_enable); 38 | context_save* save_frame = get_context(); 39 | 40 | UNUSED_VAR(save_frame); 41 | 42 | // TODO : should save current context 43 | enable_mapping(to_enable->page_directory); 44 | // TRIGGER_INTERRUPT(SWITCH_TASK_INTERRUPT); 45 | trigger_int(arch_SWITCH_TASK_INT); 46 | } 47 | 48 | void switch_regs_from_interrupt(volatile stackframe* regs){ 49 | context_save* save_frame = get_context(); 50 | // save_frame->stack_save = *regs; 51 | LOG_INFO("Switching task... context frame at {x}", save_frame); 52 | switch_task_stackframe(regs, &(save_frame->stack_save)); 53 | } 54 | 55 | void switch_task_from_interrupt(volatile stackframe* regs){ 56 | task* to_enable = target_tasks[COREID]; 57 | ASSERT(to_enable, "Switching task from interrupt...", 58 | "Invalid NULL task targeted..."); 59 | context_save* save_frame = get_context(); 60 | save_frame->stack_save = *regs; 61 | enable_mapping(to_enable->page_directory); 62 | switch_regs_from_interrupt(regs); 63 | } 64 | 65 | void enable_preemption(){ 66 | LOG_INFO("Enabling preemption"); 67 | asm volatile("sti"); 68 | } 69 | 70 | void disable_preemption(){ 71 | LOG_INFO("Disabling preemption"); 72 | disable_ints(); 73 | } 74 | 75 | task create_task(){ 76 | disable_preemption(); 77 | mapping_t current_page_directory = get_current_mapping(); 78 | task to_return = (task){ 79 | .page_directory = create_page_directory() 80 | }; 81 | enable_mapping(to_return.page_directory); 82 | initialize_mapping(); 83 | LOG_INFO("Mapping initialized."); 84 | setup_context_frame(); 85 | enable_mapping(current_page_directory); 86 | enable_preemption(); 87 | LOG_OK("Task created successfully"); 88 | return to_return; 89 | } 90 | 91 | void register_this_context(){ 92 | LOG_INFO("Registering context...") 93 | switch_task_mapped(target_tasks[COREID]); 94 | LOG_OK("Context registered."); 95 | } 96 | 97 | void modify_target_task(uint8_t core_id, task* target_task){ 98 | target_tasks[core_id] = target_task; 99 | } 100 | 101 | task create_task_from_func(uintptr_t func_ptr, 102 | uintptr_t stack_size, uintptr_t stack_virtual_addr, bool is_userspace, 103 | uint16_t cs, uint16_t ss, uint64_t rflags){ 104 | lock_ints(); 105 | // disable_preemption(); 106 | mapping_t current_page_directory = get_current_mapping(); 107 | task to_return = (task){ 108 | .page_directory = create_page_directory() 109 | }; 110 | enable_mapping(to_return.page_directory); 111 | initialize_mapping(); 112 | LOG_INFO("Mapping initialized."); 113 | setup_context_frame(); 114 | kmmap(stack_virtual_addr & CLEAN_BITS_MASK, (stack_size & CLEAN_BITS_MASK) + ARCH_PAGE_SIZE, 3 & (is_userspace ? 4 : 0)); 115 | LOG_INFO("Creating task with func_ptr = {x}", func_ptr); 116 | get_context()->stack_save.ip = func_ptr; 117 | // get_context()->stack_save.useresp = 0xdeadb000 + 64 * 4;//(stack_virtual_addr + stack_size) & CLEAN_BITS_MASK ; 118 | get_context()->stack_save.ret_sp = stack_virtual_addr + stack_size;//(stack_virtual_addr + stack_size) & CLEAN_BITS_MASK ; 119 | # ifdef X86_64 120 | get_context()->stack_save.rflags = rflags; 121 | get_context()->stack_save.cs = cs; 122 | get_context()->stack_save.ss = ss; 123 | # endif 124 | //get_context()->stack_save.rsp = stack_virtual_addr + stack_size & CLEAN_BITS_MASK + ARCH_PAGE_SIZE - 8; 125 | // asm volatile("mov cr3, %0" :: "a"(current_page_directory)); 126 | enable_mapping(current_page_directory); 127 | // enable_preemption(); 128 | unlock_ints(); 129 | LOG_OK("Task created successfully"); 130 | return to_return; 131 | } 132 | 133 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/tests.c: -------------------------------------------------------------------------------- 1 | #ifdef PTESTS 2 | 3 | #define TEST_LAUNCH(id) {\ 4 | LOG_ERR("------------ Launching " #id " tests ------------");\ 5 | launch_## id ##_tests();\ 6 | LOG_ERR("------------ " #id " tests finished ------------");\ 7 | } 8 | 9 | #include "multicore/lock.h" 10 | #include "log/log.h" 11 | #include "alloc/alloc.h" 12 | 13 | void launch_lock_tests(){ 14 | } 15 | 16 | void launch_malloc_tests(){ 17 | int* p = malloc(sizeof(int)); 18 | LOG_INFO("Pointer address: {x}", (uintptr_t)p); 19 | qASSERT(p != 0); 20 | *p = 6; 21 | qASSERT(*p == 6); 22 | LOG_INFO("Pointer at {x}", p); 23 | } 24 | 25 | void launch_free_tests(){ 26 | LOG_INFO("Freeing pointer at {x}", 0x1030); 27 | free((void*)0x1030); 28 | } 29 | 30 | void launch_tests(){ 31 | TEST_LAUNCH(malloc); 32 | TEST_LAUNCH(free); 33 | TEST_LAUNCH(malloc); 34 | TEST_LAUNCH(free); 35 | } 36 | 37 | #else 38 | 39 | void launch_tests(){} 40 | 41 | #endif -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/alloc/liballoc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" 4 | #pragma GCC diagnostic ignored "-Wsign-compare" 5 | #pragma GCC diagnostic ignored "-Waddress" 6 | #pragma GCC diagnostic ignored "-Wint-conversion" 7 | #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" 8 | 9 | /** Durand's Ridiculously Amazing Super Duper Memory functions. */ 10 | 11 | #define DEBUG 12 | #undef DEBUG 13 | 14 | #define LIBALLOC_MAGIC 0xc001c0de 15 | #define MAXCOMPLETE 5 16 | #define MAXEXP 32 17 | #define MINEXP 8 18 | 19 | #define MODE_BEST 0 20 | #define MODE_INSTANT 1 21 | 22 | #define MODE MODE_BEST 23 | 24 | #ifdef DEBUG 25 | #include "log/log.h" 26 | #endif 27 | 28 | #define fflush(...) 29 | 30 | struct boundary_tag* l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks 31 | int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks 32 | 33 | 34 | #ifdef DEBUG 35 | unsigned int l_allocated = 0; //< The real amount of memory allocated. 36 | unsigned int l_inuse = 0; //< The amount of memory in use (malloc'ed). 37 | #endif 38 | 39 | 40 | static int l_initialized = 0; //< Flag to indicate initialization. 41 | static int l_pageSize = 4096; //< Individual page size 42 | static int l_pageCount = 16; //< Minimum number of pages to allocate. 43 | 44 | 45 | // *********** HELPER FUNCTIONS ******************************* 46 | 47 | /** Returns the exponent required to manage 'size' amount of memory. 48 | * 49 | * Returns n where 2^n <= size < 2^(n+1) 50 | */ 51 | static inline int getexp( unsigned int size ) 52 | { 53 | if ( size < (1< size ) break; 67 | shift += 1; 68 | } 69 | 70 | #ifdef DEBUG 71 | LOG_INFO("getexp returns {i} ({i} bytes) for {i} size\n", shift - 1, (1<<(shift -1)), size ); 72 | #endif 73 | 74 | return shift - 1; 75 | } 76 | 77 | 78 | static void* liballoc_memset(void* s, int c, size_t n) 79 | { 80 | int i; 81 | for ( i = 0; i < n ; i++) 82 | ((char*)s)[i] = c; 83 | 84 | return s; 85 | } 86 | 87 | static void* liballoc_memcpy(void* s1, const void* s2, size_t n) 88 | { 89 | char *cdest; 90 | char *csrc; 91 | unsigned int *ldest = (unsigned int*)s1; 92 | unsigned int *lsrc = (unsigned int*)s2; 93 | 94 | while ( n >= sizeof(unsigned int) ) 95 | { 96 | *ldest++ = *lsrc++; 97 | n -= sizeof(unsigned int); 98 | } 99 | 100 | cdest = (char*)ldest; 101 | csrc = (char*)lsrc; 102 | 103 | while ( n > 0 ) 104 | { 105 | *cdest++ = *csrc++; 106 | n -= 1; 107 | } 108 | 109 | return s1; 110 | } 111 | 112 | 113 | 114 | #ifdef DEBUG 115 | static void dump_array() 116 | { 117 | int i = 0; 118 | struct boundary_tag *tag = NULL; 119 | 120 | LOG_INFO("------ Free pages array ---------\n"); 121 | LOG_INFO("System memory allocated: {i}\n", l_allocated ); 122 | LOG_INFO("Memory in used (malloc'ed): {i}\n", l_inuse ); 123 | 124 | for ( i = 0; i < MAXEXP; i++ ) 125 | { 126 | LOG_INFO("%.2i({i}): ",i, l_completePages[i] ); 127 | 128 | tag = l_freePages[ i ]; 129 | while ( tag != NULL ) 130 | { 131 | if ( tag->split_left != NULL ) LOG_INFO("*"); 132 | LOG_INFO("{i}", tag->real_size ); 133 | if ( tag->split_right != NULL ) LOG_INFO("*"); 134 | 135 | LOG_INFO(" "); 136 | tag = tag->next; 137 | } 138 | LOG_INFO("\n"); 139 | } 140 | 141 | LOG_INFO("'*' denotes a split to the left/right of a tag\n"); 142 | fflush( stdout ); 143 | } 144 | #endif 145 | 146 | 147 | 148 | static inline void insert_tag( struct boundary_tag *tag, int index ) 149 | { 150 | int realIndex; 151 | 152 | if ( index < 0 ) 153 | { 154 | realIndex = getexp( tag->real_size - sizeof(struct boundary_tag) ); 155 | if ( realIndex < MINEXP ) realIndex = MINEXP; 156 | } 157 | else 158 | realIndex = index; 159 | 160 | tag->index = realIndex; 161 | 162 | if ( l_freePages[ realIndex ] != NULL ) 163 | { 164 | l_freePages[ realIndex ]->prev = tag; 165 | tag->next = l_freePages[ realIndex ]; 166 | } 167 | 168 | l_freePages[ realIndex ] = tag; 169 | } 170 | 171 | static inline void remove_tag( struct boundary_tag *tag ) 172 | { 173 | if ( l_freePages[ tag->index ] == tag ) l_freePages[ tag->index ] = tag->next; 174 | 175 | if ( tag->prev != NULL ) tag->prev->next = tag->next; 176 | if ( tag->next != NULL ) tag->next->prev = tag->prev; 177 | 178 | tag->next = NULL; 179 | tag->prev = NULL; 180 | tag->index = -1; 181 | } 182 | 183 | 184 | static inline struct boundary_tag* melt_left( struct boundary_tag *tag ) 185 | { 186 | struct boundary_tag *left = tag->split_left; 187 | 188 | left->real_size += tag->real_size; 189 | left->split_right = tag->split_right; 190 | 191 | if ( tag->split_right != NULL ) tag->split_right->split_left = left; 192 | 193 | return left; 194 | } 195 | 196 | 197 | static inline struct boundary_tag* absorb_right( struct boundary_tag *tag ) 198 | { 199 | struct boundary_tag *right = tag->split_right; 200 | 201 | remove_tag( right ); // Remove right from free pages. 202 | 203 | tag->real_size += right->real_size; 204 | 205 | tag->split_right = right->split_right; 206 | if ( right->split_right != NULL ) 207 | right->split_right->split_left = tag; 208 | 209 | return tag; 210 | } 211 | 212 | static inline struct boundary_tag* split_tag( struct boundary_tag* tag ) 213 | { 214 | unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size; 215 | 216 | struct boundary_tag *new_tag = 217 | (struct boundary_tag*)((unsigned int)tag + sizeof(struct boundary_tag) + tag->size); 218 | 219 | new_tag->magic = LIBALLOC_MAGIC; 220 | new_tag->real_size = remainder; 221 | 222 | new_tag->next = NULL; 223 | new_tag->prev = NULL; 224 | 225 | new_tag->split_left = tag; 226 | new_tag->split_right = tag->split_right; 227 | 228 | if (new_tag->split_right != NULL) new_tag->split_right->split_left = new_tag; 229 | tag->split_right = new_tag; 230 | 231 | tag->real_size -= new_tag->real_size; 232 | 233 | insert_tag( new_tag, -1 ); 234 | 235 | return new_tag; 236 | } 237 | 238 | 239 | // *************************************************************** 240 | 241 | 242 | 243 | 244 | static struct boundary_tag* allocate_new_tag( unsigned int size ) 245 | { 246 | unsigned int pages; 247 | unsigned int usage; 248 | struct boundary_tag *tag; 249 | 250 | // This is how much space is required. 251 | usage = size + sizeof(struct boundary_tag); 252 | 253 | // Perfect amount of space 254 | pages = usage / l_pageSize; 255 | if ( (usage % l_pageSize) != 0 ) pages += 1; 256 | 257 | // Make sure it's >= the minimum size. 258 | if ( pages < l_pageCount ) pages = l_pageCount; 259 | 260 | tag = (struct boundary_tag*)liballoc_alloc( pages ); 261 | 262 | if ( tag == NULL ) return NULL; // uh oh, we ran out of memory. 263 | 264 | tag->magic = LIBALLOC_MAGIC; 265 | tag->size = size; 266 | tag->real_size = pages * l_pageSize; 267 | tag->index = -1; 268 | 269 | tag->next = NULL; 270 | tag->prev = NULL; 271 | tag->split_left = NULL; 272 | tag->split_right = NULL; 273 | 274 | 275 | #ifdef DEBUG 276 | LOG_INFO("Resource allocated %x of {i} pages ({i} bytes) for {i} size.\n", tag, pages, pages * l_pageSize, size ); 277 | 278 | l_allocated += pages * l_pageSize; 279 | 280 | LOG_INFO("Total memory usage = {i} KB\n", (int)((l_allocated / (1024))) ); 281 | #endif 282 | 283 | return tag; 284 | } 285 | 286 | 287 | 288 | void *malloc(size_t size) 289 | { 290 | int index; 291 | void *ptr; 292 | struct boundary_tag *tag = NULL; 293 | 294 | liballoc_lock(); 295 | 296 | if ( l_initialized == 0 ) 297 | { 298 | #ifdef DEBUG 299 | LOG_INFO("%s\n","liballoc initializing."); 300 | #endif 301 | for ( index = 0; index < MAXEXP; index++ ) 302 | { 303 | l_freePages[index] = NULL; 304 | l_completePages[index] = 0; 305 | } 306 | l_initialized = 1; 307 | } 308 | 309 | index = getexp( size ) + MODE; 310 | if ( index < MINEXP ) index = MINEXP; 311 | 312 | 313 | // Find one big enough. 314 | tag = l_freePages[ index ]; // Start at the front of the list. 315 | while ( tag != NULL ) 316 | { 317 | // If there's enough space in this tag. 318 | if ( (tag->real_size - sizeof(struct boundary_tag)) 319 | >= (size + sizeof(struct boundary_tag) ) ) 320 | { 321 | #ifdef DEBUG 322 | LOG_INFO("Tag search found {i} >= {i}\n",(tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag) ) ); 323 | #endif 324 | break; 325 | } 326 | 327 | tag = tag->next; 328 | } 329 | 330 | 331 | // No page found. Make one. 332 | if ( tag == NULL ) 333 | { 334 | if ( (tag = allocate_new_tag( size )) == NULL ) 335 | { 336 | liballoc_unlock(); 337 | return NULL; 338 | } 339 | 340 | index = getexp( tag->real_size - sizeof(struct boundary_tag) ); 341 | } 342 | else 343 | { 344 | remove_tag( tag ); 345 | 346 | if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) 347 | l_completePages[ index ] -= 1; 348 | } 349 | 350 | // We have a free page. Remove it from the free pages list. 351 | 352 | tag->size = size; 353 | 354 | // Removed... see if we can re-use the excess space. 355 | 356 | #ifdef DEBUG 357 | LOG_INFO("Found tag with {i} bytes available (requested {i} bytes, leaving {i}), which has exponent: {i} ({i} bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1<real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder 361 | 362 | if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<= 0 ) 367 | { 368 | #ifdef DEBUG 369 | LOG_INFO("Seems to be splittable: {i} >= 2^{i} .. {i}\n", remainder, childIndex, (1<real_size, new_tag->real_size, new_tag->index ); 378 | #endif 379 | } 380 | } 381 | 382 | 383 | 384 | ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) ); 385 | 386 | 387 | 388 | #ifdef DEBUG 389 | l_inuse += size; 390 | LOG_INFO("malloc: %x, {i}, {i}\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 ); 391 | dump_array(); 392 | #endif 393 | 394 | 395 | liballoc_unlock(); 396 | return ptr; 397 | } 398 | 399 | 400 | 401 | 402 | 403 | void free(void *ptr) 404 | { 405 | int index; 406 | struct boundary_tag *tag; 407 | 408 | if ( ptr == NULL ) return; 409 | 410 | liballoc_lock(); 411 | 412 | 413 | tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag )); 414 | 415 | if ( tag->magic != LIBALLOC_MAGIC ) 416 | { 417 | liballoc_unlock(); // release the lock 418 | return; 419 | } 420 | 421 | 422 | 423 | #ifdef DEBUG 424 | l_inuse -= tag->size; 425 | LOG_INFO("free: %x, {i}, {i}\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 ); 426 | #endif 427 | 428 | 429 | // MELT LEFT... 430 | while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) ) 431 | { 432 | #ifdef DEBUG 433 | LOG_INFO("Melting tag left into available memory. Left was {i}, becomes {i} ({i})\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size ); 434 | #endif 435 | tag = melt_left( tag ); 436 | remove_tag( tag ); 437 | } 438 | 439 | // MELT RIGHT... 440 | while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) ) 441 | { 442 | #ifdef DEBUG 443 | LOG_INFO("Melting tag right into available memory. This was was {i}, becomes {i} ({i})\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size ); 444 | #endif 445 | tag = absorb_right( tag ); 446 | } 447 | 448 | 449 | // Where is it going back to? 450 | index = getexp( tag->real_size - sizeof(struct boundary_tag) ); 451 | if ( index < MINEXP ) index = MINEXP; 452 | 453 | // A whole, empty block? 454 | if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) 455 | { 456 | 457 | if ( l_completePages[ index ] == MAXCOMPLETE ) 458 | { 459 | // Too many standing by to keep. Free this one. 460 | unsigned int pages = tag->real_size / l_pageSize; 461 | 462 | if ( (tag->real_size % l_pageSize) != 0 ) pages += 1; 463 | if ( pages < l_pageCount ) pages = l_pageCount; 464 | 465 | liballoc_free( tag, pages ); 466 | 467 | #ifdef DEBUG 468 | l_allocated -= pages * l_pageSize; 469 | LOG_INFO("Resource freeing %x of {i} pages\n", tag, pages ); 470 | dump_array(); 471 | #endif 472 | 473 | liballoc_unlock(); 474 | return; 475 | } 476 | 477 | 478 | l_completePages[ index ] += 1; // Increase the count of complete pages. 479 | } 480 | 481 | 482 | // .......... 483 | 484 | 485 | insert_tag( tag, index ); 486 | 487 | #ifdef DEBUG 488 | LOG_INFO("Returning tag with {i} bytes (requested {i} bytes), which has exponent: {i}\n", tag->real_size, tag->size, index ); 489 | dump_array(); 490 | #endif 491 | 492 | liballoc_unlock(); 493 | } 494 | 495 | 496 | 497 | 498 | void* calloc(size_t nobj, size_t size) 499 | { 500 | int real_size; 501 | void *p; 502 | 503 | real_size = nobj * size; 504 | 505 | p = malloc( real_size ); 506 | 507 | liballoc_memset( p, 0, real_size ); 508 | 509 | return p; 510 | } 511 | 512 | 513 | 514 | void* realloc(void *p, size_t size) 515 | { 516 | void *ptr; 517 | struct boundary_tag *tag; 518 | int real_size; 519 | 520 | if ( size == 0 ) 521 | { 522 | free( p ); 523 | return NULL; 524 | } 525 | if ( p == NULL ) return malloc( size ); 526 | 527 | if ( liballoc_lock != NULL ) liballoc_lock(); // lockit 528 | tag = (struct boundary_tag*)((unsigned int)p - sizeof( struct boundary_tag )); 529 | real_size = tag->size; 530 | if ( liballoc_unlock != NULL ) liballoc_unlock(); 531 | 532 | if ( real_size > size ) real_size = size; 533 | 534 | ptr = malloc( size ); 535 | liballoc_memcpy( ptr, p, real_size ); 536 | free( p ); 537 | 538 | return ptr; 539 | } 540 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/alloc/pEpitOS-liballoc.c: -------------------------------------------------------------------------------- 1 | 2 | #include "multicore/lock.h" 3 | #include "arch/arch.h" 4 | #include "memory/vmmwrapper.h" 5 | 6 | CREATE_LOCK(lock_alloc); 7 | CREATE_PROTOS(lock_alloc); 8 | 9 | extern int liballoc_lock() 10 | { 11 | //WAIT_LOCK(LOCK_NAME(lock_alloc)); 12 | GRAB_LOCK(LOCK_NAME(lock_alloc)); 13 | return 0; 14 | } 15 | 16 | extern int liballoc_unlock() 17 | { 18 | RELEASE_LOCK(LOCK_NAME(lock_alloc)); 19 | return 0; 20 | } 21 | extern void* liballoc_alloc(int n) 22 | { 23 | void *ptr = (void*)space_alloc(n, MAP_PRESENT | MAP_WRITE); 24 | return ptr; 25 | } 26 | 27 | extern int liballoc_free(void* p, int n) 28 | { 29 | space_free((uintptr_t)p, n); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/gcc/memory.c: -------------------------------------------------------------------------------- 1 | #include "freestanding.h" 2 | 3 | void *memset(volatile void *b, int c, size_t len){ 4 | char *bb; 5 | 6 | for (bb = (char*)(b); len > 0; len--) 7 | *bb++ = c; 8 | 9 | return (void*)b; 10 | } 11 | 12 | void *memcpy(volatile void *dest, volatile const void *src, size_t n){ 13 | char* x = (char*)dest; 14 | char* y = (char*)src; 15 | for(size_t i = 0; i < n; i++, x++, y++) 16 | *x = *y; 17 | return (void*)dest; 18 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/io/print.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | 3 | void sprintf(char *format, char *buff, va_list args){ 4 | while (*format){ 5 | if (*format == '{' && format[1] && format[2] == '}'){ 6 | format++; 7 | switch (*format){ 8 | case 'd':{ 9 | char buffer[30]; 10 | size_t d = va_arg(args, size_t); 11 | char *newbuff = dec(d, buffer + 29); 12 | while (*newbuff) 13 | *(buff++) = *(newbuff++); 14 | } 15 | break; 16 | case 'x':{ 17 | char buffer[30]; 18 | size_t d = va_arg(args, size_t); 19 | *(buff++) = '0'; 20 | *(buff++) = 'x'; 21 | 22 | char *newbuff = decX(d, buffer + 29); 23 | while (*newbuff) 24 | *(buff++) = *(newbuff++); 25 | } 26 | break; 27 | case 's':{ 28 | char *str = va_arg(args, char *); 29 | while (*str) 30 | *(buff++) = *(str++); 31 | } 32 | break; 33 | default: 34 | break; 35 | } 36 | format++; 37 | } 38 | else{ 39 | *buff = *format; 40 | buff++; 41 | } 42 | format++; 43 | } 44 | *buff = 0; 45 | } 46 | 47 | void printf(char *format, ...){ 48 | char buffer[500]; 49 | va_list args; 50 | va_start(args, format); 51 | 52 | sprintf(format, buffer, args); 53 | va_end(args); 54 | 55 | write_string(buffer); 56 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/string/convert.c: -------------------------------------------------------------------------------- 1 | char* dec(unsigned long long x, char *s) { 2 | *--s = 0; 3 | if (!x) 4 | *--s = '0'; 5 | for (; x; x /= 10) 6 | *--s = '0' + x % 10; 7 | return s; 8 | } 9 | 10 | char* decX(unsigned long long x, char *s) { 11 | char list[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 12 | *--s = 0; 13 | if (!x) 14 | *--s = '0'; 15 | for (; x; x /= 16) 16 | *--s = list[x % 16]; 17 | return s; 18 | } 19 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/utils/string/string.c: -------------------------------------------------------------------------------- 1 | #include "freestanding.h" 2 | 3 | bool strcmp(volatile char* str1, volatile char* str2){ 4 | for(;*str1 && *str2 && *str1 == *str2; str1++,str2++ ); 5 | if(*str1 == *str2) 6 | return 0; 7 | if(*str1) 8 | return -1; 9 | return 1; 10 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/src/vmmwrapper.c: -------------------------------------------------------------------------------- 1 | #include "memory/vmmwrapper.h" 2 | #include "vmm/vmm.h" 3 | #include "log/log.h" 4 | 5 | // should be defined in arch vmm 6 | uint64_t convert_to_arch_flags(uintptr_t flags); 7 | 8 | uintptr_t space_alloc(size_t size, uintptr_t flags) 9 | { 10 | uint64_t address = search_available(craft_addr(0,0,0,1,0), size); 11 | if(address == 0) 12 | return 0; 13 | kmmap(address, size, convert_to_arch_flags(flags)); 14 | LOG_INFO("Allocated {x} at address {x}", size, address); 15 | return address; 16 | } 17 | 18 | void space_free(uintptr_t addr, size_t size) 19 | { 20 | kmunmap(addr, size, MEM_TO_UPPER); 21 | // return 0; 22 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/userspace/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc-9 2 | LOGS = 3 | CFLAGS = -Wall -Wextra -O3 -DPTESTS -I$(ARCH_FOLDER)/$(ARCH)/include/ -I$(KERNEL_DIR)/include/ $(LOGS) 4 | 5 | ASMPARAM = -f elf64 -F dwarf 6 | 7 | BUILD = build 8 | 9 | LINK_SCRIPT = link.ld 10 | 11 | INTERNALLDFLAGS := \ 12 | -nostdlib \ 13 | -T$(LINK_SCRIPT) \ 14 | -z max-page-size=0x1000\ 15 | #-Wl,-static,-pie,--no-dynamic-linker,-ztext -fno-pic -fpie 16 | 17 | INTERNALCFLAGS := \ 18 | -std=gnu17 \ 19 | -ffreestanding \ 20 | -fno-stack-protector \ 21 | -fno-pic -fno-pie \ 22 | -mno-red-zone \ 23 | -mno-sse \ 24 | -fno-zero-initialized-in-bss \ 25 | -mcmodel=kernel \ 26 | -fno-isolate-erroneous-paths-attribute \ 27 | -fno-delete-null-pointer-checks \ 28 | -masm=intel \ 29 | -m64 30 | 31 | SRCDIRS := $(shell find . -type d) 32 | 33 | CFILES := $(shell find . -type f -name '*.c') 34 | SFILES := $(shell find . -type f -name '*.s') 35 | 36 | OBJ := $(SFILES:%.s=$(BUILD)/%.so) 37 | OBJ += $(CFILES:%.c=$(BUILD)/%.so) 38 | 39 | $(shell mkdir -p $(addprefix $(BUILD)/,$(SRCDIRS))) 40 | 41 | all: compile 42 | 43 | .PHONY: all clean compile 44 | 45 | compile: $(BUILD)/tid0.so 46 | 47 | $(BUILD)/%.so: $(BUILD)/%.o 48 | $(CC) -o $@ $^ $(INTERNALLDFLAGS) 49 | 50 | $(BUILD)/%.o: %.c 51 | $(CC) -c -o $@ $^ $(CFLAGS) $(INTERNALCFLAGS) 52 | 53 | $(BUILD)/%.o: %.c 54 | @$(CC) -o $@ $(CFLAGS) $(INTERNALCFLAGS) -c $< 55 | 56 | $(BUILD)/%.o: %.s 57 | @nasm $(ASMPARAM) -o $@ $< 58 | 59 | clean: 60 | @rm -rf $(BUILD) 61 | -------------------------------------------------------------------------------- /src/pEpitOS-kernel/userspace/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_main) 2 | SECTIONS 3 | { 4 | . = 0x1000; 5 | .entry : ALIGN(4096) { 6 | KEEP(*(.entry)) 7 | } 8 | 9 | 10 | .text : ALIGN(4K) { 11 | *(.text*) 12 | } 13 | 14 | .rodata : ALIGN(4K) { 15 | *(.rodata*) 16 | } 17 | 18 | .data : ALIGN(4K) { 19 | *(.data*) 20 | } 21 | 22 | .bss : ALIGN(4K) { 23 | *(COMMON) 24 | *(.bss*) 25 | } 26 | 27 | .note.gnu.build-id : ALIGN(4096) { 28 | KEEP(*(.note.gnu.build-id)) 29 | } 30 | 31 | .eh_frame : { 32 | KEEP(*(.eh_frame)) 33 | } 34 | } -------------------------------------------------------------------------------- /src/pEpitOS-kernel/userspace/tid0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // static volatile char test_string[] = "Hello world!"; 5 | // static volatile char *rodata = "Hello world!"; 6 | 7 | enum map_flags { 8 | 9 | MAP_PRESENT = 1, 10 | MAP_WRITE = 2, 11 | MAP_USER = 4, 12 | MAP_COPY_ON_WRITE = 8, 13 | MAP_EXECUTE = 16, 14 | MAP_SWAPPED = 32, 15 | }; 16 | 17 | void *mmap(uintptr_t addr, size_t size, int flags); 18 | 19 | __attribute__((section(".entry"), used)) 20 | void _main() 21 | { 22 | asm volatile("push rbp"); 23 | asm volatile("mov rbp, rsp"); 24 | //asm volatile("int 0x80"); 25 | volatile char *plouf = mmap(0x780000, 0x1000, MAP_PRESENT | MAP_WRITE | MAP_USER); 26 | *plouf = 5; 27 | while(1); 28 | _main(); 29 | } 30 | 31 | void *mmap(uintptr_t addr, size_t size, int flags) 32 | { 33 | asm volatile("mov r15, 1"); 34 | asm volatile("mov rdi, %0" : : "r"(addr)); 35 | asm volatile("mov rsi, %0" : : "r"(size)); 36 | asm volatile("mov r8, %0" : : "r"((uint64_t)flags)); 37 | void *ret; 38 | asm volatile("syscall" : "=a"(ret):); 39 | return ret; 40 | } 41 | 42 | int plouf(int a, int b){ 43 | return a + b; 44 | } --------------------------------------------------------------------------------