Vystem 0.2

This commit is contained in:
2026-05-27 19:34:54 +02:00
parent a43c08b893
commit d238606b75
372 changed files with 51320 additions and 83217 deletions

View File

@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_AP_H
#define SH_LIB_AP_H
#include "std/status.h"
#include "std/type.h"
#include "memory/memory.h"
#include "irq/gdt.h"
#include "irq/idt.h"
#include "devs/apic/lapic.h"
#define SH_AP_AP_TRAMPOLINE 0x7000
#define SH_AP_GDT_32_PA 0x8000
#define SH_AP_BOOTSTRAP_PA 0x9000
#define SH_AP_TRAMPOLINE_PAYLOAD 0xA000
#define SH_AP_STATE_PENDING 0x00
#define SH_AP_STATE_NO_LAPIC 0x01
#define SH_AP_STATE_OK 0x02
// Fill the 32 bits GDT used by AP trampoline
SH_STATUS sh_ap_load_gdt_32();
// AP boostrap structure, shared with each AP
#pragma pack(1)
typedef struct {
sh_page_PHYSICAL_ADDRESS lapic_base_pa;
sh_page_VIRTUAL_ADDRESS c_entry_point_va;
sh_page_PHYSICAL_ADDRESS page_table_pa;
sh_page_VIRTUAL_ADDRESS cpu_struct_base_area;
sh_page_VIRTUAL_ADDRESS shared_gdt_64_va;
sh_gdt_GDTR gdt_64_gdtr;
sh_idt_IDT *idt;
} sh_ap_AP_BOOTSTRAP;
#pragma pack()
// Per-CPU structure, one for each AP
#pragma pack(1)
typedef struct {
sh_uint64 cpu_id;
sh_uint32 bytes_outputed;
sh_bool timer_state;
char *temp_buffer;
sh_uint64 temp_buffer_size;
} sh_ap_PER_CPU;
#pragma pack()
// CPU structure, one for each AP
#pragma pack(1)
typedef struct {
sh_page_VIRTUAL_ADDRESS c_entry_point_stack_top_va;
sh_uint32 lapic_id; // just for the tranpoline to confirm it has found his own struct
sh_uint16 tss_selector;
sh_ap_PER_CPU *per_cpu;
} sh_ap_CPU_STRUCT;
#pragma pack()
// Allocate each sets of stacks for each TSS and each C stack, create each TSS entry, create global GDT64, create the CPU structure area, create and fill each CPU structure, create the AP bootstrap structure and place it correctly
SH_STATUS sh_ap_prepare_for_smp_launch(sh_lapic_DEVICE **lapic_dev_array,sh_uint64 max_lapic_id,sh_uint64 expected_lapic_found,sh_conf_BOOT_CONFIG *boot_config,sh_idt_IDT *idt);
// AP C entry point
void sh_ap_entry_point();
// Start AP boot procedure
SH_STATUS sh_ap_start_ap_boot_procedure(sh_conf_BOOT_CONFIG *boot_config);
#endif

View File

@@ -3,14 +3,17 @@
#define SH_LIB_ASM_H
#include "std/type.h"
#include "std/status.h"
#include "irq/gdt.h"
#include "irq/tss.h"
#include "irq/idt.h"
// inb instruction wrapper
static inline sh_uint8 sh_asm_inb(sh_uint16 port) {
inline sh_uint8 sh_asm_inb(sh_uint16 port) {
sh_uint8 val;
__asm__ volatile ("inb %1, %0":"=a"(val):"Nd"(port));
return val;
}
// outb instruction wrapper
static inline void sh_asm_outb(sh_uint16 port,sh_uint8 val) {
inline void sh_asm_outb(sh_uint16 port,sh_uint8 val) {
__asm__ volatile ("outb %0, %1"::"a"(val),"Nd"(port));
}
// rdtsc instruction wrapper
@@ -23,4 +26,44 @@ static inline sh_uint64 sh_asm_rdtsc() {
static inline void sh_asm_invlpg(void *addr) {
__asm__ volatile ("invlpg (%0)"::"r"(addr):"memory");
}
// lgdt instruction wrapper
static inline void sh_asm_lgdt(sh_gdt_GDTR gdtr) {
__asm__ volatile ("lgdt %0"::"m"(gdtr):"memory");
}
// ltr instruction wrapper
static inline void sh_asm_ltr(sh_uint16 tss_selector) {
__asm__ volatile ("ltr %0"::"r"(tss_selector):"memory");
}
// lidt instruction wrapper
static inline void sh_asm_lidt(sh_idt_IDTR idtr) {
__asm__ volatile ("lidt %0"::"m"(idtr):"memory");
}
// sidt instruction wrapper
static inline void sh_asm_sidt(sh_idt_IDTR* idtr) {
__asm__ volatile ("sidt %0":"=m"(*idtr)::"memory");
}
// sti instruction wrapper
static inline void sh_asm_sti() {
__asm__ volatile ("sti");
}
// cli instruction wrapper
static inline void sh_asm_cli() {
__asm__ volatile ("cli");
}
// cpuid instruction wrapper
static inline void sh_asm_cpuid(sh_uint32 leaf,sh_uint32 subleaf,sh_uint32 *eax,sh_uint32 *ebx,sh_uint32 *ecx,sh_uint32 *edx){
__asm__ volatile ("cpuid":"=a"(*eax),"=b"(*ebx),"=c"(*ecx),"=d"(*edx):"a"(leaf),"c"(subleaf));
}
// mfence instruction wrapper
inline void sh_asm_mfence() {
__asm__ volatile("mfence":::"memory");
}
// lfence instruction wrapper
inline void sh_asm_lfence() {
__asm__ volatile("lfence":::"memory");
}
// sfence instruction wrapper
inline void sh_asm_sfence() {
__asm__ volatile("sfence":::"memory");
}
#endif

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PIC_H
#define SH_LIB_PIC_H
#include "std/stdlib.h"
#define SH_PIC1_CMD 0x20
#define SH_PIC1_DATA 0x21
#define SH_PIC2_CMD 0xA0
#define SH_PIC2_DATA 0xA1
// Remap all PIC interrupts on interrupts vectors 32 to 47, leave only IRQ0 enabled
void sh_pic_remap();
// Unmask a PIC interrupt
void sh_pic_unmask(sh_uint8 irq);
// Mask a PIC interrupt
void sh_pic_mask(sh_uint8 irq);
// Send EOI to PIC
void sh_pic_send_eoi(sh_uint8 irq);
#endif

View File

@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PIT_H
#define SH_LIB_PIT_H
#include "std/stdlib.h"
// Set PIT frequency
void sh_pit_set_frequency(sh_uint64 hz);
#endif

View File

@@ -4,6 +4,7 @@
#include "std/type.h"
#include "std/status.h"
#include "cpu/asm.h"
#include "devs/devs.h"
typedef sh_uint64 sh_tsc_TSC_VALUE;
// Reas TSC register.
static inline sh_tsc_TSC_VALUE sh_tsc_read_tsc() {
@@ -15,4 +16,16 @@ SH_STATUS sh_tsc_init_tsc();
sh_tsc_TSC_VALUE sh_tsc_get_kernel_init_tsc();
// Return kernel current tsc.
sh_tsc_TSC_VALUE sh_tsc_get_kernel_current_tsc();
// Estimate CPU frequency using TSC and PIT
sh_uint64 sh_tsc_estimate_cpu_freq();
// Load CPU frequency
void sh_tsc_load_cpu_freq(sh_uint64 cpu_freq);
// Detect if CPUID provide hypervisor bit
sh_bool sh_tsc_has_hypervisor();
// Detect if CPUID provide TSC constant bit
sh_bool sh_tsc_is_tsc_constant();
// Return CPUID CPU frequence if available
SH_STATUS sh_tsc_get_cpu_freq_cpuid(sh_uint64 *freq);
// Parse a TSC DevS query
SH_STATUS sh_tsc_devs_query(char *sub_path,sh_devs_RESULT *result);
#endif

View File

@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_ACPI_H
#define SH_LIB_ACPI_H
#include "std/stdlib.h"
// ACPI v1 RSDP structure
typedef struct {
sh_uint8 signature[8];
sh_uint8 checksum;
sh_uint8 oem_id[6];
sh_uint8 revision;
sh_uint32 rsdt_address;
} sh_acpi_RSDP_V1;
// ACPI v2 RSDP structure
typedef struct {
sh_acpi_RSDP_V1 first_part;
sh_uint32 length;
sh_uint64 xsdt_address;
sh_uint8 extended_checksum;
sh_uint8 reserved[3];
} sh_acpi_RSDP_V2;
// ACPI pointers root structure
typedef struct {
sh_uint64 rsdt;
sh_uint64 xsdt; // set to 0 if ACPI v2 isn't supported
} sh_apci_ACPI_POINTERS_ROOT;
// ACPI XSDT header
typedef struct {
char signature[4];
sh_uint32 length;
sh_uint8 revision;
sh_uint8 checksum;
char oem_id[6];
char oem_table_id[8];
sh_uint32 oem_revision;
sh_uint32 creator_id;
sh_uint32 creator_revision;
} sh_acpi_ACPI_XSDT_HEADER;
// ACPI XSTD body
typedef struct {
sh_uint64 *entries;
sh_uint64 entry_count;
} sh_acpi_ACPI_XSDT_BODY;
// ACPI tables list
typedef struct {
sh_uint64 madt_physical_address;
} sh_acpi_ACPI_TABLES;
// ACPI table header
typedef struct {
char signature[4];
sh_uint32 length;
sh_uint8 revision;
sh_uint8 checksum;
char oem_id[6];
char oem_table_id[8];
sh_uint32 oem_revision;
sh_uint32 creator_id;
sh_uint32 creator_revision;
} sh_acpi_TABLE_HEADER;
// Try to obtain ACPI root pointer
SH_STATUS sh_acpi_parse_rsdp(sh_uint64 rsdp,sh_uint8 acpi_ver,sh_apci_ACPI_POINTERS_ROOT *out);
// Parse XSDT header and ensure that all entries are mapped
SH_STATUS sh_acpi_parse_xsdt(sh_uint64 xsdt,sh_acpi_ACPI_XSDT_BODY *xsdt_body);
// Parse XSDT entries, ensure that all the headers of each table is mapped and sort all entries into their respectives fields inside acpi_tables. Doesn't parse each table header
SH_STATUS sh_acpi_parse_tables(sh_acpi_ACPI_XSDT_BODY *xsdt_body,sh_acpi_ACPI_TABLES *acpi_tables);
#endif

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_ACPI_MADT_H
#define SH_LIB_ACPI_MADT_H
#include "std/stdlib.h"
// MADT header structure
typedef struct {
char signature[4];
sh_uint32 length;
sh_uint8 revision;
sh_uint8 checksum;
char oem_id[6];
char oem_table_id[8];
sh_uint32 oem_revision;
sh_uint32 creator_id;
sh_uint32 creator_revision;
} sh_acpi_madt_TABLE_HEADER;
// MADT structure
typedef struct {
sh_acpi_madt_TABLE_HEADER header;
sh_uint32 local_apic_address;
sh_uint32 flags;
} sh_acpi_madt_MADT;
// MADT entry header structure
typedef struct {
sh_uint8 type;
sh_uint8 length;
} sh_acpi_madt_ENTRY_HEADER;
// Local APIC structure
typedef struct {
sh_acpi_madt_ENTRY_HEADER header;
sh_uint8 acpi_processor_id;
sh_uint8 apic_id;
sh_uint32 flags;
} sh_acpi_madt_LAPIC;
// IO APIC structure
typedef struct {
sh_acpi_madt_ENTRY_HEADER header;
sh_uint8 ioapic_id;
sh_uint8 reserved;
sh_uint32 ioapic_address;
sh_uint32 global_system_interrupt_base;
} sh_acpi_madt_IOAPIC;
// Interrupt source override structure
typedef struct {
sh_acpi_madt_ENTRY_HEADER header;
sh_uint8 bus;
sh_uint8 source;
sh_uint32 gsi;
sh_uint16 flags;
} sh_acpi_madt_ISO;
// Parse MADT table
SH_STATUS sh_acpi_madt_parse(sh_uint64 madt_ptr);
#endif

View File

@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_IOAPIC_H
#define SH_LIB_IOAPIC_H
#include "std/stdlib.h"
#include "memory/page.h"
#define SH_IOAPIC_OFFSET_IOREGSEL 0x00
#define SH_IOAPIC_OFFSET_IOWIN 0x10
#define SH_IOAPIC_REGISTER_IOAPICID 0x00
#define SH_IOAPIC_REGISTER_IOAPICVER 0x01
#define SH_IOAPIC_REGISTER_IOAPICARB 0x02
#define SH_IOAPIC_REGISTER_IOREDTBL_BASE 0x10
// IOAPIC device structure
typedef struct {
volatile sh_uint32 *base;
sh_uint8 ioapic_id;
sh_uint32 gsi_base;
sh_uint32 gsi_count; // must be completed by reading the IOAPICVER register in the sh_ioapic_init call
sh_SPIN_LOCK lock;
} sh_ioapic_DEVICE;
// Initialize an IOAPIC device structure, intented to initialize all IOAPIC devices structures during MADT parsing
SH_STATUS sh_ioapic_init(sh_uint32 base,sh_uint8 ioapic_id,sh_uint32 gsi_base,sh_ioapic_DEVICE *ioapic);
// Initialize DevS IOAPIC backend (max_ioapic_id is the max IOAPIC id, not the number of IOAPIC counted)
SH_STATUS sh_ioapic_init_devs(sh_uint8 max_ioapic_id);
// Bind a LAPIC device to DevS LAPIC backend
SH_STATUS sh_ioapic_bind(sh_ioapic_DEVICE *lapic_dev);
// Return a pointer to an IOAPIC device based on the provided IOAPIC id
sh_ioapic_DEVICE *sh_ioapic_get_dev_ioapic_id(sh_uint64 ioapic_id);
#define SH_IOAPIC_IOREDTBL_DELIVERY_FIXED 0b000
#define SH_IOAPIC_IOREDTBL_DELIVERY_LOWEST_PRIORITY 0b001
#define SH_IOAPIC_IOREDTBL_DELIVERY_NMI 0b100
#define SH_IOAPIC_IOREDTBL_DELIVERY_INIT 0b101
#define SH_IOAPIC_IOREDTBL_DELIVERY_EXTINT 0b111
#define SH_IOAPIC_IOREDTBL_TRIGGER_EDGE 0b0
#define SH_IOAPIC_IOREDTBL_TRIGGER_LEVEL 0b1
#define SH_IOAPIC_IOREDTBL_POLARITY_HIGH 0b0
#define SH_IOAPIC_IOREDTBL_POLARITY_LOW 0b1
#define SH_IOAPIC_IOREDTBL_DEST_MODE_PHYSICAL 0b0
#define SH_IOAPIC_IOREDTBL_DEST_MODE_LOGICAL 0b1
// IOREDTBL entry structure
typedef struct {
sh_uint32 low;
sh_uint32 high;
} sh_ioapic_IOREDTBL_ENTRY;
// Create an IOREDTBL entry
inline sh_ioapic_IOREDTBL_ENTRY sh_ioapic_make_ioredtbl_entry(sh_uint8 vector,sh_uint8 delivery_mode,sh_uint8 destination_mode,sh_uint8 polarity,sh_uint8 trigger_mode,sh_bool mask,sh_uint8 apic_id) {
sh_ioapic_IOREDTBL_ENTRY e={0};
e.low=(e.low& ~0xFFU)|vector;
e.low=(e.low& ~(0x7U<<8))|((delivery_mode&0x7U)<<8);
e.low=(e.low& ~(1U<<11))|((destination_mode&0x1U)<<11);
e.low=(e.low& ~(1U<<13))|((polarity&0x1U)<<13);
e.low=(e.low& ~(1U<<15))|((trigger_mode&0x1U)<<15);
e.low=(e.low& ~(1U<<16))|((mask&0x1U)<<16);
e.high=(e.high& ~(0xFFU<<24))|((sh_uint32)apic_id<<24);
return e;
}
// Mask an IOREDTBL entry for the provided GSI
SH_STATUS sh_ioapic_mask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi);
// Unmask an IOREDTBL entry for the provided GSI
SH_STATUS sh_ioapic_unmask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi);
// Read an IOREDTBL entry for the provided GSI
SH_STATUS sh_ioapic_read_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Write an IOREDTBL entry for the provided GSI
SH_STATUS sh_ioapic_write_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Mask all IOREDTBL entries for all IOAPIC
SH_STATUS sh_ioapic_mask_all();
// Return the IOAPIC device corresponding to the provided GSI
sh_ioapic_DEVICE *sh_ioapic_get_dev_by_gsi(sh_uint32 gsi);
// Parse an IOAPIC DevS query
SH_STATUS sh_ioapic_devs_query(char *sub_path,sh_devs_RESULT *result);
#endif

View File

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_LAPIC_H
#define SH_LIB_LAPIC_H
#include "std/status.h"
#include "std/type.h"
#include "memory/page.h"
#include "devs/devs.h"
#define SH_LAPIC_OFFSET_ID 0x020
#define SH_LAPIC_OFFSET_VERSION 0x030
#define SH_LAPIC_OFFSET_EOI 0x0B0
#define SH_LAPIC_OFFSET_SVR 0x0F0
#define SH_LAPIC_OFFSET_ESR 0x280
#define SH_LAPIC_OFFSET_ICR_LOW 0x300
#define SH_LAPIC_OFFSET_ICR_HIGH 0x310
#define SH_LAPIC_OFFSET_LVT_TIMER 0x320
#define SH_LAPIC_OFFSET_LVT_ERROR 0x370
#define SH_LAPIC_OFFSET_TIMER_INIT 0x380
#define SH_LAPIC_OFFSET_TIMER_CURR 0x390
#define SH_LAPIC_OFFSET_TIMER_DIV 0x3E0
#define SH_LAPIC_TIMER_DIVIDER 0x3
// LAPIC device structure
typedef struct {
volatile sh_uint32 *base;
sh_uint8 apic_id;
sh_uint8 acpi_processor_id;
sh_uint32 flags;
sh_uint32 spurious_vector;
} sh_lapic_DEVICE;
// Initialize a LAPIC device structure, intented to initialize all LAPIC devices structures during MADT parsing
SH_STATUS sh_lapic_init(sh_uint64 lapic_phys,sh_uint8 spurious_vector,sh_uint8 apic_id,sh_uint8 apic_processor_id,sh_uint32 flags,sh_lapic_DEVICE *lapic);
// Initialize LAPIC for this CPU, intended to be used once by each CPU
SH_STATUS sh_lapic_init_dev(sh_uint8 spurious_vector,sh_lapic_DEVICE *lapic);
// Initialize DevS LAPIC backend (max_lapic_id is the max LAPIC id, not the number of LAPIC counted)
SH_STATUS sh_lapic_init_devs(sh_uint16 max_lapic_id,sh_uint16 max_acpi_processor_id);
// Bind a LAPIC device to DevS LAPIC backend
SH_STATUS sh_lapic_bind(sh_lapic_DEVICE *lapic_dev);
// Write 0 in provided LAPIC device EOI register
void sh_lapic_eoi(sh_lapic_DEVICE *lapic);
// Return a pointer to a LAPIC device based on the provided APIC id
sh_lapic_DEVICE *sh_lapic_get_dev_apic_id(sh_uint64 apic_id);
// Return a pointer to a LAPIC device based on the provided ACPI processor id
sh_lapic_DEVICE *sh_lapic_get_dev_acpi_cpu_id(sh_uint64 acpi_processor_id);
// Launch a LAPIC one-shot timer, independantely of the calibrated state of the LAPIC
SH_STATUS sh_lapic_timer_one_shot(sh_lapic_DEVICE *lapic_dev,sh_uint32 initial_value);
// Calibrate the LAPIC frequency
SH_STATUS sh_lapic_calibrate(sh_lapic_DEVICE *lapic_dev,sh_uint64 cpu_freq);
// Return the LAPIC frequency
sh_uint64 sh_lapic_get_frequency();
// Launch a LAPIC one-shot timer, LAPIC frequency need to be set
SH_STATUS sh_lapic_timer_one_shot_us(sh_lapic_DEVICE *lapic_dev,sh_uint64 microseconds_count);
// Return LAPIC DevS array
sh_lapic_DEVICE **sh_lapic_get_by_apic_id_array();
// Return max LAPIC APIC id
sh_uint64 sh_lapic_get_max_apic_id();
// Return max ACPI processor id
sh_uint64 sh_lapic_get_max_acpi_processor_id();
// Return LAPIC count
sh_uint64 sh_lapic_get_lapic_count();
#define SH_LAPIC_IPI_TYPE_NMI 0b100
#define SH_LAPIC_IPI_TYPE_INIT 0b101
#define SH_LAPIC_IPI_TYPE_STARTUP 0b110
#define SH_LAPIC_IPI_TYPE_FIXED 0b000
#define SH_LAPIC_IPI_DESTINATION_SPECIFIC (0b00<<18)
#define SH_LAPIC_IPI_DESTINATION_SELF (0b01<<18)
#define SH_LAPIC_IPI_DESTINATION_ALL (0b10<<18)
#define SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF (0b11<<18)
#define SH_LAPIC_IPI_NO_DESTINATION (sh_int16)(-1)
// Return SH_TRUE if LAPIC IPI feature is busy
sh_bool sh_lapic_ipi_is_busy(sh_lapic_DEVICE *lapic_dev);
// Return LAPIC id of current core, return -1 if error happened
sh_int16 sh_lapic_get_current_core();
// Send a fixed IPI with the specified vector. lapic_dev must be the struct of the current CPU.
// If destination_mode!=SH_LAPIC_IPI_DESTINATION_SPECIFIC, target_lapic_id must be SH_LAPIC_IPI_NO_DESTINATION
SH_STATUS sh_lapic_send_fixed_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint8 vector,sh_uint32 destination_mode,sh_int16 target_lapic_id);
// Send any IPI other than a fixed IPI to specified destination. lapic_dev must be the struct of the current CPU.
// ipi_type must be either SH_LAPIC_IPI_TYPE_INIT, SH_LAPIC_IPI_TYPE_STARTUP or SH_LAPIC_IPI_TYPE_NMI
// If ipi_type is SH_LAPIC_IPI_TYPE_STARTUP, start_address must contain the starting address. Address constraint (compatible with 16 bits mode) are checked.
// If ipi_type isn't SH_LAPIC_IPI_TYPE_STARTUP, start_address must be zero.
// If destination_mode!=SH_LAPIC_IPI_DESTINATION_SPECIFIC, target_lapic_id must be SH_LAPIC_IPI_NO_DESTINATION
SH_STATUS sh_lapic_send_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint32 ipi_type,sh_uint32 destination_mode,sh_int16 target_lapic_id,sh_page_PHYSICAL_ADDRESS start_address);
// Parse a LAPIC DevS query
SH_STATUS sh_lapic_devs_query(char *sub_path,sh_devs_RESULT *result);
#endif

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_DEVS_H
#define SH_LIB_DEVS_H
#include "std/status.h"
#include "std/type.h"
#include "std/string.h"
// DevS result type enum
enum sh_devs_RESULT_TYPE {
SH_DEVS_LAPIC,
SH_DEVS_IOAPIC,
SH_DEVS_VALUE,
SH_DEVS_BOOL
};
// DevS result structure
typedef struct {
enum sh_devs_RESULT_TYPE type;
sh_uint64 value;
} sh_devs_RESULT;
// Parse a DevS query
SH_STATUS sh_devs_query(char *path,sh_devs_RESULT *result);
#endif

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_EVENT_H
#define SH_LIB_EVENT_H
#include "std/type.h"
// Events types
typedef sh_uint8 sh_event_TYPE;
#define SH_EVENT_TYPE_PS2_NORMAL 0U
#define SH_EVENT_TYPE_PS2_E0 1U
#define SH_EVENT_TYPE_KBD_CONTEXT 2U
#define SH_EVENT_TYPE_KBD_PAUSE 3U
// Keyboard events context flags
#define SH_KBD_EVENT_SHIFT_ACTIVE (1u<<0)
#define SH_KBD_EVENT_WIN_ACTIVE (1u<<1)
#define SH_KBD_EVENT_LEFT_ACTIVE (1u<<1)
#define SH_KBD_EVENT_RIGHT_ACTIVE (1u<<0)
#define SH_KBD_EVENT_NUMLOCK_ACTIVE (1u<<0)
#define SH_KBD_EVENT_CAPSLOCK_ACTIVE (1u<<1)
// Keyboard contexts key scancodes
#define SH_KBD_CONTEXT_LSHIFT 0U
#define SH_KBD_CONTEXT_RSHIFT 1U
#define SH_KBD_CONTEXT_LCTRL 2U
#define SH_KBD_CONTEXT_RCTRL 3U
#define SH_KBD_CONTEXT_LALT 4U
#define SH_KBD_CONTEXT_RALT 5U
#define SH_KBD_CONTEXT_WIN 6U
#define SH_KBD_CONTEXT_NUMLOCK 7U
#define SH_KBD_CONTEXT_CAPSLOCK 8U
// Keyboard event structure
typedef struct {
sh_uint16 scancode;
sh_bool pressed;
sh_uint8 context_shift_win;
sh_uint8 context_alt;
sh_uint8 context_ctrl;
sh_uint8 context_lock_status;
sh_uint8 event_type;
sh_uint64 timestamp; // tsc
} sh_kbd_EVENT;
#endif

View File

@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_KBD_H
#define SH_LIB_KBD_H
#include "std/stdlib.h"
#include "devs/input/event.h"
// Keyboard driver handle structure, driver handles should only be owned by keyboards drivers
typedef struct sh_kbd_DRIVER_HANDLE sh_kbd_DRIVER_HANDLE;
// Keyboard consumer handle structure, used for requests made by consumer
typedef struct sh_kbd_CONSUMER_HANDLE sh_kbd_CONSUMER_HANDLE;
// Keyboard device structure
typedef struct {
sh_uint8 kbd_id;
sh_queue_KBD_EVENT *events_queue;
sh_bool present;
sh_bool ver_maj;
sh_bool ver_num;
sh_bool shift;
sh_bool alt;
sh_bool ctrl;
sh_bool win;
sh_SPIN_LOCK spinlock;
} sh_kbd_DEVICE;
// Initialize Keyboard input subsystem, should only be called one time
SH_STATUS sh_kbd_init_devs();
// Register the PS2 keyboard, completing the provided handle.
SH_STATUS sh_kbd_register_ps2(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle);
// Register any others keyboard, completing the provided handle, that should be used only by the keyboard driver for using the keyboard subsystem API
SH_STATUS sh_kbd_register(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle);
#define SH_KBD_FLAG_PRESENT 0U
#define SH_KBD_FLAG_VER_MAJ 1U
#define SH_KBD_FLAG_VER_NUM 2U
#define SH_KBD_FLAG_SHIFT 3U
#define SH_KBD_FLAG_ALT 4U
#define SH_KBD_FLAG_CTRL 5U
#define SH_KBD_FLAG_WIN 6U
// Set any flag in the sh_kbd_DEVICE struct, given that a correct handle has been provided
SH_STATUS sh_kbd_set_flag(sh_kbd_DRIVER_HANDLE *handle,sh_uint8 flag,sh_bool value);
// Push a keyboard event on the keyboard queue, given that a correct handle has been provided
SH_STATUS sh_kbd_push_events(sh_kbd_DRIVER_HANDLE *handle,sh_kbd_EVENT *event);
// Keyboard device enumeration structure
typedef struct {
sh_uint64 bitmap[4];
} sh_kbd_ENUMERATION;
// Enumerate all keyboard devices id
SH_STATUS sh_kbd_enumerate_devices(sh_kbd_ENUMERATION *enumeration);
// Return a valid consumer handle for the provided keyboard device id
SH_STATUS sh_kbd_get_handle(sh_uint8 kbd_id,sh_kbd_CONSUMER_HANDLE **handle);
// Destroy the provided consumer handle and set the pointer to SH_NULLPTR
SH_STATUS sh_kbd_destroy_handle(sh_kbd_CONSUMER_HANDLE **handle);
// Read any flag in the sh_kbd_DEVICE struct, given that a correct handle has been provided. Accept either a driver or consumer handle, but fail if both handle are provided
SH_STATUS sh_kbd_read_flag(sh_kbd_DRIVER_HANDLE *d_handle,sh_kbd_CONSUMER_HANDLE *c_handle,sh_uint8 flag,sh_bool *value);
#endif

View File

@@ -0,0 +1,105 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PS2_H
#define SH_LIB_PS2_H
#include "std/stdlib.h"
#include "devs/input/event.h"
#include "devs/input/kbd.h"
// Port macros
#define SH_PS2_PORT_DATA 0x60
#define SH_PS2_PORT_COMMAND 0x64
// Status byte bits
#define SH_PS2_STATUS_OBF 0b1
#define SH_PS2_STATUS_IBF 0b10
#define SH_PS2_STATUS_MOUSE_DATA 0b100000
#define SH_PS2_STATUS_TIMEOUT 0b1000000
#define SH_PS2_STATUS_PARITY 0b10000000
// Config byte bits
#define SH_PS2_CONFIG_PORT1_IRQ 0b1
#define SH_PS2_CONFIG_PORT2_IRQ 0b10
#define SH_PS2_CONFIG_PORT1_CLOCK_DISABLED 0b10000
#define SH_PS2_CONFIG_PORT2_CLOCK_DISABLED 0b100000
#define SH_PS2_CONFIG_TRANSLATION 0b1000000
// PS2 controller commands macros
#define SH_PS2_COMMAND_READ_CONFIG 0x20
#define SH_PS2_COMMAND_WRITE_CONFIG 0x60
#define SH_PS2_COMMAND_PS2_SELF_TEST 0xAA
#define SH_PS2_COMMAND_PORT1_TEST 0xAB
#define SH_PS2_COMMAND_PORT2_DISABLE 0xA7
#define SH_PS2_COMMAND_PORT2_ENABLE 0xA8
#define SH_PS2_COMMAND_PORT2_TEST 0xA9
#define SH_PS2_COMMAND_PORT1_DISABLE 0xAD
#define SH_PS2_COMMAND_PORT1_ENABLE 0xAE
#define SH_PS2_COMMAND_READ_OUTPUT 0xD0
#define SH_PS2_COMMAND_WRITE_OUTPUT 0xD1
#define SH_PS2_COMMAND_WRITE_PORT2 0xD4
// Self test results macros
#define SH_PS2_SELF_TEST_SUCCESS 0x55
#define SH_PS2_SELF_TEST_FAIL 0xFC
#define SH_PS2_PORTS_SELF_TEST_SUCCESS 0x00
// PS2 keyboard commands macros
#define SH_PS2_KBD_COMMAND_SET_LEDS 0xED
#define SH_PS2_KBD_COMMAND_ECHO 0xEE
#define SH_PS2_KBD_COMMAND_SC_SET 0xF0
#define SH_PS2_KBD_COMMAND_IDENTIFY 0xF2
#define SH_PS2_KBD_COMMAND_ENABLE_SCANNING 0xF4
#define SH_PS2_KBD_COMMAND_DISABLE_SCANNING 0xF5
#define SH_PS2_KBD_COMMAND_DEFAULTS 0xF6
#define SH_PS2_KBD_COMMAND_RESET 0xFF
// Leds bits
#define SH_PS2_KBD_LEDS_SCROLL_LOCK 0b1
#define SH_PS2_KBD_LEDS_NUM_LOCK 0b10
#define SH_PS2_KBD_LEDS_CAPS_LOCK 0b100
// Scancodes (SC) sets
#define SH_PS2_KBD_SC_SET_CURRENT 0
#define SH_PS2_KBD_SC_SET_1 1
#define SH_PS2_KBD_SC_SET_2 2
#define SH_PS2_KBD_SC_SET_3 3
// Keyboard response macros
#define SH_PS2_KBD_ACK 0xFA
#define SH_PS2_KBD_RESEND 0xFE
#define SH_PS2_KBD_BAT_SUCCESS 0xAA
#define SH_PS2_KBD_BAT_FAIL 0xFC
#define SH_PS2_KBD_ECHO_REPLY 0xEE
// Return SH_TRUE if data port contain useful datas to read
inline sh_bool sh_ps2_output_ready() {
return sh_asm_inb(SH_PS2_PORT_COMMAND) & SH_PS2_STATUS_OBF;
}
// Return SH_TRUE if controller isn't ready for any output
inline sh_bool sh_ps2_cant_write() {
return sh_asm_inb(SH_PS2_PORT_COMMAND) & SH_PS2_STATUS_IBF;
}
// Keyboard command struct
typedef struct {
sh_uint8 command;
sh_uint8 data;
sh_bool has_data;
} sh_ps2_KBD_COMMAND;
// Read status byte
inline sh_uint8 sh_ps2_read_status() {
return sh_asm_inb(SH_PS2_PORT_COMMAND);
}
// Read config byte
inline sh_uint8 sh_ps2_read_config() {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_READ_CONFIG);
while (!sh_ps2_output_ready());
return sh_asm_inb(SH_PS2_PORT_DATA);
}
// Write config byte
inline void sh_ps2_write_config(sh_uint8 config) {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_WRITE_CONFIG);
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,config);
}
// PS2 IRQ1 handler
void sh_ps2_irq1_handler();
// Send a keyboard command and wait for it to finish
SH_STATUS sh_ps2_send_keyboard_command_wait(sh_uint8 cmd,sh_uint8 data,sh_bool has_data);
// Initialize the PS2 driver
SH_STATUS sh_ps2_driver_init();
// Disable scanning
SH_STATUS sh_ps2_disable_scanning();
// Enable scanning
SH_STATUS sh_ps2_enable_scanning();
#endif

View File

@@ -0,0 +1,126 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_GDT_H
#define SH_LIB_GDT_H
#include "std/status.h"
#include "std/type.h"
#include "irq/tss.h"
// Long mode GDT part
// GDT entry 64 bits structure
#pragma pack(1)
typedef struct {
sh_uint16 limit_low;
sh_uint16 base_low;
sh_uint8 base_mid;
sh_uint8 access;
sh_uint8 flags_limit_high;
sh_uint8 base_high;
} sh_gdt_GDT_ENTRY_64;
#pragma pack()
// GDT entry 128 bits (special TSS) structure
#pragma pack(1)
typedef struct {
sh_uint16 limit_low;
sh_uint16 base_low;
sh_uint8 base_mid;
sh_uint8 access;
sh_uint8 flags_limit_high;
sh_uint8 base_high;
sh_uint32 base_upper;
sh_uint32 reserved;
} sh_gdt_GDT_ENTRY_128;
#pragma pack()
// GDTR structure
#pragma pack(1)
typedef struct {
sh_uint16 limit;
sh_uint64 base;
} sh_gdt_GDTR;
#pragma pack()
// GDT structure for bootstrap core
#pragma pack(1)
typedef struct {
sh_gdt_GDT_ENTRY_64 null;
sh_gdt_GDT_ENTRY_64 kernel_code;
sh_gdt_GDT_ENTRY_64 kernel_data;
sh_gdt_GDT_ENTRY_64 user_code;
sh_gdt_GDT_ENTRY_64 user_data;
sh_gdt_GDT_ENTRY_128 tss;
} sh_gdt_GDT;
#pragma pack()
// GDT structure for all APs
#pragma pack(1)
typedef struct {
sh_gdt_GDT_ENTRY_64 null;
sh_gdt_GDT_ENTRY_64 kernel_code;
sh_gdt_GDT_ENTRY_64 kernel_data;
sh_gdt_GDT_ENTRY_64 user_code;
sh_gdt_GDT_ENTRY_64 user_data;
sh_gdt_GDT_ENTRY_128 tss[256];
} sh_gdt_GDT_AP;
#pragma pack()
// Generate access byte
inline sh_uint8 sh_gdt_fill_access_byte(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type) {
return ((present?1:0)<<7)|((dpl&0x3)<<5)|((descriptor_type?1:0)<<4)|(segment_type&0xF);
}
// Generate flags byte (put all 4 bits in bit 0-3 of the returned byte)
inline sh_uint8 sh_gdt_fill_flags_byte(sh_bool g,sh_bool db,sh_bool l,sh_bool avl) {
return ((g?1:0)<<3)|((db?1:0)<<2)|((l?1:0)<<1)|((avl?1:0)<<0);
}
// Fill GDT entry 64 bits, expect flags as sh_gdt_fill_flags_byte would return it
sh_gdt_GDT_ENTRY_64 sh_gdt_fill_gdt_entry_64(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 flags);
// Fill GDT entry 128 bits, expect flags as sh_gdt_fill_flags_byte would return it
sh_gdt_GDT_ENTRY_128 sh_gdt_fill_gdt_entry_128(sh_uint32 limit,sh_uint64 base,sh_uint8 access,sh_uint8 flags);
// Fill GDT with provided TSS
SH_STATUS sh_gdt_fill_gdt(sh_tss_TSS *tss,sh_gdt_GDT *gdt);
// Fill APs common GDT with provided TSS array
SH_STATUS sh_gdt_fill_gdt_ap(sh_tss_TSS *tss,sh_uint64 tss_count,sh_gdt_GDT_AP *gdt);
// Generate GDTR for AP GDT
sh_gdt_GDTR sh_gdt_make_gdtr_ap(sh_gdt_GDT_AP *gdt);
// Fill and load GDTR
SH_STATUS sh_gdt_load_gdtr(sh_gdt_GDT *gdt);
// Reload registers
SH_STATUS sh_gdt_reload_registers();
// 16/32 bits mode GDT part
// GDT entry 32 bits structure
#pragma pack(1)
typedef struct {
sh_uint16 limit_low;
sh_uint16 base_low;
sh_uint8 base_middle;
sh_uint8 access;
sh_uint8 granularity;
sh_uint8 base_high;
} sh_gdt_GDT_ENTRY_32;
#pragma pack()
// GDT 32 bits structure
#pragma pack(1)
typedef struct {
sh_gdt_GDT_ENTRY_32 null;
sh_gdt_GDT_ENTRY_32 code_64;
sh_gdt_GDT_ENTRY_32 code;
sh_gdt_GDT_ENTRY_32 data;
} sh_gdt_GDT_32;
#pragma pack()
// Generate access byte
inline sh_uint8 sh_gdt_fill_access_byte_32(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type) {
sh_uint8 access=0;
access|=(present?1:0)<<7;
access|=(dpl&0x3)<<5;
access|=(descriptor_type?1:0)<<4;
access|=(segment_type&0xF);
return access;
}
// Generate granularity byte
inline sh_uint8 sh_gdt_fill_granularity_byte_32(sh_bool granularity,sh_bool db,sh_bool l,sh_bool avl) {
sh_uint8 g=0;
g|=(granularity?1:0)<<7;
g|=(db?1:0)<<6;
g|=(l?1:0)<<5;
g|=(avl?1:0)<<4;
return g;
}
// Fill GDT entry 32 bits, expect granularity as sh_gdt_fill_granularity_byte_32 would return it
sh_gdt_GDT_ENTRY_32 sh_gdt_fill_gdt_entry_32(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 granularity);
// Fill GDT 32 bits
SH_STATUS sh_gdt_fill_gdt_32(sh_gdt_GDT_32 *gdt_32);
#endif

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_GSI_H
#define SH_LIB_GSI_H
#include "std/stdlib.h"
#include "devs/apic/ioapic.h"
// GSI polarity enum
enum sh_gsi_POLARITY {
SH_GSI_POLARITY_NOT_SET=0,
SH_GSI_POLARITY_BUS_DEFAULT,
SH_GSI_POLARITY_ACTIVE_HIGH,
SH_GSI_POLARITY_ACTIVE_LOW
};
// GSI trigger mode enum
enum sh_gsi_TRIGGER_MODE {
SH_GSI_TRIGGER_MODE_NOT_SET=0,
SH_GSI_TRIGGER_MODE_BUS_DEFAULT,
SH_GSI_TRIGGER_MODE_EDGE,
SH_GSI_TRIGGER_MODE_LEVEL
};
// Interrupt source override (ISO) structure
typedef struct {
sh_uint32 gsi;
// must default to SH_FALSE
sh_bool valid;
// when ISOs array is initialized, this field must default to 0
sh_uint8 source_irq;
// these two fields are determined by the flags field in the MADT entry. Bus-default value are resolved when writing IOREDTBL
enum sh_gsi_POLARITY polarity;
enum sh_gsi_TRIGGER_MODE trigger_mode;
// when ISOs array is initialized, this field must default to 0
sh_uint8 bus;
} sh_gsi_ISO;
// Initialize a 256 elements array of sh_gsi_ISO structs
SH_STATUS sh_gsi_iso_array_init();
// Register an ISO, this function is supposed to be used during MADT parsing when encountering an ISO. It expect the field as they are provided into the MADT entry
SH_STATUS sh_gsi_iso_register(sh_uint8 bus,sh_uint8 source,sh_uint32 gsi,sh_uint16 flags);
// Return an ISO structure for the given interrupt
sh_gsi_ISO *sh_gsi_get_iso_by_irq(sh_uint8 irq);
// Return an ISO structure for the given GSI
sh_gsi_ISO *sh_gsi_get_iso_by_gsi(sh_uint32 gsi);
// These two functions provide a thread-safe and "interrupt-storm" safe way to get and set IOREDTBL entries
// Read the IOREDTBL entry associated with the provided GSI
SH_STATUS sh_gsi_get(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Set the provided GSI to the corresponding IOREDTBL entry, mask the IOOREDTBL entry and doesn't unmask it
SH_STATUS sh_gsi_set(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry);
// Set the provided IRQ to IOREDTBL entry, calculate the expected GSI using sh_gsi_get_iso_by_irq
SH_STATUS sh_gsi_irq_set(sh_uint8 irq,sh_ioapic_IOREDTBL_ENTRY *entry);
// Mask the IOREDTBL entry corresponding to the provided GSI
inline SH_STATUS sh_gsi_mask(sh_uint32 gsi) {
return sh_ioapic_mask_gsi(sh_ioapic_get_dev_by_gsi(gsi),gsi);
}
// Unmask the IOREDTBL entry corresponding to the provided GSI
inline SH_STATUS sh_gsi_unmask(sh_uint32 gsi) {
return sh_ioapic_unmask_gsi(sh_ioapic_get_dev_by_gsi(gsi),gsi);
}
// Mask the IOREDTBL entry corresponding to the provided IRQ
SH_STATUS sh_gsi_irq_mask(sh_uint8 irq);
// Unmask the IOREDTBL entry corresponding to the provided IRQ
SH_STATUS sh_gsi_irq_unmask(sh_uint8 irq);
// Load all legacy IRQ to IOREDTBL entries, intented to be called only one time
SH_STATUS sh_gsi_irq_switch();
#endif

View File

@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_IDT_H
#define SH_LIB_IDT_H
#include "std/status.h"
#include "std/type.h"
// IDT entry structure
#pragma pack(1)
typedef struct {
sh_uint16 offset_low;
sh_uint16 selector;
sh_uint8 ist;
sh_uint8 type_attr;
sh_uint16 offset_mid;
sh_uint32 offset_high;
sh_uint32 reserved;
} sh_idt_IDT_ENTRY;
#pragma pack()
// IDTR structure
#pragma pack(1)
typedef struct {
sh_uint16 limit;
sh_uint64 base;
} sh_idt_IDTR;
#pragma pack()
// Full IDT structure
#pragma pack(1)
typedef struct {
sh_idt_IDT_ENTRY entries[256];
} sh_idt_IDT;
#pragma pack()
// Generate type_attr byte
inline sh_uint8 sh_idt_fill_type_attr_byte(sh_bool present,sh_uint8 dpl,sh_uint8 type) {
return ((present?1:0)<<7)|((dpl&0x3)<<5)|(type&0x1F);
}
// Fill an IDT entry, expect type_attr as sh_idt_fill_type_attr_byte would return it
sh_idt_IDT_ENTRY sh_idt_fill_idt_entry(sh_uint64 offset,sh_uint16 selector,sh_uint8 ist,sh_uint8 type_attr);
// Fill the IDT
SH_STATUS sh_idt_fill_idt(sh_idt_IDT *idt);
// Fill and load IDTR
SH_STATUS sh_idt_load_idtr(sh_idt_IDT *idt);
#endif

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_IRQ_H
#define SH_LIB_IRQ_H
#include "std/stdlib.h"
// Interrupt frame structure
#pragma pack(1)
typedef struct {
sh_uint64 r11,r10,r9,r8,rdx,rcx,rax;
sh_uint64 vector;
sh_uint64 error_code;
sh_uint64 rip;
sh_uint64 cs;
sh_uint64 rflags;
} sh_irq_INTERRUPT_FRAME;
#pragma pack()
#define SH_IRQ_DIV_BY_ZERO_FAULT_STRING "Division by Zero #DE"
#define SH_IRQ_DEBUG_STRING "Debug #DB\nWarning: Usage of debugger in Shelter isn't supported and any #DB fault will result in a dead kernel."
#define SH_IRQ_PAGE_FAULT_STRING "Page fault #PF"
#define SH_IRQ_NMI_FAULT_STRING "Non maskable interrupt"
#define SH_IRQ_BREAKPOINT_STRING "Breakpoint #BP\nWarning: Usage of debugger in Shelter isn't supported but usage of #BP fault will not block the kernel."
#define SH_IRQ_OVERFLOW_STRING "Overflow #OF"
#define SH_IRQ_BOUND_RANGE_STRING "Bound range Exceedeed #BR"
#define SH_IRQ_INVALID_OPCODE_STRING "Invalid Opcode #UD"
#define SH_IRQ_DEVICE_NOT_AVAILABLE_STRING "Device Not Available #NM"
#define SH_IRQ_DOUBLE_FAULT_STRING "Double Fault #DF"
#define SH_IRQ_COPROCESSOR_SEGMENT_OVRERRUN_STRING "Coprocessor segment overrun"
#define SH_IRQ_INVALID_TSS_STRING "Invalid TSS #TS"
#define SH_IRQ_SEGMENT_NOT_PRESENT_STRING "Segment Not Present #NP"
#define SH_IRQ_STACK_SEGMENT_FAULT_STRING "Stack Segment Fault #SS"
#define SH_IRQ_GENERAL_PROTECTION_FAULT_STRING "General Protection Fault #GP"
#define SH_IRQ_X87_FLOATING_POINT_EXCEPTION_STRING "x87 Floating Point Exception #MF"
#define SH_IRQ_ALIGNMENT_CHECK_STRING "Alignment Check #AC"
#define SH_IRQ_MACHINE_CHECK_STRING "Machine Check #MC"
#define SH_IRQ_SIMD_FLOATING_POINT_EXCEPTION_STRING "SIMD Floating Point Exception #XM"
#define SH_IRQ_VIRTUALIZATION_EXCEPTION_STRING "Virtualization Exception #VE"
#define SH_IRQ_CONTROL_PROTECTION_EXCEPTION_STRING "Control Protection Exception #CP"
#define SH_IRQ_HYPERVISOR_INJECTION_EXCEPTION_STRING "Hypervisor Injection Exception #HV\nWarning: Shelter will never communicate with an hypervisor."
#define SH_IRQ_VMM_COMMUNICATION_EXCEPTION_STRING "VMM Communication Exception #VC\nWarning: Shelter will never communicate with an hypervisor."
#define SH_IRQ_SECURITY_EXCEPTION_STRING "Security Exception #SX\nWarning: Shelter will never communicate with an hypervisor."
typedef void (*sh_irq_HANDLER_PTR)();
// Start TSC calibration
void sh_irq_start_tsc();
// Return TSC delta mesured between two PIC interrupts
sh_uint64 sh_irq_get_tsc_delta();
// Set timer state of this CPU to SH_TRUE
void sh_irq_start_timer();
// Get timer state of this CPU
sh_bool sh_irq_get_timer_state();
// Set the irq_managed_by_ioapic to SH_TRUE
SH_STATUS sh_irq_switch_irq_management();
// Register a legacy IRQ handler, unmask the corresponding GSI
SH_STATUS sh_irq_legacy_register_handler(sh_uint8 legacy_irq,sh_irq_HANDLER_PTR handler);
// Present interrupt frame if it's a fault
void sh_irq_present_frame(sh_irq_INTERRUPT_FRAME *frame);
// Dispatch interrupts
void sh_irq_dispatch(sh_irq_INTERRUPT_FRAME *frame);
#endif

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TSS_H
#define SH_LIB_TSS_H
#include "std/status.h"
#include "std/type.h"
#include "std/malloc.h"
#include "std/mem.h"
// TSS structure
#pragma pack(1)
typedef struct {
sh_uint32 reserved0;
sh_uint64 rsp0;
sh_uint64 rsp1;
sh_uint64 rsp2;
sh_uint64 reserved1;
sh_uint64 ist1;
sh_uint64 ist2;
sh_uint64 ist3;
sh_uint64 ist4;
sh_uint64 ist5;
sh_uint64 ist6;
sh_uint64 ist7;
sh_uint64 reserved2;
sh_uint16 reserved3;
sh_uint16 iomap_base;
} sh_tss_TSS;
#pragma pack()
// TR structure
#pragma pack(1)
typedef struct {
sh_uint16 limit;
sh_uint64 base;
} sh_tss_TR;
#pragma pack()
// Fill TSS structure for any CPU core and allocate stacks
SH_STATUS sh_tss_fill_tss(sh_tss_TSS *tss);
// Fill and load TR
SH_STATUS sh_tss_load_tr(sh_tss_TSS *tss);
#endif

View File

@@ -5,7 +5,22 @@
#include "std/status.h"
#include "memory/page.h"
#include "memory/vmem_layout.h"
#include "devs/devs.h"
#define SH_CONF_BOOT_CONFIG_VA SH_VMEM_LAYOUT_BOOT_CONFIG_VA
// Framebuffer configuration
typedef struct __attribute__((aligned(8))) {
sh_bool fb_present;
sh_page_VIRTUAL_ADDRESS fb_pa;
sh_uint32 white_pixel_value;
sh_uint32 gray_pixel_value;
sh_uint64 size_in_bytes;
sh_uint32 fb_height;
sh_uint32 fb_width;
sh_uint16 text_x;
sh_uint16 text_y;
sh_uint16 text_width;
sh_uint16 text_height;
} sh_conf_FB_CONFIG;
// Boot config structure.
typedef struct __attribute__((aligned(8))) {
sh_uint8 sig_start[8];
@@ -18,8 +33,14 @@ typedef struct __attribute__((aligned(8))) {
sh_bool log_disable_serial_port;
sh_bool disable_serial_port;
sh_uint16 log_ring_size;
sh_uint64 acpi_rsdp;
sh_uint8 acpi_ver;
sh_uint16 kbd_events_queue_capacity;
sh_conf_FB_CONFIG fb_config;
sh_uint8 sig_end[8];
} sh_conf_BOOT_CONFIG;
// Check and create boot config structure.
SH_STATUS sh_conf_get_boot_config(sh_conf_BOOT_CONFIG **config);
// Parse a configuration DevS query
SH_STATUS sh_conf_devs_query(char *sub_path,sh_devs_RESULT *result);
#endif

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_EFIFB_H
#define SH_LIB_EFIFB_H
#include "std/stdlib.h"
#include "kernel/conf.h"
// Initialize the EFI FB subsystem
SH_STATUS sh_efifb_init_fb(sh_conf_FB_CONFIG *fb_conf,sh_page_PAGE_TABLE_POOL *ptp);
// Initialize the boot progress bar
SH_STATUS sh_efifb_init_bar();
// Set the progress bar to a certain percentage
SH_STATUS sh_efifb_set_bar(sh_uint8 percent);
#endif

View File

@@ -12,6 +12,7 @@ typedef sh_uint8 sh_log_OUTPUT_TYPE;
#define SH_LOG_CRITICAL ((sh_log_OUTPUT_TYPE)4)
#define SH_LOG_FATAL ((sh_log_OUTPUT_TYPE)5)
#define SH_LOG_TEST ((sh_log_OUTPUT_TYPE)6)
#define SH_LOG_FAULT ((sh_log_OUTPUT_TYPE)7)
typedef sh_uint16 sh_log_OUTPUT_SOURCE;
#define SH_LOG_SOURCE_MAIN ((sh_log_OUTPUT_SOURCE)0)
#define SH_LOG_SOURCE_CONF ((sh_log_OUTPUT_SOURCE)1)
@@ -22,6 +23,11 @@ typedef sh_uint16 sh_log_OUTPUT_SOURCE;
#define SH_LOG_SOURCE_PBA ((sh_log_OUTPUT_SOURCE)6)
#define SH_LOG_SOURCE_HEAP ((sh_log_OUTPUT_SOURCE)7)
#define SH_LOG_SOURCE_STD ((sh_log_OUTPUT_SOURCE)8)
#define SH_LOG_SOURCE_MEMS ((sh_log_OUTPUT_SOURCE)9)
#define SH_LOG_SOURCE_CPUF ((sh_log_OUTPUT_SOURCE)10)
#define SH_LOG_SOURCE_ACPI ((sh_log_OUTPUT_SOURCE)11)
#define SH_LOG_SOURCE_TSC ((sh_log_OUTPUT_SOURCE)12)
#define SH_LOG_SOURCE_SMP ((sh_log_OUTPUT_SOURCE)13)
typedef struct {
sh_log_OUTPUT_TYPE output_type;
sh_log_OUTPUT_SOURCE output_source;
@@ -30,11 +36,11 @@ typedef struct {
} sh_log_OUTPUT_PAYLOAD;
// Return SH_TRUE if provided output type is valid.
static inline sh_bool sh_log_output_type_valid(sh_log_OUTPUT_TYPE t) {
return t<=SH_LOG_TEST;
return t<=SH_LOG_FAULT;
}
// Return SH_TRUE if provided source type is valid.
static inline sh_bool sh_log_output_source_valid(sh_log_OUTPUT_SOURCE s) {
return s<=SH_LOG_SOURCE_STD;
return s<=SH_LOG_SOURCE_SMP;
}
// Load serial logging setting
void sh_log_load_serial_setting(sh_bool is_disabled);
@@ -46,6 +52,8 @@ void sh_log_load_logging_ring_size(sh_uint16 pages_count);
sh_uint32 sh_log_get_logging_ring_size();
// Return total bytes written to the ring buffer
sh_uint64 sh_log_get_total_bytes_written();
// Disable global logging ring, should only be used after SMP is enabled
void sh_log_disable_global_logging_ring();
// Log a byte
void sh_log_byte(sh_uint8 byte);
// Log a string
@@ -103,6 +111,8 @@ SH_STATUS sh_log_error(const char* str,sh_log_OUTPUT_SOURCE source);
SH_STATUS sh_log_critical(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fatal channel, from provided source.
SH_STATUS sh_log_fatal(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fault channel, from provided source.
SH_STATUS sh_log_fault(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to test channel. Doesn't include the new line caracter.
SH_STATUS sh_log_ltest(const char* str);
// Print a string to debug channel, from provided source. Doesn't include the new line caracter.
@@ -117,6 +127,8 @@ SH_STATUS sh_log_lerror(const char* str,sh_log_OUTPUT_SOURCE source);
SH_STATUS sh_log_lcritical(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fatal channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lfatal(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fault channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lfault(const char* str,sh_log_OUTPUT_SOURCE source);
// The following functions format the output before logging it. The syntax is as follow:
// - %s : char*
// - %d : double
@@ -141,6 +153,8 @@ SH_STATUS sh_log_ferror(const sh_log_OUTPUT_SOURCE source,const char* format,...
SH_STATUS sh_log_fcritical(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to fatal channel, from provided source. Format it before hand
SH_STATUS sh_log_ffatal(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to fault channel, from provided source. Format it before hand
SH_STATUS sh_log_ffault(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print every information about memory statictics. Require log level to be 1 or 0
SH_STATUS sh_log_mem_stats(sh_log_OUTPUT_SOURCE source);
#endif

View File

@@ -4,4 +4,5 @@
#include "kernel/tests/test_radix.h"
#include "kernel/tests/test_pez.h"
#include "kernel/tests/test_malloc.h"
#include "kernel/tests/test_queues.h"
#include "kernel/tests/test_utils.h"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_QUEUES_H
#define SH_LIB_TEST_QUEUES_H
#include "std/stdlib.h"
#include "cpu/tsc.h"
// Test and benchmark queues from standard library
SH_STATUS sh_test_benchmark_queues();
#endif

View File

@@ -5,7 +5,7 @@
#include "std/status.h"
#include "cpu/tsc.h"
// Compute and print time stats based on provided list of TSC values.
SH_STATUS sh_test_compute_print_stats(char* benchname,sh_tsc_TSC_VALUE *tsc_value_array,sh_uint64 array_size);
SH_STATUS sh_test_compute_print_stats(char* benchname,sh_tsc_TSC_VALUE *tsc_value_array,sh_uint64 array_size,sh_bool use_std_print);
// Return pointer to TSC values buffer
sh_tsc_TSC_VALUE* sh_test_get_tsc_values_buffer_ptr();
// Load the number of iterations for benchmarks.

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_MEMORY_H
#define SH_LIB_MEMORY_H
#include "std/type.h"
#include "std/status.h"
#include "kernel/conf.h"
#include "memory/page.h"
#include "memory/slab.h"
#include "memory/heap.h"
// Memory subsystem services structure
typedef struct {
sh_page_PAGE_TABLE_POOL kernel_ptp;
sh_slab_reg_phys_SLAB_ALLOCATOR slab_reg_phys;
sh_slab_reg_virt_SLAB_ALLOCATOR slab_reg_virt;
struct sh_slab_radix_node_SLAB_ALLOCATOR slab_radix_node;
sh_pez_PHYSICAL_PLANE physical_plane;
sh_pez_VIRTUAL_PLANE virtual_plane_kernel_heap;
sh_heap_KERNEL_HEAP kernel_heap;
} sh_memory_MEMORY_SERVICES;
// Initialize memory subsystem
SH_STATUS sh_memory_init_subsystem(sh_conf_BOOT_CONFIG *boot_config,sh_memory_MEMORY_SERVICES *services);
// Identity map a physical memory area
SH_STATUS sh_memory_identity_map(sh_page_PHYSICAL_ADDRESS phys_start,sh_uint64 page_count,sh_uint64 flags);
// Parse a memory DevS query
SH_STATUS sh_memory_devs_query(char *sub_path,sh_devs_RESULT *result);
#endif

View File

@@ -156,4 +156,6 @@ SH_STATUS sh_page_analyse_memory_map(sh_page_PAGE_TABLE_POOL *ptp);
sh_page_VIRTUAL_ADDRESS sh_page_get_physical_bitmap_ptr();
// Get physical memory statistics
SH_STATUS sh_page_get_memory_stats(sh_page_MEM_STATS *mem_stats);
// Return total installed memory in bytes
sh_uint64 sh_page_get_installed_memory_bytes();
#endif

View File

@@ -15,4 +15,6 @@ typedef struct {
SH_STATUS sh_ring_write_byte(sh_ring_RING_BUFFER_HEADER *ring_buffer,sh_uint8 byte);
// Write a null terminated string into the provided ring buffer
SH_STATUS sh_ring_write_string(sh_ring_RING_BUFFER_HEADER *ring_buffer,char *string);
// Read bytes_count from the provided ring buffer, and put it into output. Return SH_STATUS_TOO_MUCH_DATA if bytes_count>buf.buffer_size_bytes, setting the entire buffer to 0x00
SH_STATUS sh_ring_read_bytes(sh_ring_RING_BUFFER_HEADER *ring_buffer,sh_uint32 bytes_count,void *output);
#endif

View File

@@ -79,7 +79,7 @@
#define SH_VMEM_LAYOUT_SLAB_REG_VIRT_VA 0xFFFFFF800C600000ULL
// The total size for the slabs for virtual regions objects
#define SH_VMEM_LAYOUT_SLAB_REG_VIRT_SIZE_BYTES (1ULL<<29)*12ULL
// The alignement for SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA
// The alignment for SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA
#define SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN (32ULL*4096ULL)
// The base for the PBA for the slabs for radix nodes
#define SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA ((SH_VMEM_LAYOUT_SLAB_REG_VIRT_VA+SH_VMEM_LAYOUT_SLAB_REG_VIRT_SIZE_BYTES+SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN)/SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN)*SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN

View File

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PRINT_H
#define SH_LIB_PRINT_H
#include "std/status.h"
#include "std/type.h"
#include "kernel/log.h"
#include "kernel/conf.h"
#include "cpu/ap.h"
#define SH_DEBUG SH_LOG_DEBUG
#define SH_LOG SH_LOG_LOG
#define SH_WARNING SH_LOG_WARNING
#define SH_ERROR SH_LOG_ERROR
#define SH_CRITICAL SH_LOG_CRITICAL
#define SH_FATAL SH_LOG_FATAL
#define SH_TEST SH_LOG_TEST
#define SH_FAULT SH_LOG_FAULT
// Setup rings buffer for APs
SH_STATUS sh_print_setup_ring_buffers_per_ap(sh_conf_BOOT_CONFIG *boot_config);
// Print string
SH_STATUS sh_print(sh_log_OUTPUT_TYPE output_type,char* text);
// Print string, format it before hand
SH_STATUS sh_printf(sh_log_OUTPUT_TYPE output_type,char* format,...);
// Priority print string, reserved to IRQ handler
SH_STATUS sh_iprint(sh_log_OUTPUT_TYPE output_type,char* text);
// Priority print string, reserved to IRQ handler, format it before hand
SH_STATUS sh_iprintf(sh_log_OUTPUT_TYPE output_type,char* text,...);
// Format a string and put it into the provided buffer
SH_STATUS sh_sprintf(char* output_string,sh_uint64 output_len,char* format,...);
#endif

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_QUEUE_H
#define SH_LIB_QUEUE_H
#include "std/type.h"
#include "std/status.h"
#include "devs/input/event.h"
// Keyboard events queue structure
typedef struct {
sh_kbd_EVENT *buffer;
sh_uint32 capacity;
sh_uint32 write_index;
} sh_queue_KBD_EVENT;
// Initialize an event queue
SH_STATUS sh_queue_event_init(sh_queue_KBD_EVENT *q,sh_uint32 capacity);
// Push a keyboard event to the provided queue
SH_STATUS sh_queue_event_push(sh_queue_KBD_EVENT *q,sh_kbd_EVENT ev);
// Destroy the provided keyboard event queue
SH_STATUS sh_queue_event_destroy(sh_queue_KBD_EVENT *q);
#endif

View File

@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_SMP_H
#define SH_LIB_SMP_H
#include "std/type.h"
#include "std/status.h"
#include "cpu/ap.h"
#include "cpu/serial.h"
#include "cpu/asm.h"
// Write GS base register
inline void sh_smp_write_gs_base(sh_uint64 value) {
sh_uint32 low=(sh_uint32)(value);
sh_uint32 high=(sh_uint32)(value>>32);
__asm__ volatile ("wrmsr"::"c"(0xC0000101),"a"(low),"d"(high));
}
// Return CPU struct of this CPU
inline sh_ap_CPU_STRUCT *sh_smp_gs_base() {
sh_uint32 low,high;
__asm__ volatile ("rdmsr":"=a"(low),"=d"(high):"c"(0xC0000101));
return (sh_ap_CPU_STRUCT*)(((sh_uint64)high<<32)|low);
}
// Lock structure, unlocked lock have lapic_id to SH_UINT32_MAX
typedef struct {
volatile sh_uint32 spinlock;
sh_uint32 lapic_id;
} sh_SPIN_LOCK;
// Create an unlocked lock, intended for creation of global variables.
#define SH_LOCK() {.spinlock=0,.lapic_id=SH_UINT32_MAX}
// Create an unlocked lock, intended for creation of local variables
#define SH_LOCK_LOCAL() ((sh_SPIN_LOCK){.spinlock=0,.lapic_id=SH_UINT32_MAX})
// Lock a spinlock
inline void sh_spin_lock(sh_SPIN_LOCK *lock) {
while (__atomic_test_and_set(&lock->spinlock,__ATOMIC_ACQUIRE)) {
while (lock->spinlock) {
__asm__ volatile ("pause");
}
}
if (sh_smp_gs_base()==SH_NULLPTR) {
sh_serial_send_byte('!');
while (SH_TRUE) {}
}
lock->lapic_id=sh_smp_gs_base()->lapic_id;
}
// Unlock a spinlock
inline void sh_spin_unlock(sh_SPIN_LOCK *lock) {
lock->lapic_id=SH_UINT32_MAX;
__atomic_clear(&lock->spinlock,__ATOMIC_RELEASE);
}
// Try to lock a spinlock, doesn't wait for it to be unlocked, return SH_TRUE if lock is now owned by us
inline sh_bool sh_spin_trylock(sh_SPIN_LOCK *lock) {
if (__atomic_test_and_set(&lock->spinlock,__ATOMIC_ACQUIRE)) return SH_FALSE;
lock->lapic_id=sh_smp_gs_base()->lapic_id;
return SH_TRUE;
}
// Return which CPU is locking the lock
inline sh_uint32 sh_spin_wholock(sh_SPIN_LOCK *lock) {
return lock->lapic_id;
}
// Set CPU count (aka max_cpu_id+1)
void sh_smp_set_cpu_count(sh_int16 cpu_count);
// Return CPU count, return -1 if this value isn't initialized
sh_int16 sh_smp_get_cpu_count();
// Memory barrier
inline void sh_mb() {
sh_asm_mfence();
}
// Read memory barrier
inline void sh_rmb() {
sh_asm_lfence();
}
// Write memory barrier
inline void sh_wmb() {
sh_asm_sfence();
}
#endif

View File

@@ -36,6 +36,17 @@ typedef sh_int64 SH_STATUS;
#define SH_STATUS_PAGE_ALREADY_FREE 25LL
#define SH_STATUS_TOO_MUCH_DATA 26LL
#define SH_STATUS_HEAP_NOT_INITIALIZED 27LL
#define SH_STATUS_MEMORY_SUBSYSTEM_NOT_INITIALIZED 28LL
#define SH_STATUS_INVALID_CHECKSUM 29LL
#define SH_STATUS_BAD_SIZE 30LL
#define SH_STATUS_INVALID_STATE 31LL
#define SH_STATUS_DEVS_NOT_INITIALIZED 32LL
#define SH_STATUS_UNAVAILABLE 33LL
#define SH_STATUS_ALREADY_INITIALIZED 34LL
#define SH_STATUS_AP_NO_LAPIC 35LL
#define SH_STATUS_ISO_UNKNOW_BUS 36LL
#define SH_STATUS_INVALID_HANDLE 37LL
#define SH_STATUS_DEVICE_NOT_PRESENT 38LL
// Return SH_TRUE if provided status is an error
static inline sh_bool sh_status_error(SH_STATUS s) {
return s>=SH_STATUS_INVALID_PARAMETER;

View File

@@ -1,7 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
// This header is just here to include all standard header
// If you are looking for printing functions, take a look at kernel/log.h
// If you are looking for non-thread safe/more direct printing functions, take a look at kernel/log.h
#include "std/mem.h"
#include "std/malloc.h"
#include "std/status.h"
#include "std/print.h"
#include "std/smp.h"
#include "std/type.h"
#include "std/status.h"
#include "std/string.h"
#include "std/queue.h"

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_STRING_H
#define SH_LIB_STRING_H
#include "std/type.h"
// Return the length of a null terminated string
sh_uint64 sh_string_len(char *str);
// Compare two null terminated string, both strings must not exceed the provided length. Return SH_TRUE if both strings are equals on the provided length
sh_bool sh_string_compare(char *str1,char* str2,sh_uint64 length);
// Return the index of the first occurence of the provided character into the string, return SH_UINT64_MAX if not found or error
sh_uint64 sh_string_find_char(char *str,char character);
// Return the index of the start of the first occurence of the provided substring into the string, return SH_UINT64_MAX if not found or error
sh_uint64 sh_string_find(char *str,char *substr);
// Copy a substring from a string to another string, and return the pointer to the new string
char *sh_string_substring(char *source_str,sh_uint64 start_index,sh_uint64 length,char *output);
// Convert a string to a sh_uint64
sh_uint64 sh_string_to_uint64(char *str);
#endif