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

151
shelter/lib/src/cpu/ap.c Normal file
View File

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/ap.h"
#include "devs/apic/lapic.h"
#include "devs/input/kbd.h"
#include "memory/memory.h"
#include "kernel/log.h"
#include "std/stdlib.h"
sh_ap_AP_BOOTSTRAP *ap_bootstrap_struct=(sh_ap_AP_BOOTSTRAP*)SH_AP_BOOTSTRAP_PA;
sh_uint8 *is_ap_started=SH_NULLPTR;
static sh_ap_CPU_STRUCT bsp_cpu_struct;
static sh_ap_PER_CPU bsp_per_cpu;
SH_STATUS sh_ap_load_gdt_32() {
if (sh_page_is_allocated((sh_uint8*)sh_page_get_physical_bitmap_ptr(),SH_AP_GDT_32_PA)) return SH_STATUS_OUT_OF_MEMORY;
SH_STATUS status=sh_memory_identity_map(SH_AP_GDT_32_PA,1,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status)) return status;
sh_gdt_GDT_32 *gdt_32=(sh_gdt_GDT_32*)(sh_uint8*)SH_AP_GDT_32_PA;
status=sh_gdt_fill_gdt_32(gdt_32);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
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) {
if (lapic_dev_array==SH_NULLPTR || expected_lapic_found==0 || max_lapic_id>255) return SH_STATUS_INVALID_PARAMETER;
SH_STATUS status=sh_memory_identity_map(SH_AP_BOOTSTRAP_PA,1,SH_PAGE_PRESENT | SH_PAGE_RW | SH_PAGE_NX);
if (sh_status_error(status)) return status;
sh_ap_AP_BOOTSTRAP *ap_bootstrap=(sh_ap_AP_BOOTSTRAP*)(sh_uint8*)SH_AP_BOOTSTRAP_PA;
ap_bootstrap->c_entry_point_va=(sh_uint64)&sh_ap_entry_point;
ap_bootstrap->page_table_pa=boot_config->page_table_pool_pa;
sh_int16 current_lapic_id=sh_lapic_get_current_core();
if (current_lapic_id<0) return SH_STATUS_INVALID_STATE;
sh_lapic_DEVICE *lapic_device_default=SH_NULLPTR;
sh_uint64 lapic_found=0;
for (sh_iter64 i=0;i<max_lapic_id+1;i++) {
sh_lapic_DEVICE *lapic_dev=lapic_dev_array[i];
if (lapic_dev==SH_NULLPTR) continue;
if (lapic_device_default==SH_NULLPTR) lapic_device_default=lapic_dev;
lapic_found++;
}
if (lapic_found!=expected_lapic_found) return SH_STATUS_RESCAN_NEEDED;
ap_bootstrap->lapic_base_pa=(sh_uint64)(sh_uint8*)lapic_device_default->base;
sh_uint8 *cpu_struct_base_ptr=sh_malloc(sizeof(sh_ap_CPU_STRUCT)*(max_lapic_id+1));
if (!cpu_struct_base_ptr) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_ap_CPU_STRUCT *cpu_struct_base=(sh_ap_CPU_STRUCT*)cpu_struct_base_ptr;
ap_bootstrap->cpu_struct_base_area=(sh_uint64)cpu_struct_base_ptr;
sh_uint8 *tss_array_ptr=sh_malloc(sizeof(sh_tss_TSS)*(lapic_found-1));
sh_tss_TSS *tss_array=(sh_tss_TSS*)tss_array_ptr;
sh_uint64 cpu_count=0;
sh_uint64 cpu_index=1;
for (sh_iter64 i=0;i<max_lapic_id+1;i++) {
sh_lapic_DEVICE *lapic_dev=lapic_dev_array[i];
if (lapic_dev==SH_NULLPTR) continue;
if (lapic_dev->apic_id==current_lapic_id) continue;
sh_uint8 *c_entry_point_stack=sh_malloc(64*SH_PAGE_SIZE);
if (!c_entry_point_stack) return SH_STATUS_ERROR_NULLPTR_RETURNED;
cpu_struct_base[i].c_entry_point_stack_top_va=(sh_uint64)c_entry_point_stack+64*SH_PAGE_SIZE;
cpu_struct_base[i].lapic_id=lapic_dev->apic_id;
status=sh_tss_fill_tss(&tss_array[cpu_count]);
if (sh_status_error(status)) return status;
cpu_struct_base[i].tss_selector=(sh_uint16)(0x28+cpu_count*sizeof(sh_gdt_GDT_ENTRY_128));
cpu_struct_base[i].per_cpu=(sh_ap_PER_CPU*)sh_malloc(sizeof(sh_ap_PER_CPU));
if (!cpu_struct_base[i].per_cpu) return SH_STATUS_ERROR_NULLPTR_RETURNED;
cpu_struct_base[i].per_cpu->cpu_id=cpu_index;
cpu_struct_base[i].per_cpu->bytes_outputed=0;
cpu_struct_base[i].per_cpu->timer_state=SH_FALSE;
cpu_struct_base[i].per_cpu->temp_buffer=sh_malloc(256);
if (!cpu_struct_base[i].per_cpu->temp_buffer) return SH_STATUS_ERROR_NULLPTR_RETURNED;
cpu_struct_base[i].per_cpu->temp_buffer_size=256;
cpu_count++;
cpu_index++;
}
sh_uint8 *global_gdt_ptr=sh_malloc(sizeof(sh_gdt_GDT_AP));
sh_gdt_GDT_AP *global_gdt=(sh_gdt_GDT_AP*)global_gdt_ptr;
status=sh_gdt_fill_gdt_ap(tss_array,cpu_count,global_gdt);
if (sh_status_error(status)) return status;
ap_bootstrap->shared_gdt_64_va=(sh_uint64)global_gdt;
ap_bootstrap->gdt_64_gdtr=sh_gdt_make_gdtr_ap(global_gdt);
ap_bootstrap->idt=idt;
sh_smp_set_cpu_count((sh_int16)cpu_index);
is_ap_started=sh_malloc(cpu_index);
if (!is_ap_started) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8(is_ap_started,SH_AP_STATE_PENDING,cpu_index);
return SH_STATUS_SUCCESS;
}
void sh_ap_entry_point() {
sh_lapic_DEVICE *lapic_dev=sh_lapic_get_dev_apic_id(sh_smp_gs_base()->lapic_id);
if (!lapic_dev) {
sh_print(SH_FATAL,"Couldn't obtain LAPIC of this AP.");
is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_NO_LAPIC;
while (SH_TRUE) {};
}
SH_STATUS status=sh_lapic_init_dev(0xFF,lapic_dev);
if (sh_status_error(status)) {
sh_print(SH_FATAL,"Couldn't initialize LAPIC.");
is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_NO_LAPIC;
while (SH_TRUE) {};
}
sh_idt_load_idtr(ap_bootstrap_struct->idt);
sh_asm_sti();
sh_printf(SH_LOG,"Thread with lapic_id=%4u and cpu_id=%8u successfully reached C entry point.\n",sh_smp_gs_base()->lapic_id,sh_smp_gs_base()->per_cpu->cpu_id);
sh_mb();
is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_OK;
sh_mb();
while (SH_TRUE) {};
}
SH_STATUS sh_ap_start_ap_boot_procedure(sh_conf_BOOT_CONFIG *boot_config) {
SH_STATUS status=sh_memory_identity_map(SH_AP_AP_TRAMPOLINE,1,SH_PAGE_RW | SH_PAGE_PRESENT);
if (sh_status_error(status)) return status;
sh_mem_copy((sh_uint8*)SH_AP_AP_TRAMPOLINE,(sh_uint8*)SH_AP_TRAMPOLINE_PAYLOAD,4096);
sh_lapic_DEVICE *lapic_dev=sh_lapic_get_dev_apic_id((sh_uint64)sh_lapic_get_current_core());
if (lapic_dev==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
bsp_cpu_struct.c_entry_point_stack_top_va=0;
bsp_cpu_struct.lapic_id=(sh_uint32)sh_lapic_get_current_core();
bsp_cpu_struct.tss_selector=0;
bsp_per_cpu.cpu_id=0;
bsp_per_cpu.bytes_outputed=0;
bsp_per_cpu.timer_state=SH_FALSE;
bsp_per_cpu.temp_buffer=sh_malloc(256);
if (!bsp_per_cpu.temp_buffer) return SH_STATUS_ERROR_NULLPTR_RETURNED;
bsp_per_cpu.temp_buffer_size=256;
bsp_cpu_struct.per_cpu=(&bsp_per_cpu);
sh_smp_write_gs_base((sh_uint64)&bsp_cpu_struct);
is_ap_started[sh_smp_gs_base()->per_cpu->cpu_id]=SH_AP_STATE_OK;
sh_log_debug("Trying sending INIT IPI...",SH_LOG_SOURCE_SMP);
status=sh_lapic_send_ipi(lapic_dev,SH_LAPIC_IPI_TYPE_INIT,SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF,SH_LAPIC_IPI_NO_DESTINATION,0);
if (sh_status_error(status)) return status;
sh_log_debug("Sent INIT IPI. Waiting 10 ms.",SH_LOG_SOURCE_SMP);
status=sh_lapic_timer_one_shot_us(lapic_dev,10000);
if (sh_status_error(status)) return status;
sh_log_debug("Trying sending first SIPI...",SH_LOG_SOURCE_SMP);
status=sh_print_setup_ring_buffers_per_ap(boot_config);
if (sh_status_error(status)) return status;
status=sh_lapic_send_ipi(lapic_dev,SH_LAPIC_IPI_TYPE_STARTUP,SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF,SH_LAPIC_IPI_NO_DESTINATION,SH_AP_AP_TRAMPOLINE);
if (sh_status_error(status)) return status;
sh_log_disable_global_logging_ring();
sh_print(SH_DEBUG,"Sent first SIPI.\n");
while (SH_TRUE) {
sh_mb();
sh_int16 cpu_good=0;
for (sh_int16 i=0;i<sh_smp_get_cpu_count();i++) {
if (is_ap_started[i]==SH_AP_STATE_PENDING) continue;
if (is_ap_started[i]==SH_AP_STATE_NO_LAPIC) {
sh_printf(SH_CRITICAL,"AP %8u failed to set up his LAPIC.\n",i);
return SH_STATUS_AP_NO_LAPIC;
} else if (is_ap_started[i]==SH_AP_STATE_OK) {
cpu_good++;
}
}
if (cpu_good==sh_smp_get_cpu_count()) {
return SH_STATUS_SUCCESS;
}
}
}

View File

@@ -0,0 +1,112 @@
; SPDX-License-Identifier: MPL-2.0
bits 16
org 0x7000
start:
cli
lgdt [gdtr]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x10:second_stage_entry
gdt_phys_addr equ 0x8000 ; the bsp will always place the 32 bits gdt at 0x8000
gdtr:
dw 32 - 1 ; the size of three segment less 1
dd gdt_phys_addr
bits 32
second_stage_entry:
mov ax, 0x18
mov ds, ax
mov es, ax
mov ss, ax
; read lapic base
mov eax, [0x9000]
; get lapic id and keep it safe
mov esi, [eax + 0x20]
shr esi, 24
; enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; load cr3
mov eax, [0x9010]
mov cr3, eax
; enable LME
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
or eax, 1 << 11 ; enable this fuckingly useless kill switch that is the NXE bit, this should be enabled by default
wrmsr
; enable pagging
mov eax, cr0
or eax, (1 << 31)
mov cr0, eax
jmp 0x08:third_stage_entry
bits 64
cpu_struct_size_bytes equ 22
far_jump:
dq 0x08
dq fourth_stage_entry
third_stage_entry:
mov rax, [0x9018] ; base pointer
mov rdi, cpu_struct_size_bytes
mov rsi, rsi
; rdi = lapic_id * struct_size
imul rdi, rsi
; rax = base + offset
add rax, rdi
; test if cpu struct is the expected one
mov edi, [rax + 0x8]
cmp rsi, rdi
jne incorrect_lapic_id
; load stack
mov rcx, [rax]
mov rsp, rcx
and rsp, -16
sub rsp, 8
; load gdt 64
mov rcx, 0x9028
lgdt [rcx]
mov cx, 0x10
mov ds, cx
mov es, cx
mov ss, cx
xor cx, cx
mov fs, cx
mov gs, cx
; reload cs
push 0x08
lea rcx, [rel fourth_stage_entry]
push rcx
retfq
incorrect_lapic_id:
hlt;
fourth_stage_entry:
; load ltr
mov cx, [rax + 12]
ltr cx
; load gs
mov rdx, rax
shr rdx, 32
mov ecx, 0xC0000101
wrmsr
; jump to C
mov rcx, [0x9008]
jmp rcx
hlt

45
shelter/lib/src/cpu/pic.c Normal file
View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/pic.h"
#include "cpu/asm.h"
void sh_pic_remap() {
sh_asm_outb(SH_PIC1_CMD,0x11);
sh_asm_outb(SH_PIC2_CMD,0x11);
sh_asm_outb(SH_PIC1_DATA,0x20);
sh_asm_outb(SH_PIC2_DATA,0x28);
sh_asm_outb(SH_PIC1_DATA,0x04);
sh_asm_outb(SH_PIC2_DATA,0x02);
sh_asm_outb(SH_PIC1_DATA,0x01);
sh_asm_outb(SH_PIC2_DATA,0x01);
sh_asm_outb(SH_PIC1_DATA,0xFE);
sh_asm_outb(SH_PIC2_DATA,0xFF);
}
void sh_pic_unmask(sh_uint8 irq) {
sh_uint16 port;
sh_uint8 value;
if (irq<8) {
port=SH_PIC1_DATA;
} else {
port=SH_PIC2_DATA;
irq-=8;
}
value=sh_asm_inb(port);
value&= (sh_uint8)~((sh_uint8)(1u<<irq));
sh_asm_outb(port,value);
}
void sh_pic_mask(sh_uint8 irq) {
sh_uint16 port;
sh_uint8 value;
if (irq<8) {
port=SH_PIC1_DATA;
} else {
port=SH_PIC2_DATA;
irq-=8;
}
value=sh_asm_inb(port);
value|=(sh_uint8)(1u<<irq);
sh_asm_outb(port,value);
}
void sh_pic_send_eoi(sh_uint8 irq) {
if (irq>=8) sh_asm_outb(SH_PIC2_CMD,0x20);
sh_asm_outb(SH_PIC1_CMD,0x20);
}

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/pit.h"
#include "cpu/asm.h"
void sh_pit_set_frequency(sh_uint64 hz) {
sh_uint16 divisor=(sh_uint16)((sh_uint64)1193182/hz);
sh_asm_outb(0x43,0x36);
sh_asm_outb(0x40,(sh_uint8)(divisor&0xFF));
sh_asm_outb(0x40,(sh_uint8)(divisor>>8));
}

View File

@@ -1,6 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/tsc.h"
#include "cpu/pit.h"
#include "cpu/pic.h"
#include "irq/irq.h"
#include "kernel/log.h"
sh_tsc_TSC_VALUE kernel_start_tsc=0;
sh_uint64 internal_cpu_freq=0;
sh_bool is_cpu_freq_provided=SH_FALSE;
SH_STATUS sh_tsc_init_tsc() {
kernel_start_tsc=sh_tsc_read_tsc();
return SH_STATUS_SUCCESS;
@@ -11,3 +17,82 @@ sh_tsc_TSC_VALUE sh_tsc_get_kernel_init_tsc() {
sh_tsc_TSC_VALUE sh_tsc_get_kernel_current_tsc() {
return sh_tsc_read_tsc()-kernel_start_tsc;
}
sh_uint64 sh_tsc_estimate_cpu_freq() {
sh_pic_remap();
sh_pic_mask(0);
sh_asm_sti();
sh_pit_set_frequency(1000);
sh_uint64 total_tsc=0;
for (sh_uint64 i=0;i<16;i++) {
sh_irq_start_tsc();
sh_pic_unmask(0);
while (sh_irq_get_tsc_delta()==0) {
__asm__ volatile("hlt");
}
sh_pic_mask(0);
total_tsc+=sh_irq_get_tsc_delta();
sh_log_fdebug(SH_LOG_SOURCE_MAIN,"CPU Frequence #%8u: %8u hz`\n",i+1,sh_irq_get_tsc_delta()*1000);
}
return (total_tsc*1000)/16;
}
void sh_tsc_load_cpu_freq(sh_uint64 cpu_freq) {
internal_cpu_freq=cpu_freq;
}
sh_bool sh_tsc_has_hypervisor() {
sh_uint32 eax,ebx,ecx,edx;
sh_asm_cpuid(1,0,&eax,&ebx,&ecx,&edx);
return (sh_bool)((ecx>>31)&1);
}
sh_bool sh_tsc_is_tsc_constant() {
sh_uint32 eax,ebx,ecx,edx;
sh_asm_cpuid(0x80000000,0,&eax,&ebx,&ecx,&edx);
if (eax<0x80000007) return SH_FALSE;
sh_asm_cpuid(0x80000007,0,&eax,&ebx,&ecx,&edx);
sh_uint32 constant;
constant=(edx>>8)&1;
return (sh_bool)constant;
}
SH_STATUS sh_tsc_get_cpu_freq_cpuid(sh_uint64 *freq) {
sh_uint32 eax,ebx,ecx,edx;
sh_asm_cpuid(0x15,0,&eax,&ebx,&ecx,&edx);
if (eax==0 || ebx==0) return SH_STATUS_UNAVAILABLE;
if (ecx!=0) {
*freq=((sh_uint64)ecx*ebx)/eax;
} else {
return SH_STATUS_UNAVAILABLE;
}
is_cpu_freq_provided=SH_TRUE;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_tsc_devs_query(char *sub_path,sh_devs_RESULT *result) {
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(sub_path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (sh_string_compare(sub_path,"/kernel-init-tsc",16)) {
if (path_len==16) {
result->type=SH_DEVS_VALUE;
result->value=kernel_start_tsc;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/cpu-freq",9)) {
if (path_len==9) {
result->type=SH_DEVS_VALUE;
result->value=internal_cpu_freq;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/is-cpu-freq-provided",21)) {
if (path_len==21) {
result->type=SH_DEVS_BOOL;
result->value=is_cpu_freq_provided;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
}

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/acpi.h"
#include "memory/memory.h"
#include "kernel/log.h"
static sh_uint8 sh_acpi_internal_checksum(sh_uint8 *ptr,sh_uint64 size) {
sh_uint8 sum=0;
for (sh_uint64 i=0;i<size;i++) {
sum+=ptr[i];
}
return sum;
}
SH_STATUS sh_acpi_parse_rsdp(sh_uint64 rsdp,sh_uint8 acpi_ver,sh_apci_ACPI_POINTERS_ROOT *out) {
if (rsdp==0 || (acpi_ver!=1 && acpi_ver!=2) || out==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page=rsdp& ~0xFFFULL;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"RSDP: 0x%x; RSDP aligned: 0x%x\n",rsdp,page);
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status)) return status;
sh_acpi_RSDP_V1 *v1=(sh_acpi_RSDP_V1*)rsdp;
const char sig[8]={'R','S','D',' ','P','T','R',' '};
for (sh_uint8 i=0;i<8;i++) {
if (v1->signature[i]!=sig[i]) return SH_STATUS_INVALID_SIGNATURE;
}
if (sh_acpi_internal_checksum((sh_uint8*)v1,sizeof(sh_acpi_RSDP_V1))!=0) return SH_STATUS_INVALID_CHECKSUM;
if (acpi_ver==1 || v1->revision==0) {
out->rsdt=v1->rsdt_address;
out->xsdt=0;
return SH_STATUS_SUCCESS;
}
sh_acpi_RSDP_V2 *v2=(sh_acpi_RSDP_V2 *)rsdp;
if (v2->length<sizeof(sh_acpi_RSDP_V1)) return SH_STATUS_BAD_SIZE;
if (sh_acpi_internal_checksum((sh_uint8*)v2,v2->length)!=0) return SH_STATUS_INVALID_CHECKSUM;
if (acpi_ver==1 && v1->revision>=2) return SH_STATUS_INVALID_STATE;
out->rsdt=v2->first_part.rsdt_address;
out->xsdt=v2->xsdt_address;
if (out->xsdt==0) return SH_STATUS_NOT_FOUND;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_acpi_parse_xsdt(sh_uint64 xsdt,sh_acpi_ACPI_XSDT_BODY *xsdt_body) {
if (xsdt==0 || xsdt_body==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page=xsdt& ~0xFFFULL;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"XSDT: 0x%x; XSDT aligned: 0x%x\n",xsdt,page);
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status)) return status;
sh_acpi_ACPI_XSDT_HEADER *header=(sh_acpi_ACPI_XSDT_HEADER*)xsdt;
if (header->signature[0]!='X' || header->signature[1]!='S' ||header->signature[2]!='D' ||header->signature[3]!='T') return SH_STATUS_INVALID_SIGNATURE;
if (header->length<sizeof(sh_acpi_ACPI_XSDT_HEADER)) return SH_STATUS_INVALID_STATE;
if (sh_acpi_internal_checksum((sh_uint8*)header,header->length)!=0) return SH_STATUS_INVALID_CHECKSUM;
sh_uint64 count=(header->length-sizeof(sh_acpi_ACPI_XSDT_HEADER))/8;
if (count==0) return SH_STATUS_NOT_FOUND;
sh_uint64 *entries=(sh_uint64*)(header+1);
sh_uint64 entries_bytes=count*sizeof(sh_uint64);
sh_uint64 entries_start=(sh_uint64)entries & ~0xFFFULL;
sh_uint64 entries_end=((sh_uint64)entries+entries_bytes+0xFFF)&~0xFFFULL;
sh_uint64 pages=(entries_end-entries_start)>>12;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"XSDT entries: 0x%x; XSDT entries aligned: 0x%x\n",entries,entries_start);
status=sh_memory_identity_map(entries_start,pages,SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status) && status!=SH_STATUS_ERROR_VA_FULLY_MAPPED) return status;
sh_uint64 valid=0;
for (sh_uint64 i=0;i<count;i++) {
if (entries[i]!=0) valid++;
}
if (valid==0) return SH_STATUS_NOT_FOUND;
xsdt_body->entries=entries;
xsdt_body->entry_count=count;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_acpi_parse_tables(sh_acpi_ACPI_XSDT_BODY *xsdt_body,sh_acpi_ACPI_TABLES *acpi_tables) {
if (xsdt_body==SH_NULLPTR || acpi_tables==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
acpi_tables->madt_physical_address=0;
for (sh_uint64 i=0;i<xsdt_body->entry_count;i++) {
sh_uint64 phys=xsdt_body->entries[i];
if (phys==0) {
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Table #%8u: empty, skipping.\n",i);
continue;
}
sh_uint64 page=phys& ~0xfffull;
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status)) return status;
sh_acpi_TABLE_HEADER *header=(sh_acpi_TABLE_HEADER*)phys;
if (header->length<sizeof(sh_acpi_TABLE_HEADER)) {
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Table #%8u: bad length, skipping.\n",i);
continue;
}
if (header->signature[0]=='A' && header->signature[1]=='P' && header->signature[2]=='I' && header->signature[3]=='C') {
if (acpi_tables->madt_physical_address!=0) {
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Duplicated table with APIC signature, skipping.\n");
continue;
} else {
acpi_tables->madt_physical_address=phys;
}
}
char table_signature[5]={0};
sh_mem_copy(table_signature,header->signature,sizeof(header->signature));
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Table #%8u: Signature \"%s\". Stored at 0x%x\n",i,table_signature,(sh_uint64)header);
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,102 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/acpi_tables/madt.h"
#include "devs/apic/lapic.h"
#include "devs/apic/ioapic.h"
#include "memory/memory.h"
#include "kernel/log.h"
#include "irq/gsi.h"
SH_STATUS sh_acpi_madt_parse(sh_uint64 madt_ptr) {
if (madt_ptr==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page=madt_ptr & ~0xfffull;
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_PRESENT | SH_PAGE_NX);
if (sh_status_error(status) && status!=SH_STATUS_ERROR_VA_FULLY_MAPPED) return status;
sh_acpi_madt_MADT *madt=(sh_acpi_madt_MADT*)madt_ptr;
if (madt->header.signature[0]!='A' || madt->header.signature[1]!='P' || madt->header.signature[2]!='I' || madt->header.signature[3]!='C') return SH_STATUS_INVALID_SIGNATURE;
if (madt->header.length<sizeof(sh_acpi_madt_MADT)) return SH_STATUS_INVALID_STATE;
sh_uint64 offset=sizeof(sh_acpi_madt_MADT);
sh_uint64 end=madt->header.length;
sh_uint16 max_apic_id=0;
sh_uint16 max_acpi_processor_id=0;
sh_uint8 max_ioapic_id=0;
status=sh_gsi_iso_array_init();
if (sh_status_error(status)) return status;
while (offset<end) {
sh_acpi_madt_ENTRY_HEADER *header=(sh_acpi_madt_ENTRY_HEADER*)((sh_uint8*)madt+offset);
if (header->length==0) break;
switch (header->type) {
case 0: {
sh_acpi_madt_LAPIC *lapic=(sh_acpi_madt_LAPIC*)header;
if (lapic->flags & 1) {
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Found LAPIC with CPU: apic_id=%1u acpi_processor_id=%1u flags=0x%4U\n",lapic->apic_id,lapic->acpi_processor_id,lapic->flags);
if (lapic->apic_id>max_apic_id) max_apic_id=lapic->apic_id;
if (lapic->acpi_processor_id>max_acpi_processor_id) max_acpi_processor_id=lapic->acpi_processor_id;
} else {
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Found LAPIC without CPU: apic_id=%1u acpi_processor_id=%1u flags=0x%4U\n",lapic->apic_id,lapic->acpi_processor_id,lapic->flags);
}
break;
}
case 1: {
sh_acpi_madt_IOAPIC *ioapic=(sh_acpi_madt_IOAPIC*)header;
if (ioapic->ioapic_id>max_ioapic_id) max_ioapic_id=ioapic->ioapic_id;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Found IOAPIC: ioapic_id=%1u ioapic_address=0x%4U gsi_base=%4U\n",ioapic->ioapic_id,ioapic->ioapic_address,ioapic->global_system_interrupt_base);
break;
}
case 2: {
sh_acpi_madt_ISO *iso=(sh_acpi_madt_ISO*)header;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Found interrupt source override: bus=%1u source=%1u gsi=%4u flags=0x%2U\n",iso->bus,iso->source,iso->gsi,iso->flags);
break;
}
default:
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"Found unknow type: %1u\n",header->type);
break;
}
offset+=header->length;
}
status=sh_lapic_init_devs(max_apic_id,max_acpi_processor_id);
if (sh_status_error(status)) return status;
status=sh_ioapic_init_devs(max_ioapic_id);
if (sh_status_error(status)) return status;
offset=sizeof(sh_acpi_madt_MADT);
end=madt->header.length;
while (offset<end) {
sh_acpi_madt_ENTRY_HEADER *header=(sh_acpi_madt_ENTRY_HEADER*)((sh_uint8*)madt+offset);
if (header->length==0) break;
switch (header->type) {
case 0: {
sh_acpi_madt_LAPIC *lapic=(sh_acpi_madt_LAPIC*)header;
if (lapic->flags & 1) {
sh_lapic_DEVICE *lapic_dev=sh_malloc(sizeof(sh_lapic_DEVICE));
if (!lapic_dev) return SH_STATUS_ERROR_NULLPTR_RETURNED;
status=sh_lapic_init(madt->local_apic_address,0xFF,lapic->apic_id,lapic->acpi_processor_id,lapic->flags,lapic_dev);
if (sh_status_error(status)) return status;
status=sh_lapic_bind(lapic_dev);
if (sh_status_error(status)) return status;
} else {
// ignore
}
break;
}
case 1: {
sh_acpi_madt_IOAPIC *ioapic=(sh_acpi_madt_IOAPIC*)header;
sh_ioapic_DEVICE *ioapic_dev=sh_malloc(sizeof(sh_ioapic_DEVICE));
if (!ioapic_dev) return SH_STATUS_ERROR_NULLPTR_RETURNED;
status=sh_ioapic_init(ioapic->ioapic_address,ioapic->ioapic_id,ioapic->global_system_interrupt_base,ioapic_dev);
if (sh_status_error(status)) return status;
status=sh_ioapic_bind(ioapic_dev);
if (sh_status_error(status)) return status;
break;
}
case 2: {
sh_acpi_madt_ISO *iso=(sh_acpi_madt_ISO*)header;
status=sh_gsi_iso_register(iso->bus,iso->source,iso->gsi,iso->flags);
if (sh_status_error(status)) return status;
break;
}
default:
// ignore
break;
}
offset+=header->length;
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,175 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/apic/ioapic.h"
#include "memory/memory.h"
#include "kernel/log.h"
typedef struct {
sh_ioapic_DEVICE **by_ioapic_id;
sh_uint64 max_ioapic_id;
sh_uint64 ioapic_count;
} ioapic_devs_template;
ioapic_devs_template ioapic_devs={0};
static inline sh_uint32 sh_ioapic_read(sh_ioapic_DEVICE *ioapic,sh_uint32 reg) {
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOREGSEL)=reg;
return *(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOWIN);
}
static inline void sh_ioapic_write(sh_ioapic_DEVICE *ioapic,sh_uint32 reg,sh_uint32 value) {
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOREGSEL)=reg;
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOWIN)=value;
}
SH_STATUS sh_ioapic_init(sh_uint32 base,sh_uint8 ioapic_id,sh_uint32 gsi_base,sh_ioapic_DEVICE *ioapic) {
if (ioapic==SH_NULLPTR || base==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page=base& ~0xfffull;
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_PCD);
if (sh_status_error(status) && status!=SH_STATUS_ERROR_VA_FULLY_MAPPED) return status;
ioapic->base=(volatile sh_uint32*)(sh_uint64)base;
ioapic->ioapic_id=ioapic_id;
ioapic->gsi_base=gsi_base;
ioapic->gsi_count=0;
ioapic->lock=SH_LOCK_LOCAL();
sh_uint32 ver=sh_ioapic_read(ioapic,SH_IOAPIC_REGISTER_IOAPICVER);
sh_uint32 max_redir=(ver>>16)&0xFF;
ioapic->gsi_count=max_redir+1;
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"IOAPIC with id %1u: [%4u - %4u]\n",ioapic->ioapic_id,ioapic->gsi_base,ioapic->gsi_base+ioapic->gsi_count-1);
sh_uint32 id_reg=sh_ioapic_read(ioapic,SH_IOAPIC_REGISTER_IOAPICID);
sh_uint8 hw_id=(id_reg>>24)&0x0F;
if (hw_id!=ioapic_id) {
sh_log_fwarning(SH_LOG_SOURCE_ACPI,"IOAPIC of IOAPIC id %1u doesn't provide the same id in his hardware register: %4u.\n",ioapic_id,hw_id);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ioapic_init_devs(sh_uint8 max_ioapic_id) {
sh_ioapic_DEVICE **ioapic_ptr_by_ioapic_id=sh_malloc((max_ioapic_id+1)*sizeof(sh_ioapic_DEVICE*));
if (!ioapic_ptr_by_ioapic_id) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)ioapic_ptr_by_ioapic_id,0x0,(max_ioapic_id+1)*sizeof(sh_ioapic_DEVICE*));
ioapic_devs.by_ioapic_id=ioapic_ptr_by_ioapic_id;
ioapic_devs.max_ioapic_id=max_ioapic_id;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ioapic_bind(sh_ioapic_DEVICE *ioapic_dev) {
if (ioapic_dev==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
ioapic_devs.by_ioapic_id[ioapic_dev->ioapic_id]=ioapic_dev;
ioapic_devs.ioapic_count++;
return SH_STATUS_SUCCESS;
}
sh_ioapic_DEVICE *sh_ioapic_get_dev_ioapic_id(sh_uint64 ioapic_id) {
if (ioapic_id>ioapic_devs.max_ioapic_id) return SH_NULLPTR;
return ioapic_devs.by_ioapic_id[ioapic_id];
}
SH_STATUS sh_ioapic_read_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
if (!ioapic_dev || !entry) return SH_STATUS_INVALID_PARAMETER;
if (gsi<ioapic_dev->gsi_base) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 index=gsi-ioapic_dev->gsi_base;
if (index>=ioapic_dev->gsi_count) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 low_reg=SH_IOAPIC_REGISTER_IOREDTBL_BASE+(index*2);
sh_uint32 high_reg=low_reg+1;
sh_spin_lock(&ioapic_dev->lock);
entry->low=sh_ioapic_read(ioapic_dev,low_reg);
entry->high=sh_ioapic_read(ioapic_dev,high_reg);
sh_spin_unlock(&ioapic_dev->lock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ioapic_mask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi) {
if (!dev) return SH_STATUS_INVALID_PARAMETER;
sh_ioapic_IOREDTBL_ENTRY e;
SH_STATUS status=sh_ioapic_read_ioredtbl_entry(dev,gsi,&e);
if (status!=SH_STATUS_SUCCESS) return status;
e.low|=(1<<16);
return sh_ioapic_write_ioredtbl_entry(dev,gsi,&e);
}
SH_STATUS sh_ioapic_unmask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi) {
if (!dev) return SH_STATUS_INVALID_PARAMETER;
sh_ioapic_IOREDTBL_ENTRY e;
SH_STATUS status=sh_ioapic_read_ioredtbl_entry(dev,gsi,&e);
if (status!=SH_STATUS_SUCCESS) return status;
e.low&= ~(1U<<16);
return sh_ioapic_write_ioredtbl_entry(dev,gsi,&e);
}
SH_STATUS sh_ioapic_write_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
if (!ioapic_dev || !entry) return SH_STATUS_INVALID_PARAMETER;
if (gsi<ioapic_dev->gsi_base) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 index=gsi-ioapic_dev->gsi_base;
if (index>=ioapic_dev->gsi_count) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 low_reg=SH_IOAPIC_REGISTER_IOREDTBL_BASE+(index*2);
sh_uint32 high_reg=low_reg+1;
sh_spin_lock(&ioapic_dev->lock);
sh_ioapic_write(ioapic_dev,high_reg,entry->high);
sh_ioapic_write(ioapic_dev,low_reg,entry->low);
sh_spin_unlock(&ioapic_dev->lock);
return SH_STATUS_SUCCESS;
}
sh_ioapic_DEVICE *sh_ioapic_get_dev_by_gsi(sh_uint32 gsi) {
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_NULLPTR;
for (sh_uint64 i=0;i<=ioapic_devs.max_ioapic_id;i++) {
sh_ioapic_DEVICE *dev=ioapic_devs.by_ioapic_id[i];
if (!dev) continue;
if (gsi>=dev->gsi_base && gsi<(dev->gsi_base+dev->gsi_count)) {
return dev;
}
}
return SH_NULLPTR;
}
SH_STATUS sh_ioapic_mask_all() {
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
for (sh_uint64 i=0;i<=ioapic_devs.max_ioapic_id;i++) {
sh_ioapic_DEVICE *dev=ioapic_devs.by_ioapic_id[i];
if (!dev) continue;
for (sh_uint32 j=0;j<dev->gsi_count;j++) {
sh_uint32 gsi=dev->gsi_base+j;
SH_STATUS status=sh_ioapic_mask_gsi(dev,gsi);
if (sh_status_error(status)) return status;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ioapic_devs_query(char *sub_path,sh_devs_RESULT *result) {
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(sub_path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
if (sh_string_compare(sub_path,"/count",6)) {
if (path_len==6) {
result->type=SH_DEVS_VALUE;
result->value=ioapic_devs.ioapic_count;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/max-ioapic-id",14)) {
if (path_len==14) {
result->type=SH_DEVS_VALUE;
result->value=ioapic_devs.max_ioapic_id;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/by-ioapic-id/",14)) {
if (path_len>14 && path_len<=34) {
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-ioapic-id/");
char ioapic_id_str[22];
sh_string_substring(sub_path,sh_string_len("/by-ioapic-id/"),remaining_text,ioapic_id_str);
sh_uint64 ioapic_id=sh_string_to_uint64(ioapic_id_str);
if (ioapic_id>ioapic_devs.max_ioapic_id) return SH_STATUS_NOT_FOUND;
result->type=SH_DEVS_IOAPIC;
result->value=(sh_uint64)ioapic_devs.by_ioapic_id[ioapic_id];
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/by-gsi/",8)) {
if (path_len>8 && path_len<=28) {
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-gsi/");
char gsi_str[22];
sh_string_substring(sub_path,sh_string_len("/by-gsi/"),remaining_text,gsi_str);
sh_uint64 gsi=sh_string_to_uint64(gsi_str);
result->type=SH_DEVS_IOAPIC;
result->value=(sh_uint64)sh_ioapic_get_dev_by_gsi((sh_uint32)gsi);
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,286 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/apic/lapic.h"
#include "memory/memory.h"
#include "irq/irq.h"
#include "cpu/tsc.h"
typedef struct {
sh_lapic_DEVICE **by_apic_id;
sh_lapic_DEVICE **by_cpu_id;
sh_uint64 max_apic_id;
sh_uint64 max_acpi_processor_id;
sh_uint64 lapic_count;
} lapic_devs_template;
lapic_devs_template lapic_devs={0};
sh_uint64 lapic_frequency=0;
static inline sh_uint32 sh_lapic_read(sh_lapic_DEVICE *lapic,sh_uint32 reg) {
return *(volatile sh_uint32*)((sh_uint8*)lapic->base+reg);
}
static inline void sh_lapic_write(sh_lapic_DEVICE *lapic,sh_uint32 reg,sh_uint32 value) {
*(volatile sh_uint32*)((sh_uint8*)lapic->base+reg)=value;
}
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) {
if (lapic==SH_NULLPTR || lapic_phys==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page=lapic_phys& ~0xfffull;
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_PCD);
if (sh_status_error(status) && status!=SH_STATUS_ERROR_VA_FULLY_MAPPED) return status;
lapic->base=(volatile sh_uint32*)lapic_phys;
lapic->spurious_vector=spurious_vector;
lapic->apic_id=apic_id;
lapic->acpi_processor_id=apic_processor_id;
lapic->flags=flags;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_lapic_init_dev(sh_uint8 spurious_vector,sh_lapic_DEVICE *lapic) {
if (lapic==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 svr=spurious_vector|(1<<8);
sh_lapic_write(lapic,SH_LAPIC_OFFSET_SVR,svr);
sh_lapic_write(lapic,SH_LAPIC_OFFSET_ESR,0);
sh_lapic_write(lapic,SH_LAPIC_OFFSET_ESR,0);
sh_lapic_write(lapic,SH_LAPIC_OFFSET_EOI,0);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_lapic_init_devs(sh_uint16 max_lapic_id,sh_uint16 max_acpi_processor_id) {
if (max_lapic_id==0 || max_lapic_id>256) return SH_STATUS_INVALID_PARAMETER;
sh_lapic_DEVICE **lapic_ptr_by_apic_id=sh_malloc((max_lapic_id+1)*sizeof(sh_lapic_DEVICE*));
if (!lapic_ptr_by_apic_id) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)lapic_ptr_by_apic_id,0x0,(max_lapic_id+1)*sizeof(sh_lapic_DEVICE*));
lapic_devs.by_apic_id=lapic_ptr_by_apic_id;
sh_lapic_DEVICE **lapic_ptr_by_cpu_id=sh_malloc((max_acpi_processor_id+1)*sizeof(sh_lapic_DEVICE*));
if (!lapic_ptr_by_cpu_id) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)lapic_ptr_by_cpu_id,0x0,(max_acpi_processor_id+1)*sizeof(sh_lapic_DEVICE*));
lapic_devs.by_cpu_id=lapic_ptr_by_cpu_id;
lapic_devs.max_apic_id=max_lapic_id;
lapic_devs.max_acpi_processor_id=max_acpi_processor_id;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_lapic_bind(sh_lapic_DEVICE *lapic_dev) {
if (lapic_dev==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (lapic_devs.by_apic_id==SH_NULLPTR || lapic_devs.by_cpu_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
lapic_devs.by_apic_id[lapic_dev->apic_id]=lapic_dev;
lapic_devs.by_cpu_id[lapic_dev->acpi_processor_id]=lapic_dev;
lapic_devs.lapic_count++;
return SH_STATUS_SUCCESS;
}
void sh_lapic_eoi(sh_lapic_DEVICE *lapic) {
sh_lapic_write(lapic,SH_LAPIC_OFFSET_EOI,0);
}
sh_lapic_DEVICE *sh_lapic_get_dev_apic_id(sh_uint64 apic_id) {
if (lapic_devs.by_apic_id==SH_NULLPTR) return SH_NULLPTR;
if (apic_id>lapic_devs.max_apic_id) return SH_NULLPTR;
return lapic_devs.by_apic_id[apic_id];
}
sh_lapic_DEVICE *sh_lapic_get_dev_acpi_cpu_id(sh_uint64 acpi_processor_id) {
if (lapic_devs.by_cpu_id==SH_NULLPTR) return SH_NULLPTR;
if (acpi_processor_id>lapic_devs.max_apic_id) return SH_NULLPTR;
return lapic_devs.by_apic_id[acpi_processor_id];
}
SH_STATUS sh_lapic_timer_one_shot(sh_lapic_DEVICE *lapic_dev,sh_uint32 initial_value) {
if (lapic_dev==SH_NULLPTR || initial_value==0) return SH_STATUS_INVALID_PARAMETER;
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_LVT_TIMER,(1<<16));
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_TIMER_DIV,SH_LAPIC_TIMER_DIVIDER);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_TIMER_INIT,initial_value);
sh_uint32 lvt=(0xFE)|(0<<17)|(0<<16);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_LVT_TIMER,lvt);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_lapic_calibrate(sh_lapic_DEVICE *lapic_dev,sh_uint64 cpu_freq) {
if (!lapic_dev) return SH_STATUS_INVALID_PARAMETER;
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_TIMER_DIV,SH_LAPIC_TIMER_DIVIDER);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_LVT_TIMER,(1<<16));
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_TIMER_INIT,0xFFFFFFFF);
sh_uint64 tsc_start=sh_tsc_read_tsc();
sh_uint32 lapic_start=sh_lapic_read(lapic_dev,SH_LAPIC_OFFSET_TIMER_CURR);
for (volatile int i=0;i<10000000;i++) __asm__ volatile("pause");
sh_uint32 lapic_end=sh_lapic_read(lapic_dev,SH_LAPIC_OFFSET_TIMER_CURR);
sh_uint64 tsc_end=sh_tsc_read_tsc();
sh_uint32 lapic_delta=lapic_start-lapic_end;
sh_uint64 tsc_delta=tsc_end-tsc_start;
if (!tsc_delta || !lapic_delta) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 lapic_freq=(lapic_delta*cpu_freq)/tsc_delta;
lapic_frequency=lapic_freq;
return SH_STATUS_SUCCESS;
}
sh_uint64 sh_lapic_get_frequency() {
return lapic_frequency;
}
SH_STATUS sh_lapic_timer_one_shot_us(sh_lapic_DEVICE *lapic_dev,sh_uint64 microseconds_count) {
sh_asm_sti();
if (lapic_frequency==0) return SH_STATUS_INVALID_STATE;
if (microseconds_count==0) return SH_STATUS_SUCCESS;
sh_uint64 ticks=(lapic_frequency*microseconds_count)/1000000ULL;
if (ticks>0xFFFFFFFF) return SH_STATUS_TOO_MUCH_DATA;
if (ticks==0) ticks=1;
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_LVT_TIMER,(1<<16));
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_LVT_TIMER,0xFE);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_TIMER_INIT,(sh_uint32)ticks);
sh_irq_start_timer();
while (sh_irq_get_timer_state()) {
__asm__ volatile ("hlt");
}
return SH_STATUS_SUCCESS;
}
sh_lapic_DEVICE **sh_lapic_get_by_apic_id_array() {
return lapic_devs.by_apic_id;
}
sh_uint64 sh_lapic_get_max_apic_id() {
return lapic_devs.max_apic_id;
}
sh_uint64 sh_lapic_get_max_acpi_processor_id() {
return lapic_devs.max_acpi_processor_id;
}
sh_uint64 sh_lapic_get_lapic_count() {
return lapic_devs.lapic_count;
}
sh_bool sh_lapic_ipi_is_busy(sh_lapic_DEVICE *lapic_dev) {
if (!lapic_dev) return SH_FALSE;
return (sh_lapic_read(lapic_dev,SH_LAPIC_OFFSET_ICR_LOW)&(1u<<12))?SH_TRUE:SH_FALSE;
}
sh_int16 sh_lapic_get_current_core() {
sh_lapic_DEVICE *lapic_dev=sh_lapic_get_dev_apic_id(0);
if (!lapic_dev) return -1;
return (sh_int16)((sh_lapic_read(lapic_dev,SH_LAPIC_OFFSET_ID)>>24)&0xFF);
}
SH_STATUS sh_lapic_send_fixed_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint8 vector,sh_uint32 destination_mode,sh_int16 target_lapic_id) {
sh_uint32 icr_low=0;
sh_uint32 icr_high=0;
if (!lapic_dev) return SH_STATUS_INVALID_PARAMETER;
if (vector<16) return SH_STATUS_INVALID_PARAMETER;
switch (destination_mode) {
case SH_LAPIC_IPI_DESTINATION_SPECIFIC:
if (target_lapic_id==SH_LAPIC_IPI_NO_DESTINATION)
return SH_STATUS_INVALID_PARAMETER;
break;
case SH_LAPIC_IPI_DESTINATION_SELF:
case SH_LAPIC_IPI_DESTINATION_ALL:
case SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF:
if (target_lapic_id!=SH_LAPIC_IPI_NO_DESTINATION)
return SH_STATUS_INVALID_PARAMETER;
break;
default:
return SH_STATUS_INVALID_PARAMETER;
}
while (sh_lapic_ipi_is_busy(lapic_dev));
if (destination_mode==SH_LAPIC_IPI_DESTINATION_SPECIFIC) icr_high=((sh_uint32)target_lapic_id&0xFF)<<24;
icr_low=vector|(SH_LAPIC_IPI_TYPE_FIXED<<8)|(1u<<14)|destination_mode;
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_ICR_HIGH,icr_high);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_ICR_LOW,icr_low);
return SH_STATUS_SUCCESS;
}
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) {
sh_uint32 icr_low=0;
sh_uint32 icr_high=0;
if (!lapic_dev) return SH_STATUS_INVALID_PARAMETER;
if (ipi_type!=SH_LAPIC_IPI_TYPE_INIT && ipi_type!=SH_LAPIC_IPI_TYPE_STARTUP && ipi_type!=SH_LAPIC_IPI_TYPE_NMI) return SH_STATUS_INVALID_PARAMETER;
if (ipi_type==SH_LAPIC_IPI_TYPE_STARTUP) {
if (start_address==0) return SH_STATUS_INVALID_PARAMETER;
if (start_address&0xFFF) return SH_STATUS_INVALID_PARAMETER;
if ((start_address>>12)>0xFF) return SH_STATUS_INVALID_PARAMETER;
} else {
if (start_address!=0) return SH_STATUS_INVALID_PARAMETER;
}
switch (destination_mode) {
case SH_LAPIC_IPI_DESTINATION_SPECIFIC:
if (target_lapic_id==SH_LAPIC_IPI_NO_DESTINATION)
return SH_STATUS_INVALID_PARAMETER;
break;
case SH_LAPIC_IPI_DESTINATION_SELF:
case SH_LAPIC_IPI_DESTINATION_ALL:
case SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF:
if (target_lapic_id!=SH_LAPIC_IPI_NO_DESTINATION)
return SH_STATUS_INVALID_PARAMETER;
break;
default:
return SH_STATUS_INVALID_PARAMETER;
}
while (sh_lapic_ipi_is_busy(lapic_dev));
if (destination_mode==SH_LAPIC_IPI_DESTINATION_SPECIFIC) icr_high=((sh_uint32)target_lapic_id&0xFF)<<24;
icr_low=(ipi_type<<8)|(1u<<14)|destination_mode;
if (ipi_type==SH_LAPIC_IPI_TYPE_STARTUP) icr_low|=(sh_uint32)(start_address>>12);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_ICR_HIGH,icr_high);
sh_lapic_write(lapic_dev,SH_LAPIC_OFFSET_ICR_LOW,icr_low);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_lapic_devs_query(char *sub_path,sh_devs_RESULT *result) {
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(sub_path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (lapic_devs.by_apic_id==SH_NULLPTR || lapic_devs.by_cpu_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
if (sh_string_compare(sub_path,"/count",6)) {
if (path_len==6) {
result->type=SH_DEVS_VALUE;
result->value=lapic_devs.lapic_count;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/timer-frequency",16)) {
if (path_len==16) {
result->type=SH_DEVS_VALUE;
result->value=lapic_frequency;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/max-apic-id",12)) {
if (path_len==12) {
result->type=SH_DEVS_VALUE;
result->value=lapic_devs.max_apic_id;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/max-acpi-id",12)) {
if (path_len==12) {
result->type=SH_DEVS_VALUE;
result->value=lapic_devs.max_acpi_processor_id;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/base-address",13)) {
if (path_len==13) {
result->type=SH_DEVS_VALUE;
result->value=(sh_uint64)sh_lapic_get_dev_apic_id(sh_smp_gs_base()->lapic_id)->base;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/this-cpu-lapic",15)) {
if (path_len==15) {
result->type=SH_DEVS_LAPIC;
result->value=(sh_uint64)sh_lapic_get_dev_apic_id(sh_smp_gs_base()->lapic_id);
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/by-apic-id/",12)) {
if (path_len>12 && path_len<=32) {
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-apic-id/");
char apic_id_str[22];
sh_string_substring(sub_path,sh_string_len("/by-apic-id/"),remaining_text,apic_id_str);
sh_uint64 apic_id=sh_string_to_uint64(apic_id_str);
if (apic_id>lapic_devs.max_apic_id) return SH_STATUS_NOT_FOUND;
result->type=SH_DEVS_LAPIC;
result->value=(sh_uint64)lapic_devs.by_apic_id[apic_id];
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/by-acpi-id/",12)) {
if (path_len>12 && path_len<=32) {
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-acpi-id/");
char acpi_id_str[22];
sh_string_substring(sub_path,sh_string_len("/by-acpi-id/"),remaining_text,acpi_id_str);
sh_uint64 acpi_id=sh_string_to_uint64(acpi_id_str);
if (acpi_id>lapic_devs.max_apic_id) return SH_STATUS_NOT_FOUND;
result->type=SH_DEVS_LAPIC;
result->value=(sh_uint64)lapic_devs.by_cpu_id[acpi_id];
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/devs.h"
#include "devs/apic/lapic.h"
#include "devs/apic/ioapic.h"
#include "std/smp.h"
SH_STATUS sh_devs_query(char *path,sh_devs_RESULT *result) {
if (path==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (sh_string_compare(path,"$apic/lapic",11)) {
if (path_len>11) {
sh_uint64 remaining_text=sh_string_len(path)-sh_string_len("$apic/lapic");
return sh_lapic_devs_query(sh_string_substring(path,sh_string_len("$apic/lapic"),remaining_text,sh_smp_gs_base()->per_cpu->temp_buffer),result);
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(path,"$apic/ioapic",12)) {
if (path_len>12) {
sh_uint64 remaining_text=sh_string_len(path)-sh_string_len("$apic/ioapic");
return sh_ioapic_devs_query(sh_string_substring(path,sh_string_len("$apic/ioapic"),remaining_text,sh_smp_gs_base()->per_cpu->temp_buffer),result);
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(path,"$tsc",4)) {
if (path_len>4) {
sh_uint64 remaining_text=sh_string_len(path)-sh_string_len("$tsc");
return sh_tsc_devs_query(sh_string_substring(path,sh_string_len("$tsc"),remaining_text,sh_smp_gs_base()->per_cpu->temp_buffer),result);
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(path,"$kernel/conf",12)) {
if (path_len>12) {
sh_uint64 remaining_text=sh_string_len(path)-sh_string_len("$kernel/conf");
return sh_conf_devs_query(sh_string_substring(path,sh_string_len("$kernel/conf"),remaining_text,sh_smp_gs_base()->per_cpu->temp_buffer),result);
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(path,"$memory",7)) {
if (path_len>7) {
sh_uint64 remaining_text=sh_string_len(path)-sh_string_len("$memory");
return sh_memory_devs_query(sh_string_substring(path,sh_string_len("$memory"),remaining_text,sh_smp_gs_base()->per_cpu->temp_buffer),result);
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(path,"$smp/cpu-count",14)) {
if (path_len==14) {
result->type=SH_DEVS_VALUE;
result->value=(sh_uint64)sh_smp_get_cpu_count();
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
}

View File

@@ -0,0 +1,340 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/input/kbd.h"
struct sh_kbd_DRIVER_HANDLE {
sh_uint8 id;
sh_uint32 generation;
};
struct sh_kbd_CONSUMER_HANDLE {
sh_uint8 id;
sh_uint32 generation;
sh_uint32 read_index;
};
typedef struct {
sh_kbd_DEVICE by_id[256];
sh_uint32 id_generation[256];
sh_uint64 bitmap[4];
sh_uint64 keyboard_count;
sh_SPIN_LOCK id_manipulation_spinlock;
sh_bool ps2_registered;
sh_uint16 events_queue_capacity;
sh_bool is_kbd_devs_initialized;
} kbd_devs_template;
kbd_devs_template kbd_devs={.id_manipulation_spinlock=SH_LOCK()};
SH_STATUS sh_kbd_init_devs() {
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ALREADY_INITIALIZED;
}
sh_mem_set_8((sh_uint8*)kbd_devs.by_id,0x0,sizeof(sh_kbd_DEVICE)*256);
for (sh_iter64 i=0;i<256;i++) kbd_devs.by_id[i].spinlock=SH_LOCK_LOCAL();
sh_mem_set_8((sh_uint8*)kbd_devs.id_generation,0x0,sizeof(sh_uint16)*256);
sh_mem_set_8((sh_uint8*)kbd_devs.bitmap,0x0,sizeof(sh_uint64)*4);
kbd_devs.keyboard_count=0;
kbd_devs.is_kbd_devs_initialized=SH_TRUE;
sh_devs_RESULT res;
SH_STATUS status=sh_devs_query("$kernel/conf/kbd-events-queue-capacity",&res);
if (sh_status_error(status)) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return status;
}
kbd_devs.events_queue_capacity=(sh_uint16)res.value;
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_register_ps2(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle) {
if (handle==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
if (kbd_devs.ps2_registered) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ALREADY_INITIALIZED;
}
sh_uint8 id=0;
kbd_devs.bitmap[0]|=1ULL;
kbd_devs.id_generation[id]++;
sh_kbd_DEVICE *dev=&kbd_devs.by_id[id];
dev->kbd_id=id;
dev->present=is_present;
dev->ver_maj=SH_FALSE;
dev->ver_num=SH_FALSE;
dev->shift=SH_FALSE;
dev->alt=SH_FALSE;
dev->ctrl=SH_FALSE;
dev->win=SH_FALSE;
dev->spinlock=SH_LOCK_LOCAL();
sh_queue_KBD_EVENT *dev_queue=sh_malloc(sizeof(sh_queue_KBD_EVENT));
if (!dev_queue) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ERROR_NULLPTR_RETURNED;
}
SH_STATUS status=sh_queue_event_init(dev_queue,kbd_devs.events_queue_capacity);
if (sh_status_error(status)) {
sh_free(dev_queue);
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return status;
}
dev->events_queue=dev_queue;
kbd_devs.keyboard_count++;
kbd_devs.ps2_registered=SH_TRUE;
sh_kbd_DRIVER_HANDLE *driver_handle=sh_malloc(sizeof(sh_kbd_DRIVER_HANDLE));
if (!dev_queue) {
status=sh_queue_event_destroy(dev_queue);
if (sh_status_error(status)) return status;
sh_free(dev_queue);
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ERROR_NULLPTR_RETURNED;
}
driver_handle->id=id;
driver_handle->generation=kbd_devs.id_generation[id];
*handle=driver_handle;
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_register(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle) {
if (handle==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
sh_uint8 id=0;
sh_bool found=SH_FALSE;
for (sh_uint32 i=1;i<256;i++) {
sh_uint32 idx=i/64;
sh_uint32 bit=i%64;
if (!(kbd_devs.bitmap[idx] & (1ULL<<bit))) {
kbd_devs.bitmap[idx]|=(1ULL<<bit);
id=(sh_uint8)i;
found=SH_TRUE;
break;
}
}
if (!found) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_NOT_FOUND;
}
sh_kbd_DEVICE *dev=&kbd_devs.by_id[id];
sh_mem_set_8((sh_uint8*)dev,0,sizeof(sh_kbd_DEVICE));
dev->kbd_id=id;
dev->present=is_present;
dev->ver_maj=SH_FALSE;
dev->ver_num=SH_FALSE;
dev->shift=SH_FALSE;
dev->alt=SH_FALSE;
dev->ctrl=SH_FALSE;
dev->win=SH_FALSE;
dev->spinlock=SH_LOCK_LOCAL();
kbd_devs.id_generation[id]++;
sh_queue_KBD_EVENT *dev_queue=sh_malloc(sizeof(sh_queue_KBD_EVENT));
if (!dev_queue) {
kbd_devs.bitmap[id/64]&= ~(1ULL<<(id%64));
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ERROR_NULLPTR_RETURNED;
}
SH_STATUS status=sh_queue_event_init(dev_queue,kbd_devs.events_queue_capacity);
if (sh_status_error(status)) {
sh_free(dev_queue);
kbd_devs.bitmap[id/64]&= ~(1ULL<<(id%64));
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return status;
}
dev->events_queue=dev_queue;
kbd_devs.keyboard_count++;
sh_kbd_DRIVER_HANDLE *driver_handle=sh_malloc(sizeof(sh_kbd_DRIVER_HANDLE));
if (!dev_queue) {
status=sh_queue_event_destroy(dev_queue);
if (sh_status_error(status)) return status;
sh_free(dev_queue);
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ERROR_NULLPTR_RETURNED;
}
driver_handle->id=id;
driver_handle->generation=kbd_devs.id_generation[id];
*handle=driver_handle;
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_set_flag(sh_kbd_DRIVER_HANDLE *handle,sh_uint8 flag,sh_bool value) {
if (handle==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
sh_uint8 id=handle->id;
if (kbd_devs.id_generation[id]!=handle->generation) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_INVALID_HANDLE;
}
sh_uint32 idx=id/64;
sh_uint32 bit=id%64;
if (!(kbd_devs.bitmap[idx] & (1ULL<<bit))) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_INVALID_HANDLE;
}
sh_kbd_DEVICE *dev=&kbd_devs.by_id[id];
sh_spin_lock(&dev->spinlock);
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
switch (flag) {
case SH_KBD_FLAG_PRESENT:
dev->present=value;
break;
case SH_KBD_FLAG_VER_MAJ:
dev->ver_maj=value;
break;
case SH_KBD_FLAG_VER_NUM:
dev->ver_num=value;
break;
case SH_KBD_FLAG_SHIFT:
dev->shift=value;
break;
case SH_KBD_FLAG_ALT:
dev->alt=value;
break;
case SH_KBD_FLAG_CTRL:
dev->ctrl=value;
break;
case SH_KBD_FLAG_WIN:
dev->win=value;
break;
default:
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_INVALID_PARAMETER;
}
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_push_events(sh_kbd_DRIVER_HANDLE *handle,sh_kbd_EVENT *event) {
if (handle==SH_NULLPTR || event==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint8 id=handle->id;
if (kbd_devs.id_generation[id]!=handle->generation) return SH_STATUS_INVALID_HANDLE;
if (!(kbd_devs.bitmap[id/64] & (1ULL<<(id%64)))) return SH_STATUS_INVALID_HANDLE;
sh_kbd_DEVICE *dev=&kbd_devs.by_id[id];
sh_spin_lock(&dev->spinlock);
if (!dev->present) {
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_DEVICE_NOT_PRESENT;
}
sh_queue_KBD_EVENT *queue=(sh_queue_KBD_EVENT*)dev->events_queue;
if (queue==SH_NULLPTR) {
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_INVALID_STATE;
}
SH_STATUS status=sh_queue_event_push(queue,*event);
if (sh_status_error(status)) {
sh_spin_unlock(&dev->spinlock);
return status;
}
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_enumerate_devices(sh_kbd_ENUMERATION *enumeration) {
if (enumeration==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
enumeration->bitmap[0]=kbd_devs.bitmap[0];
enumeration->bitmap[1]=kbd_devs.bitmap[1];
enumeration->bitmap[2]=kbd_devs.bitmap[2];
enumeration->bitmap[3]=kbd_devs.bitmap[3];
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_get_handle(sh_uint8 kbd_id,sh_kbd_CONSUMER_HANDLE **handle) {
if (handle==SH_NULLPTR)return SH_STATUS_INVALID_PARAMETER;
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
sh_uint32 idx=kbd_id>>6;
sh_uint32 bit=kbd_id&63;
if (!(kbd_devs.bitmap[idx] & (1ULL<<bit))) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_NOT_FOUND;
}
sh_uint32 generation=kbd_devs.id_generation[kbd_id];
sh_kbd_CONSUMER_HANDLE *h=sh_malloc(sizeof(sh_kbd_CONSUMER_HANDLE));
if (h==SH_NULLPTR) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_ERROR_NULLPTR_RETURNED;
}
h->id=kbd_id;
h->generation=generation;
h->read_index=kbd_devs.by_id[kbd_id].events_queue->write_index;
*handle=h;
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_destroy_handle(sh_kbd_CONSUMER_HANDLE **handle) {
if (handle==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (*handle==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_free(*handle);
*handle=SH_NULLPTR;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_kbd_read_flag(sh_kbd_DRIVER_HANDLE *d_handle,sh_kbd_CONSUMER_HANDLE *c_handle,sh_uint8 flag,sh_bool *value) {
if (value==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if ((d_handle==SH_NULLPTR && c_handle==SH_NULLPTR) || (d_handle!=SH_NULLPTR && c_handle!=SH_NULLPTR)) return SH_STATUS_INVALID_PARAMETER;
sh_uint8 id;
sh_uint32 generation;
if (d_handle!=SH_NULLPTR) {
id=d_handle->id;
generation=d_handle->generation;
} else {
id=c_handle->id;
generation=c_handle->generation;
}
sh_spin_lock(&kbd_devs.id_manipulation_spinlock);
if (!kbd_devs.is_kbd_devs_initialized) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_DEVS_NOT_INITIALIZED;
}
if (kbd_devs.id_generation[id]!=generation) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_INVALID_HANDLE;
}
sh_uint32 idx=id>>6;
sh_uint32 bit=id&63;
if (!(kbd_devs.bitmap[idx] & (1ULL<<bit))) {
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
return SH_STATUS_INVALID_HANDLE;
}
sh_kbd_DEVICE *dev=&kbd_devs.by_id[id];
sh_spin_lock(&dev->spinlock);
sh_spin_unlock(&kbd_devs.id_manipulation_spinlock);
switch (flag) {
case SH_KBD_FLAG_PRESENT:
*value=dev->present;
break;
case SH_KBD_FLAG_VER_MAJ:
*value=dev->ver_maj;
break;
case SH_KBD_FLAG_VER_NUM:
*value=dev->ver_num;
break;
case SH_KBD_FLAG_SHIFT:
*value=dev->shift;
break;
case SH_KBD_FLAG_ALT:
*value=dev->alt;
break;
case SH_KBD_FLAG_CTRL:
*value=dev->ctrl;
break;
case SH_KBD_FLAG_WIN:
*value=dev->win;
break;
default:
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_INVALID_PARAMETER;
}
sh_spin_unlock(&dev->spinlock);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,777 @@
// SPDX-License-Identifier: MPL-2.0
#include "devs/input/ps2.h"
#include "devs/input/kbd.h"
#include "irq/irq.h"
enum ps2_scancode_state {
PS2_SCANCODE_STATE_NORMAL,
PS2_SCANCODE_STATE_E0,
PS2_SCANCODE_STATE_E1
};
enum ps2_command_state {
PS2_COMMAND_STATE_IDLE,
PS2_COMMAND_STATE_WAIT_ACK,
PS2_COMMAND_STATE_WAIT_LED_ACK_1,
PS2_COMMAND_STATE_WAIT_LED_ACK_2,
PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1,
PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2,
PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK,
PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1,
PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2,
PS2_COMMAND_STATE_WAIT_ECHO,
PS2_COMMAND_STATE_WAIT_RESET_ACK,
PS2_COMMAND_STATE_WAIT_RESET_RESULT
};
typedef struct {
enum ps2_scancode_state scancode_state;
enum ps2_command_state command_state;
sh_ps2_KBD_COMMAND current_command;
sh_uint8 last_byte;
sh_uint8 e1_bytes_left;
sh_uint8 e1_bytes_idx;
sh_uint8 e1_bytes_array[5];
sh_bool command_in_progress;
sh_uint8 keyboard_id[2];
sh_uint8 keyboard_id_len;
sh_bool scanning_enabled;
sh_bool shift_state;
sh_bool l_alt_state;
sh_bool r_alt_state;
sh_bool l_ctrl_state;
sh_bool r_ctrl_state;
sh_bool win_state;
sh_bool capslock_state;
sh_bool numlock_state;
sh_kbd_DRIVER_HANDLE *d_handle;
} ps2_state_template;
ps2_state_template ps2_state;
static void sh_ps2_send_keyboard_command(sh_uint8 cmd,sh_uint8 data,sh_bool has_data) {
ps2_state.current_command.command=cmd;
ps2_state.current_command.data=data;
ps2_state.current_command.has_data=has_data;
ps2_state.command_in_progress=SH_TRUE;
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,cmd);
}
SH_STATUS sh_ps2_send_keyboard_command_wait(sh_uint8 cmd,sh_uint8 data,sh_bool has_data) {
sh_ps2_send_keyboard_command(cmd,data,has_data);
while (ps2_state.command_in_progress) {
asm volatile("hlt");
}
return SH_STATUS_SUCCESS;
}
// Because we don't have a scheduler or kernel threads/worker, we can't properly update these leds for the moment
__attribute__((__unused__)) static void sh_ps2_update_leds() {
sh_uint8 led_byte=0;
if (ps2_state.numlock_state) {
led_byte|=SH_PS2_KBD_LEDS_NUM_LOCK;
}
if (ps2_state.capslock_state) {
led_byte|=SH_PS2_KBD_LEDS_CAPS_LOCK;
}
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_SET_LEDS,led_byte,SH_TRUE);
return;
}
static SH_STATUS sh_ps2_handle_command_response(sh_uint8 data) {
if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_ACK) {
if (data==SH_PS2_KBD_ACK) {
if (ps2_state.current_command.command==SH_PS2_KBD_COMMAND_DISABLE_SCANNING) {
ps2_state.scanning_enabled=SH_FALSE;
} else if (ps2_state.current_command.command==SH_PS2_KBD_COMMAND_ENABLE_SCANNING) {
ps2_state.scanning_enabled=SH_TRUE;
}
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.current_command.command=0;
ps2_state.current_command.data=0;
ps2_state.current_command.has_data=SH_FALSE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
sh_ps2_send_keyboard_command(ps2_state.current_command.command,ps2_state.current_command.data,ps2_state.current_command.has_data);
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_ECHO) {
if (data==SH_PS2_KBD_COMMAND_ECHO) {
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else {
sh_iprint(SH_DEBUG,"wrong echo\n");
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK) {
if (data==SH_PS2_KBD_ACK) {
ps2_state.keyboard_id_len=0;
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_IDENTIFY,0,SH_FALSE);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK;
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1) {
ps2_state.keyboard_id[0]=data;
ps2_state.keyboard_id_len=1;
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2;
return SH_STATUS_SUCCESS;
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2) {
ps2_state.keyboard_id[1]=data;
ps2_state.keyboard_id_len=2;
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_LED_ACK_1) {
if (data==SH_PS2_KBD_ACK) {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_2;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_SET_LEDS,ps2_state.current_command.data,SH_TRUE);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_LED_ACK_2) {
if (data==SH_PS2_KBD_ACK) {
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_RESET_ACK) {
if (data==SH_PS2_KBD_ACK) {
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_RESET_RESULT;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_RESET,0,SH_FALSE);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_RESET_ACK;
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_RESET_RESULT) {
if (data==0xAA || data==0xFC) {
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else {
sh_iprintf(SH_DEBUG,"wrong reset\n");
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1) {
if (data==SH_PS2_KBD_ACK) {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_SC_SET,ps2_state.current_command.data,SH_TRUE);
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1;
return SH_STATUS_SUCCESS;
}
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2) {
if (data==SH_PS2_KBD_ACK) {
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.command_in_progress=SH_FALSE;
return SH_STATUS_SUCCESS;
} else if (data==SH_PS2_KBD_RESEND) {
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
return SH_STATUS_SUCCESS;
}
}
return SH_STATUS_INVALID_STATE;
}
static inline sh_bool sh_ps2_shift() {
return ps2_state.shift_state;
}
static inline sh_bool sh_ps2_alt() {
return ps2_state.l_alt_state || ps2_state.r_alt_state;
}
static inline sh_bool sh_ps2_ctrl() {
return ps2_state.l_ctrl_state || ps2_state.r_ctrl_state;
}
static void sh_ps2_handle_scancodes(sh_uint8 data) {
if (data==0xE0 && ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
ps2_state.scancode_state=PS2_SCANCODE_STATE_E0;
return;
} else if (data==0xE1 && ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
ps2_state.scancode_state=PS2_SCANCODE_STATE_E1;
ps2_state.e1_bytes_left=5;
ps2_state.e1_bytes_idx=0;
return;
}
if (ps2_state.scancode_state!=PS2_SCANCODE_STATE_E1) {
switch (data) {
case 0x1D: {
// ctrl pressed
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LCTRL,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.l_ctrl_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
}
return;
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RCTRL,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.r_ctrl_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
}
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
return;
}
break;
}
case 0x9D: {
// ctrl released
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LCTRL,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.l_ctrl_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
}
return;
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RCTRL,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.r_ctrl_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
}
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
return;
}
break;
}
case 0x36: {
// right shift pressed
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RSHIFT,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.shift_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
}
return;
}
case 0x2A: {
// left shift pressed
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LSHIFT,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.shift_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
}
return;
}
case 0xAA: {
// left shift released
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LSHIFT,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.shift_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
}
return;
}
case 0xB6: {
// right shift released
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RSHIFT,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.shift_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
}
return;
}
case 0x38: {
// alt pressed
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LALT,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.l_alt_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
}
return;
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RALT,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.r_alt_state=SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
}
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
return;
}
break;
}
case 0xB8: {
// alt released
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_LALT,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.l_alt_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
}
return;
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_RALT,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.r_alt_state=SH_FALSE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
}
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
return;
}
break;
}
case 0xC5: {
// numlock released
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_NUMLOCK,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.numlock_state=ps2_state.numlock_state?SH_FALSE:SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_VER_NUM,ps2_state.numlock_state);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings numlock flags: status=%8s\n",status);
}
return;
}
case 0xBA: {
// capslock released
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_CAPSLOCK,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
ps2_state.capslock_state=ps2_state.capslock_state?SH_FALSE:SH_TRUE;
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_VER_MAJ,ps2_state.capslock_state);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error settings capslock flags: status=%8s\n",status);
}
return;
}
case 0x45: {
// numlock pressed
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_NUMLOCK,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
}
case 0x3A: {
// capslock pressed
sh_kbd_EVENT ev={
.scancode=SH_KBD_CONTEXT_CAPSLOCK,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
}
default: {
break;
}
}
}
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
if (data & (1u<<7)) {
sh_kbd_EVENT ev={
.scancode=0x0000|data,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_PS2_NORMAL,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
} else {
sh_kbd_EVENT ev={
.scancode=0x0000|data,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_PS2_NORMAL,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
}
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
if (data & (1u<<7)) {
sh_kbd_EVENT ev={
.scancode=0xE000|data,
.pressed=SH_FALSE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_PS2_E0,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
} else {
sh_kbd_EVENT ev={
.scancode=0xE000|data,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_PS2_E0,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
}
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E1) {
ps2_state.e1_bytes_array[ps2_state.e1_bytes_idx]=data;
ps2_state.e1_bytes_left--;
ps2_state.e1_bytes_idx++;
if (ps2_state.e1_bytes_idx==5 && ps2_state.e1_bytes_left==0) ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
sh_kbd_EVENT ev={
.scancode=0,
.pressed=SH_TRUE,
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
.event_type=SH_EVENT_TYPE_KBD_PAUSE,
.timestamp=sh_tsc_get_kernel_current_tsc()
};
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
if (sh_status_error(status)) {
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
}
return;
}
}
void sh_ps2_irq1_handler() {
sh_uint8 data;
if (!sh_ps2_output_ready()) return;
data=sh_asm_inb(SH_PS2_PORT_DATA);
ps2_state.last_byte=data;
if (ps2_state.command_in_progress) {
sh_ps2_handle_command_response(data);
return;
}
if (ps2_state.scanning_enabled) {
sh_ps2_handle_scancodes(data);
}
return;
}
SH_STATUS sh_ps2_driver_init() {
sh_asm_cli();
// flush output buffer
while (sh_ps2_output_ready()) {
sh_asm_inb(SH_PS2_PORT_DATA);
}
// debug log status and config byte
sh_printf(SH_DEBUG,"PS2 status byte initial value: 0x%1U\n",sh_ps2_read_status());
sh_printf(SH_DEBUG,"PS2 config byte initial value: 0x%1U\n",sh_ps2_read_config());
// disable ps2 ports
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_DISABLE);
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT2_DISABLE);
// reflush output buffer
while (sh_ps2_output_ready()) {
sh_asm_inb(SH_PS2_PORT_DATA);
}
// disable IRQs
sh_uint8 cfg=sh_ps2_read_config();
cfg&= (sh_uint8)~SH_PS2_CONFIG_PORT1_IRQ;
cfg&= (sh_uint8)~SH_PS2_CONFIG_PORT2_IRQ;
sh_ps2_write_config(cfg);
// ps2 self test
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PS2_SELF_TEST);
while (!sh_ps2_output_ready());
sh_uint8 result=sh_asm_inb(SH_PS2_PORT_DATA);
if (result!=SH_PS2_SELF_TEST_SUCCESS) return SH_STATUS_TEST_FAILED;
// port1 test
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_TEST);
while (!sh_ps2_output_ready());
result=sh_asm_inb(SH_PS2_PORT_DATA);
if (result!=SH_PS2_PORTS_SELF_TEST_SUCCESS) return SH_STATUS_TEST_FAILED;
// enable port1
while (sh_ps2_cant_write());
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_ENABLE);
// enable translation
cfg=sh_ps2_read_config();
cfg|=SH_PS2_CONFIG_TRANSLATION;
sh_ps2_write_config(cfg);
// initialize ps2_state struct
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
ps2_state.current_command.command=0;
ps2_state.current_command.data=0;
ps2_state.current_command.has_data=SH_FALSE;
ps2_state.last_byte=0;
ps2_state.e1_bytes_left=0;
ps2_state.command_in_progress=SH_FALSE;
ps2_state.keyboard_id[0]=0;
ps2_state.keyboard_id[1]=0;
ps2_state.keyboard_id_len=0;
ps2_state.shift_state=SH_FALSE;
ps2_state.l_alt_state=SH_FALSE;
ps2_state.r_alt_state=SH_FALSE;
ps2_state.l_ctrl_state=SH_FALSE;
ps2_state.r_ctrl_state=SH_FALSE;
ps2_state.win_state=SH_FALSE;
ps2_state.capslock_state=SH_FALSE;
ps2_state.numlock_state=SH_FALSE;
// enabling IRQ1
cfg=sh_ps2_read_config();
cfg|=(sh_uint8)SH_PS2_CONFIG_PORT1_IRQ;
sh_ps2_write_config(cfg);
SH_STATUS status=sh_irq_legacy_register_handler(1,&sh_ps2_irq1_handler);
if (sh_status_error(status)) return status;
sh_asm_sti();
// disabling scanning
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_DISABLE_SCANNING,0,SH_FALSE);
// set leds
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_SET_LEDS,0,SH_TRUE);
// identify keyboard
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_IDENTIFY,0,SH_FALSE);
sh_printf(SH_DEBUG,"PS2 identifier value : 0x%1U 0x%1U\n",ps2_state.keyboard_id[0],ps2_state.keyboard_id[1]);
// register ps2 keyboard
status=sh_kbd_register_ps2(SH_TRUE,&ps2_state.d_handle);
if (sh_status_error(status)) return status;
// enable scanning
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_ENABLE_SCANNING,0,SH_FALSE);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ps2_disable_scanning() {
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_DISABLE_SCANNING,0,SH_FALSE);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ps2_enable_scanning() {
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_ENABLE_SCANNING,0,SH_FALSE);
return SH_STATUS_SUCCESS;
}

83
shelter/lib/src/irq/gdt.c Normal file
View File

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MPL-2.0
#include "irq/gdt.h"
#include "cpu/asm.h"
sh_gdt_GDT_ENTRY_64 sh_gdt_fill_gdt_entry_64(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 flags) {
sh_gdt_GDT_ENTRY_64 entry;
entry.limit_low=(sh_uint16)(limit & 0xFFFF);
entry.base_low=(sh_uint16)(base & 0xFFFF);
entry.base_mid=(sh_uint8)((base>>16)&0xFF);
entry.access=access;
entry.flags_limit_high=(sh_uint8)(((flags&0xF)<<4)|((limit>>16)&0xF));
entry.base_high=(sh_uint8)((base>>24)&0xFF);
return entry;
}
sh_gdt_GDT_ENTRY_128 sh_gdt_fill_gdt_entry_128(sh_uint32 limit,sh_uint64 base,sh_uint8 access,sh_uint8 flags) {
sh_gdt_GDT_ENTRY_128 entry;
entry.limit_low=(sh_uint16)(limit&0xFFFF);
entry.base_low=(sh_uint16)(base&0xFFFF);
entry.base_mid=(sh_uint8)((base>>16)&0xFF);
entry.access=access;
entry.flags_limit_high=(sh_uint8)(((flags&0xF)<<4)|((limit>>16)&0xF));
entry.base_high=(sh_uint8)((base>>24)&0xFF);
entry.base_upper=(sh_uint32)((base>>32)&0xFFFFFFFF);
entry.reserved=0;
return entry;
}
SH_STATUS sh_gdt_fill_gdt(sh_tss_TSS *tss,sh_gdt_GDT *gdt) {
if (tss==SH_NULLPTR || gdt==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_mem_set_8((sh_uint8 *)gdt,0x0,sizeof(sh_gdt_GDT));
gdt->null=sh_gdt_fill_gdt_entry_64(0,0,0,0);
gdt->kernel_code=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,0,SH_TRUE,0xA),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_TRUE,SH_FALSE));
gdt->kernel_data=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,0,SH_TRUE,0x2),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_FALSE,SH_FALSE));
gdt->user_code=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,3,SH_TRUE,0xA),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_TRUE,SH_FALSE));
gdt->user_data=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,3,SH_TRUE,0x2),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_FALSE,SH_FALSE));
gdt->tss=sh_gdt_fill_gdt_entry_128(sizeof(sh_tss_TSS)-1,(sh_uint64)tss,sh_gdt_fill_access_byte(SH_TRUE,0,SH_FALSE,0x9),0);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_gdt_fill_gdt_ap(sh_tss_TSS *tss,sh_uint64 tss_count,sh_gdt_GDT_AP *gdt) {
if (tss==SH_NULLPTR || tss_count==0 || tss_count>256 || gdt==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_mem_set_8((sh_uint8 *)gdt,0x0,sizeof(sh_gdt_GDT));
gdt->null=sh_gdt_fill_gdt_entry_64(0,0,0,0);
gdt->kernel_code=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,0,SH_TRUE,0xA),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_TRUE,SH_FALSE));
gdt->kernel_data=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,0,SH_TRUE,0x2),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_FALSE,SH_FALSE));
gdt->user_code=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,3,SH_TRUE,0xA),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_TRUE,SH_FALSE));
gdt->user_data=sh_gdt_fill_gdt_entry_64(0,0,sh_gdt_fill_access_byte(SH_TRUE,3,SH_TRUE,0x2),sh_gdt_fill_flags_byte(SH_FALSE,SH_FALSE,SH_FALSE,SH_FALSE));
for (sh_iter64 i=0;i<tss_count;i++) {
gdt->tss[i]=sh_gdt_fill_gdt_entry_128(sizeof(sh_tss_TSS)-1,(sh_uint64)&tss[i],sh_gdt_fill_access_byte(SH_TRUE,0,SH_FALSE,0x9),0);
}
return SH_STATUS_SUCCESS;
}
sh_gdt_GDTR sh_gdt_make_gdtr_ap(sh_gdt_GDT_AP *gdt) {
if (gdt==SH_NULLPTR) return (sh_gdt_GDTR){0};
sh_gdt_GDTR gdtr;
gdtr.limit=(sh_uint16)(sizeof(sh_gdt_GDT_AP)-1);
gdtr.base=(sh_uint64)gdt;
return gdtr;
}
SH_STATUS sh_gdt_load_gdtr(sh_gdt_GDT *gdt) {
if (gdt==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_gdt_GDTR gdtr;
gdtr.limit=(sh_uint16)(sizeof(sh_gdt_GDT)-1);
gdtr.base=(sh_uint64)gdt;
sh_asm_lgdt(gdtr);
return SH_STATUS_SUCCESS;
}
extern SH_STATUS sh_gdt_reload_registers();
sh_gdt_GDT_ENTRY_32 sh_gdt_fill_gdt_entry_32(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 granularity) {
sh_gdt_GDT_ENTRY_32 entry;
entry.limit_low=limit&0xFFFF;
entry.base_low=base&0xFFFF;
entry.base_middle=(base>>16)&0xFF;
entry.base_high=(sh_uint8)(base>>24)&0xFF;
entry.access=access;
entry.granularity=(granularity&0xF0)|((limit>>16)&0x0F);
return entry;
}
SH_STATUS sh_gdt_fill_gdt_32(sh_gdt_GDT_32 *gdt_32){
if (!gdt_32) return SH_STATUS_INVALID_PARAMETER;
gdt_32->null=(sh_gdt_GDT_ENTRY_32){0};
gdt_32->code=sh_gdt_fill_gdt_entry_32(0xFFFFF,0x00000000,sh_gdt_fill_access_byte_32(SH_TRUE,0,SH_TRUE,0xA),sh_gdt_fill_granularity_byte_32(SH_TRUE,SH_TRUE,SH_FALSE,SH_FALSE));
gdt_32->data=sh_gdt_fill_gdt_entry_32(0xFFFFF,0x00000000,sh_gdt_fill_access_byte_32(SH_TRUE,0,SH_TRUE,0x2),sh_gdt_fill_granularity_byte_32(SH_TRUE,SH_TRUE,SH_FALSE,SH_FALSE));
gdt_32->code_64=sh_gdt_fill_gdt_entry_32(0xFFFFF,0x00000000,sh_gdt_fill_access_byte_32(SH_TRUE,0,SH_TRUE,0xA),sh_gdt_fill_granularity_byte_32(SH_TRUE,SH_FALSE,SH_TRUE,SH_FALSE));
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,21 @@
; SPDX-License-Identifier: MPL-2.0
global sh_gdt_reload_registers
section .text
sh_gdt_reload_registers:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
xor ax, ax
mov fs, ax
mov gs, ax
push 0x08
lea rax, [rel .reload]
push rax
retfq
.reload:
ret

182
shelter/lib/src/irq/gsi.c Normal file
View File

@@ -0,0 +1,182 @@
// SPDX-License-Identifier: MPL-2.0
#include "irq/gsi.h"
#include "irq/irq.h"
static sh_gsi_ISO *iso_array=SH_NULLPTR;
sh_uint16 bumb=0;
SH_STATUS sh_gsi_iso_array_init() {
iso_array=sh_malloc(sizeof(sh_gsi_ISO)*256);
if (!iso_array) return SH_STATUS_ERROR_NULLPTR_RETURNED;
bumb=0;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_gsi_iso_register(sh_uint8 bus,sh_uint8 source,sh_uint32 gsi,sh_uint16 flags) {
if (!iso_array) return SH_STATUS_UNAVAILABLE;
if (bumb>=256) return SH_STATUS_TOO_MUCH_DATA;
for (sh_uint16 i=0;i<bumb;i++) {
if (iso_array[i].valid && iso_array[i].source_irq==source) {
iso_array[i].bus=bus;
iso_array[i].gsi=gsi;
iso_array[i].source_irq=source;
switch (flags&0x3) {
case 0:
iso_array[i].polarity=SH_GSI_POLARITY_BUS_DEFAULT;
break;
case 1:
iso_array[i].polarity=SH_GSI_POLARITY_ACTIVE_HIGH;
break;
case 3:
iso_array[i].polarity=SH_GSI_POLARITY_ACTIVE_LOW;
break;
default:
iso_array[i].polarity=SH_GSI_POLARITY_BUS_DEFAULT;
break;
}
switch (flags&0xC) {
case 0:
iso_array[i].trigger_mode=SH_GSI_TRIGGER_MODE_BUS_DEFAULT;
break;
case 0x4:
iso_array[i].trigger_mode=SH_GSI_TRIGGER_MODE_EDGE;
break;
case 0xC:
iso_array[i].trigger_mode=SH_GSI_TRIGGER_MODE_LEVEL;
break;
default:
iso_array[i].trigger_mode=SH_GSI_TRIGGER_MODE_BUS_DEFAULT;
break;
}
iso_array[i].valid=SH_TRUE;
return SH_STATUS_SUCCESS;
}
}
sh_gsi_ISO *iso=&iso_array[bumb++];
iso->bus=bus;
iso->source_irq=source;
iso->gsi=gsi;
iso->valid=SH_TRUE;
switch (flags & 0x3) {
case 0:
iso->polarity=SH_GSI_POLARITY_BUS_DEFAULT;
break;
case 1:
iso->polarity=SH_GSI_POLARITY_ACTIVE_HIGH;
break;
case 3:
iso->polarity=SH_GSI_POLARITY_ACTIVE_LOW;
break;
default:
iso->polarity=SH_GSI_POLARITY_BUS_DEFAULT;
break;
}
switch (flags & 0xC) {
case 0:
iso->trigger_mode=SH_GSI_TRIGGER_MODE_BUS_DEFAULT;
break;
case 0x4:
iso->trigger_mode=SH_GSI_TRIGGER_MODE_EDGE;
break;
case 0xC:
iso->trigger_mode=SH_GSI_TRIGGER_MODE_LEVEL;
break;
default:
iso->trigger_mode=SH_GSI_TRIGGER_MODE_BUS_DEFAULT;
break;
}
return SH_STATUS_SUCCESS;
}
sh_gsi_ISO *sh_gsi_get_iso_by_irq(sh_uint8 irq) {
if (!iso_array) return SH_NULLPTR;
for (sh_uint16 i=0;i<bumb;i++) {
if (iso_array[i].valid && iso_array[i].source_irq==irq) return &iso_array[i];
}
return SH_NULLPTR;
}
sh_gsi_ISO *sh_gsi_get_iso_by_gsi(sh_uint32 gsi) {
if (!iso_array) return SH_NULLPTR;
for (sh_uint16 i=0;i<bumb;i++) {
if (iso_array[i].valid && iso_array[i].gsi==gsi) return &iso_array[i];
}
return SH_NULLPTR;
}
SH_STATUS sh_gsi_get(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
if (entry==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_ioapic_DEVICE *dev=sh_ioapic_get_dev_by_gsi(gsi);
if (!dev) return SH_STATUS_ERROR_NULLPTR_RETURNED;
SH_STATUS status=sh_ioapic_read_ioredtbl_entry(dev,gsi,entry);
return status;
}
SH_STATUS sh_gsi_set(sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
if (entry==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_ioapic_DEVICE *dev=sh_ioapic_get_dev_by_gsi(gsi);
if (!dev) return SH_STATUS_ERROR_NULLPTR_RETURNED;
SH_STATUS status=sh_ioapic_mask_gsi(dev,gsi);
if (sh_status_error(status)) return status;
status=sh_ioapic_write_ioredtbl_entry(dev,gsi,entry);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_gsi_irq_set(sh_uint8 irq,sh_ioapic_IOREDTBL_ENTRY *entry) {
if (!entry) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 gsi=irq;
sh_gsi_ISO *iso=sh_gsi_get_iso_by_irq((sh_uint8)irq);
if (iso && iso->valid) {
gsi=iso->gsi;
}
return sh_gsi_set(gsi,entry);
}
SH_STATUS sh_gsi_irq_mask(sh_uint8 irq) {
sh_uint32 gsi=irq;
sh_gsi_ISO *iso=sh_gsi_get_iso_by_irq(irq);
if (iso && iso->valid) {
gsi=iso->gsi;
}
return sh_gsi_mask(gsi);
}
SH_STATUS sh_gsi_irq_unmask(sh_uint8 irq) {
sh_uint32 gsi=irq;
sh_gsi_ISO *iso=sh_gsi_get_iso_by_irq(irq);
if (iso && iso->valid) {
gsi=iso->gsi;
}
return sh_gsi_unmask(gsi);
}
SH_STATUS sh_gsi_irq_switch() {
sh_bool gsi_already_used[256]={0};
for (sh_iter64 i=0;i<16;i++) {
sh_ioapic_IOREDTBL_ENTRY entry={0};
sh_gsi_ISO *iso=sh_gsi_get_iso_by_irq((sh_uint8)i);
sh_uint32 gsi=(sh_uint32)i;
sh_uint8 polarity=SH_IOAPIC_IOREDTBL_POLARITY_HIGH;
sh_uint8 trigger_mode=SH_IOAPIC_IOREDTBL_TRIGGER_EDGE;
if (iso && iso->valid) {
gsi=iso->gsi;
if (iso->polarity==SH_GSI_POLARITY_ACTIVE_LOW) {
polarity=SH_IOAPIC_IOREDTBL_POLARITY_LOW;
} else if (iso->polarity==SH_GSI_POLARITY_BUS_DEFAULT) {
if (iso->bus==0) {
polarity=SH_IOAPIC_IOREDTBL_POLARITY_HIGH;
} else {
return SH_STATUS_ISO_UNKNOW_BUS;
}
}
if (iso->trigger_mode==SH_GSI_TRIGGER_MODE_LEVEL) {
trigger_mode=SH_IOAPIC_IOREDTBL_TRIGGER_LEVEL;
} else if (iso->trigger_mode==SH_GSI_TRIGGER_MODE_BUS_DEFAULT) {
if (iso->bus==0) {
trigger_mode=SH_IOAPIC_IOREDTBL_TRIGGER_EDGE;
} else {
return SH_STATUS_ISO_UNKNOW_BUS;
}
}
}
if (gsi_already_used[gsi]) continue;
entry=sh_ioapic_make_ioredtbl_entry((sh_uint8)i+32,SH_IOAPIC_IOREDTBL_DELIVERY_FIXED,SH_IOAPIC_IOREDTBL_DEST_MODE_PHYSICAL,polarity,trigger_mode,SH_TRUE,0);
SH_STATUS status=sh_gsi_irq_set((sh_uint8)i,&entry);
if (sh_status_error(status)) return status;
gsi_already_used[gsi]=SH_TRUE;
sh_gsi_irq_mask((sh_uint8)i);
}
SH_STATUS status=sh_irq_switch_irq_management();
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}

109
shelter/lib/src/irq/idt.c Normal file
View File

@@ -0,0 +1,109 @@
// SPDX-License-Identifier: MPL-2.0
#include "irq/idt.h"
#include "cpu/asm.h"
sh_idt_IDT_ENTRY sh_idt_fill_idt_entry(sh_uint64 offset,sh_uint16 selector,sh_uint8 ist,sh_uint8 type_attr) {
sh_idt_IDT_ENTRY entry;
entry.offset_low=(sh_uint16)(offset&0xFFFF);
entry.selector=selector;
entry.ist=(sh_uint8)(ist&0x7);
entry.type_attr=type_attr;
entry.offset_mid=(sh_uint16)((offset>>16)&0xFFFF);
entry.offset_high=(sh_uint32)((offset>>32)&0xFFFFFFFF);
entry.reserved=0;
return entry;
}
extern void sh_irq_noerr_0(void);
extern void sh_irq_noerr_1(void);
extern void sh_irq_noerr_2(void);
extern void sh_irq_noerr_3(void);
extern void sh_irq_noerr_4(void);
extern void sh_irq_noerr_5(void);
extern void sh_irq_noerr_6(void);
extern void sh_irq_noerr_7(void);
extern void sh_irq_err_8(void);
extern void sh_irq_noerr_9(void);
extern void sh_irq_err_10(void);
extern void sh_irq_err_11(void);
extern void sh_irq_err_12(void);
extern void sh_irq_err_13(void);
extern void sh_irq_err_14(void);
extern void sh_irq_noerr_16(void);
extern void sh_irq_err_17(void);
extern void sh_irq_noerr_18(void);
extern void sh_irq_noerr_19(void);
extern void sh_irq_noerr_20(void);
extern void sh_irq_err_21(void);
extern void sh_irq_noerr_28(void);
extern void sh_irq_err_29(void);
extern void sh_irq_err_30(void);
extern void sh_irq_noerr_32(void);
extern void sh_irq_noerr_33(void);
extern void sh_irq_noerr_34(void);
extern void sh_irq_noerr_35(void);
extern void sh_irq_noerr_36(void);
extern void sh_irq_noerr_37(void);
extern void sh_irq_noerr_38(void);
extern void sh_irq_noerr_39(void);
extern void sh_irq_noerr_40(void);
extern void sh_irq_noerr_41(void);
extern void sh_irq_noerr_42(void);
extern void sh_irq_noerr_43(void);
extern void sh_irq_noerr_44(void);
extern void sh_irq_noerr_45(void);
extern void sh_irq_noerr_46(void);
extern void sh_irq_noerr_47(void);
extern void sh_irq_noerr_254(void);
extern void sh_irq_noerr_255(void);
SH_STATUS sh_idt_fill_idt(sh_idt_IDT *idt) {
idt->entries[0]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_0,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[1]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_1,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[2]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_2,0x08,2,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[3]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_3,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xF));
idt->entries[4]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_4,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xF));
idt->entries[5]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_5,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[6]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_6,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[7]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_7,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[8]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_8,0x08,1,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[9]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_9,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[10]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_10,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[11]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_11,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[12]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_12,0x08,4,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[13]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_13,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[14]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_14,0x08,3,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[16]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_16,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[17]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_17,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[18]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_18,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[19]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_19,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[20]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_20,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[21]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_21,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[28]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_28,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[29]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_29,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[30]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_err_30,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[32]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_32,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[33]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_33,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[34]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_34,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[35]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_35,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[36]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_36,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[37]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_37,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[38]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_38,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[39]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_39,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[40]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_40,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[41]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_41,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[42]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_42,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[43]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_43,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[44]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_44,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[45]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_45,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[46]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_46,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[47]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_47,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[254]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_254,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
idt->entries[255]=sh_idt_fill_idt_entry((sh_uint64)sh_irq_noerr_255,0x08,0,sh_idt_fill_type_attr_byte(SH_TRUE,0,0xE));
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_idt_load_idtr(sh_idt_IDT *idt) {
if (idt==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_idt_IDTR idtr;
idtr.limit=(sh_uint16)(sizeof(sh_idt_IDT)-1);
idtr.base=(sh_uint64)idt;
sh_asm_lidt(idtr);
return SH_STATUS_SUCCESS;
}

243
shelter/lib/src/irq/irq.c Normal file
View File

@@ -0,0 +1,243 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/stdlib.h"
#include "irq/irq.h"
#include "irq/gsi.h"
#include "devs/apic/lapic.h"
#include "cpu/pic.h"
sh_uint64 tsc_delta;
sh_uint64 tsc_start;
sh_uint64 tsc_end;
sh_uint8 tsc_state=2;
sh_bool irq_managed_by_ioapic=SH_FALSE;
sh_irq_HANDLER_PTR *legacy_irq_handler_array;
sh_SPIN_LOCK frame_presentation_lock=SH_LOCK();
void sh_irq_start_tsc() {
tsc_delta=0;
tsc_start=0;
tsc_end=0;
tsc_state=0;
}
sh_uint64 sh_irq_get_tsc_delta() {
return tsc_delta;
}
void sh_irq_start_timer() {
sh_smp_gs_base()->per_cpu->timer_state=SH_TRUE;
return;
}
sh_bool sh_irq_get_timer_state() {
return sh_smp_gs_base()->per_cpu->timer_state;
}
SH_STATUS sh_irq_switch_irq_management() {
if (irq_managed_by_ioapic) return SH_STATUS_ALREADY_INITIALIZED;
irq_managed_by_ioapic=SH_TRUE;
legacy_irq_handler_array=sh_malloc(sizeof(sh_irq_HANDLER_PTR)*16);
if (!legacy_irq_handler_array) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)legacy_irq_handler_array,0x0,sizeof(sh_irq_HANDLER_PTR)*16);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_irq_legacy_register_handler(sh_uint8 legacy_irq,sh_irq_HANDLER_PTR handler) {
if (legacy_irq>15 || handler==SH_NULLPTR || legacy_irq==0) return SH_STATUS_INVALID_PARAMETER;
if (legacy_irq_handler_array==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (legacy_irq_handler_array[legacy_irq]!=SH_NULLPTR) return SH_STATUS_ALREADY_INITIALIZED;
legacy_irq_handler_array[legacy_irq]=handler;
SH_STATUS status=sh_gsi_irq_unmask(legacy_irq);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
void sh_irq_present_frame(sh_irq_INTERRUPT_FRAME *frame) {
sh_spin_lock(&frame_presentation_lock);
if (frame->error_code) {
sh_iprintf(SH_FAULT,"IDT Entry Index (vector): %8u | Error code: %8u\n",frame->vector,frame->error_code);
} else {
sh_iprintf(SH_FAULT,"IDT Entry Index (vector): %8u | No error code provided.\n",frame->vector);
}
sh_iprintf(SH_FAULT,"RIP: 0x%x | R8 : 0x%x\n",frame->rip,frame->r8);
sh_iprintf(SH_FAULT,"RAX: 0x%x | R9 : 0x%x\n",frame->rax,frame->r9);
sh_iprintf(SH_FAULT,"RCX: 0x%x | R10: 0x%x\n",frame->rcx,frame->r10);
sh_iprintf(SH_FAULT,"RDX: 0x%x | R11: 0x%x\n",frame->rdx,frame->r11);
sh_iprintf(SH_FAULT,"CS : 0x%x | RFLAGS: 0x%x\n",frame->cs,frame->rflags);
sh_spin_unlock(&frame_presentation_lock);
return;
}
void sh_irq_dispatch(sh_irq_INTERRUPT_FRAME *frame) {
switch (frame->vector) {
case 0:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_DIV_BY_ZERO_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 1:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_DEBUG_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 2:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_NMI_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 3:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_BREAKPOINT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
// usage of breakpoints is authorized
break;
case 4:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_OVERFLOW_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 5:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_BOUND_RANGE_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 6:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_INVALID_OPCODE_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 7:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_DEVICE_NOT_AVAILABLE_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 8:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_DOUBLE_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 9:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_COPROCESSOR_SEGMENT_OVRERRUN_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 10:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_INVALID_TSS_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 11:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_SEGMENT_NOT_PRESENT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 12:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_STACK_SEGMENT_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 13:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_GENERAL_PROTECTION_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 14:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_PAGE_FAULT_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 16:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_X87_FLOATING_POINT_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 17:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_ALIGNMENT_CHECK_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 18:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_MACHINE_CHECK_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 19:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_SIMD_FLOATING_POINT_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 20:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_VIRTUALIZATION_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 21:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_CONTROL_PROTECTION_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 28:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_HYPERVISOR_INJECTION_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 29:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_VMM_COMMUNICATION_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 30:
sh_iprintf(SH_FAULT,"CPU Fault Hapenned: %s\n",SH_IRQ_SECURITY_EXCEPTION_STRING);
if (frame->vector<32) sh_irq_present_frame(frame);
while (SH_TRUE) {};
break;
case 32:
if (frame->vector<32) sh_irq_present_frame(frame);
if (irq_managed_by_ioapic) {
sh_iprint(SH_LOG,"Interrupt: PIT timer outside of TSC frequency estimation, managed by IOAPIC.\n");
sh_lapic_eoi(sh_lapic_get_dev_apic_id((sh_uint64)sh_smp_gs_base()->lapic_id));
break;
} else {
if (tsc_state==0) {
tsc_start=sh_tsc_read_tsc();
tsc_state++;
} else if (tsc_state==1) {
tsc_end=sh_tsc_read_tsc();
tsc_delta=tsc_end-tsc_start;
tsc_state=2;
} else {
sh_iprint(SH_LOG,"Interrupt: PIT timer outside of TSC frequency estimation.\n");
}
sh_pic_send_eoi(0);
}
break;
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
if (frame->vector<32) sh_irq_present_frame(frame);
if (irq_managed_by_ioapic) {
if (legacy_irq_handler_array[frame->vector-32]!=SH_NULLPTR) {
legacy_irq_handler_array[frame->vector-32]();
sh_lapic_eoi(sh_lapic_get_dev_apic_id((sh_uint64)sh_smp_gs_base()->lapic_id));
} else {
sh_lapic_eoi(sh_lapic_get_dev_apic_id((sh_uint64)sh_smp_gs_base()->lapic_id));
}
break;
} else {
sh_iprintf(SH_LOG,"Interrupt: received interrupt on vector %1u, legacy IRQ not managed by IOAPIC.\n",frame->vector);
while (SH_TRUE) {};
}
case 254:
if (sh_smp_gs_base()->per_cpu->timer_state==SH_FALSE) sh_iprint(SH_LOG,"Interrupt: LAPIC One Shot Timer finished");
if (frame->vector<32) sh_irq_present_frame(frame);
if (sh_smp_gs_base()->per_cpu->timer_state==SH_TRUE) sh_smp_gs_base()->per_cpu->timer_state=SH_FALSE;
sh_lapic_eoi(sh_lapic_get_dev_apic_id(sh_smp_gs_base()->lapic_id));
break;
case 255:
sh_iprint(SH_LOG,"Interrupt: Spurious vector");
if (frame->vector<32) sh_irq_present_frame(frame);
break;
}
}

View File

@@ -0,0 +1,86 @@
; SPDX-License-Identifier: MPL-2.0
global sh_irq_common_stub
extern sh_irq_dispatch
%macro SH_IRQ_NOERR 1
global sh_irq_noerr_%1
sh_irq_noerr_%1:
push 0 ; fake error code
push %1 ; vector
jmp sh_irq_common_stub
%endmacro
%macro SH_IRQ_ERR 1
global sh_irq_err_%1
sh_irq_err_%1:
push %1 ; vector (CPU already pushed error code)
jmp sh_irq_common_stub
%endmacro
SH_IRQ_NOERR 0 ; div by zero
SH_IRQ_NOERR 1 ; debug
SH_IRQ_NOERR 2 ; nmi
SH_IRQ_NOERR 3 ; breakpoint
SH_IRQ_NOERR 4 ; overflow
SH_IRQ_NOERR 5 ; bound range exceeded
SH_IRQ_NOERR 6 ; invalid opcode
SH_IRQ_NOERR 7 ; device not available
SH_IRQ_ERR 8 ; double fault
SH_IRQ_NOERR 9 ; coprocessor segment overrun
SH_IRQ_ERR 10 ; invalid tss
SH_IRQ_ERR 11 ; segment not present
SH_IRQ_ERR 12 ; stack segment fault
SH_IRQ_ERR 13 ; general protection fault
SH_IRQ_ERR 14 ; page fault
SH_IRQ_NOERR 16 ; x87 floating point exception
SH_IRQ_ERR 17 ; alignment check
SH_IRQ_NOERR 18 ; machine check
SH_IRQ_NOERR 19 ; simd floating point exception
SH_IRQ_NOERR 20 ; virtualization exception
SH_IRQ_ERR 21 ; control protection exception
SH_IRQ_NOERR 28 ; hypervisor injection exception
SH_IRQ_ERR 29 ; vmm communication exception
SH_IRQ_ERR 30 ; security exception
SH_IRQ_NOERR 32 ; PIC IRQ0 aka PIT tick
SH_IRQ_NOERR 33 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 34 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 35 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 36 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 37 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 38 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 39 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 40 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 41 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 42 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 43 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 44 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 45 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 46 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 47 ; IOAPIC legacy IRQ
SH_IRQ_NOERR 254 ; lapic one shot timer vector
SH_IRQ_NOERR 255 ; spurious vector for lapic
section .text
sh_irq_common_stub:
push rax
push rcx
push rdx
push r8
push r9
push r10
push r11
mov rdi, rsp
call sh_irq_dispatch
pop r11
pop r10
pop r9
pop r8
pop rdx
pop rcx
pop rax
add rsp, 16
iretq

30
shelter/lib/src/irq/tss.c Normal file
View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MPL-2.0
#include "irq/tss.h"
#include "cpu/asm.h"
SH_STATUS sh_tss_fill_tss(sh_tss_TSS *tss) {
if (tss==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_mem_set_8((sh_uint8*)tss,0x0,sizeof(sh_tss_TSS));
void* rsp0=sh_malloc(4096*4);
if (!rsp0) return SH_STATUS_ERROR_NULLPTR_RETURNED;
tss->rsp0=(sh_uint64)rsp0+4096*4;
void* double_fault=sh_malloc(4096*4);
if (!double_fault) return SH_STATUS_ERROR_NULLPTR_RETURNED;
tss->ist1=(sh_uint64)double_fault+4096*4;
void* nmi_fault=sh_malloc(4096*4);
if (!nmi_fault) return SH_STATUS_ERROR_NULLPTR_RETURNED;
tss->ist2=(sh_uint64)nmi_fault+4096*4;
void* page_fault=sh_malloc(4096*4);
if (!page_fault) return SH_STATUS_ERROR_NULLPTR_RETURNED;
tss->ist3=(sh_uint64)page_fault+4096*4;
void* ss_fault=sh_malloc(4096*4);
if (!ss_fault) return SH_STATUS_ERROR_NULLPTR_RETURNED;
tss->ist4=(sh_uint64)ss_fault+4096*4;
tss->iomap_base=sizeof(*tss);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_tss_load_tr(sh_tss_TSS *tss) {
if (tss==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 tss_selector=0x28;
sh_asm_ltr(tss_selector);
return SH_STATUS_SUCCESS;
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/conf.h"
#include "kernel/log.h"
#include "std/mem.h"
sh_conf_BOOT_CONFIG boot_config;
SH_STATUS sh_conf_get_boot_config(sh_conf_BOOT_CONFIG **config) {
if (config==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
@@ -15,5 +15,54 @@ SH_STATUS sh_conf_get_boot_config(sh_conf_BOOT_CONFIG **config) {
if (sh_mem_compare((*config)->sig_end,sig_end,sizeof(sig_end))==SH_STATUS_MEM_NOT_EQUAL) {
return SH_STATUS_INVALID_SIGNATURE;
}
sh_mem_copy((sh_uint8*)&boot_config,(sh_uint8*)*config,sizeof(sh_conf_BOOT_CONFIG));
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_conf_devs_query(char *sub_path,sh_devs_RESULT *result) {
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(sub_path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (sh_string_compare(sub_path,"/log-level",10)) {
if (path_len==10) {
result->type=SH_DEVS_VALUE;
result->value=boot_config.log_level;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/test-benchmark",15)) {
if (path_len==15) {
result->type=SH_DEVS_BOOL;
result->value=boot_config.test_benchmark;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/bench-iterations",17)) {
if (path_len==17) {
result->type=SH_DEVS_VALUE;
result->value=boot_config.bench_iterations;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/disable-serial-port",20)) {
if (path_len==20) {
result->type=SH_DEVS_BOOL;
result->value=boot_config.disable_serial_port;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/kbd-events-queue-capacity",26)) {
if (path_len==26) {
result->type=SH_DEVS_VALUE;
result->value=boot_config.kbd_events_queue_capacity;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
}

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/efifb.h"
sh_uint32 fb_height=0;
sh_uint32 fb_width=0;
sh_uint32 fb_size_bytes=0;
sh_uint32 fb_white=0;
sh_uint32 fb_gray=0;
sh_bool fb_present=SH_FALSE;
sh_uint32 *fb_base=SH_NULLPTR;
sh_uint16 bar_x0=0;
sh_uint16 bar_y0=0;
sh_uint16 bar_x1=0;
sh_uint16 bar_y1=0;
static SH_STATUS sh_efifb_fill_rectangle(sh_uint32 x,sh_uint32 y,sh_uint32 width,sh_uint32 height,sh_uint32 pixel_value) {
if (fb_base==SH_NULLPTR) return SH_STATUS_VA_NOT_MAPPED;
sh_uint32 end_x=x+width;
sh_uint32 end_y=y+height;
if (x>=fb_width || y>=fb_height) return SH_STATUS_BAD_SIZE;
if (end_x>fb_width) end_x=fb_width;
if (end_y>fb_height) end_y=fb_height;
for (sh_uint32 curr_y=y;curr_y<end_y;curr_y++) {
sh_uint32 *line=fb_base+(curr_y*fb_width);
for (sh_uint32 curr_x=x;curr_x<end_x;curr_x++) {
line[curr_x]=pixel_value;
}
}
return SH_STATUS_SUCCESS;
}
static void sh_efifb_draw_rounded_bar(sh_uint32 x0,sh_uint32 y0,sh_uint32 x1,sh_uint32 y1,sh_uint32 r,sh_uint32 color) {
if (x1-x0<=r*2) {
x1=x0+r*2;
}
for (sh_uint32 y=y0;y<=y1;y++) {
for (sh_uint32 x=x0;x<=x1;x++) {
sh_bool in_rect=(x>=x0+r && x<=x1-r);
if (in_rect) {
fb_base[fb_width*y+x]=color;
continue;
}
sh_uint32 cxL=x0+r;
sh_uint32 cy=y0+r;
sh_uint32 cxR=x1-r;
sh_uint32 dx,dy;
dx=x-cxL;
dy=y-cy;
if (dx*dx+dy*dy<=r*r) {
fb_base[fb_width*y+x]=color;
continue;
}
dx=x-cxR;
dy=y-cy;
if (dx*dx+dy*dy<=r*r) {
fb_base[fb_width*y+x]=color;
continue;
}
}
}
}
SH_STATUS sh_efifb_init_fb(sh_conf_FB_CONFIG *fb_conf,sh_page_PAGE_TABLE_POOL *ptp) {
if (fb_conf==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (!fb_conf->fb_present) return SH_STATUS_SUCCESS;
fb_height=fb_conf->fb_height;
fb_width=fb_conf->fb_width;
fb_size_bytes=fb_width*fb_height*sizeof(sh_uint32);
if (fb_size_bytes!=fb_conf->size_in_bytes) return SH_STATUS_BAD_SIZE;
SH_STATUS status=sh_page_map_contiguous_pages_range_ptp(ptp,fb_conf->fb_pa,fb_conf->fb_pa,SH_PAGE_PRESENT | SH_PAGE_RW | SH_PAGE_NX | SH_PAGE_PCD,(((fb_size_bytes+4096)/4096)*4096));
if (sh_status_error(status)) return status;
fb_white=fb_conf->white_pixel_value;
fb_gray=fb_conf->gray_pixel_value;
fb_base=(sh_uint32*)fb_conf->fb_pa;
fb_present=SH_TRUE;
status=sh_efifb_fill_rectangle(fb_conf->text_x,fb_conf->text_y,fb_conf->text_width,fb_conf->text_height,0);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_efifb_init_bar() {
if (!fb_present) return SH_STATUS_SUCCESS;
bar_x0=(sh_uint16)(fb_width*0.3);
bar_x1=(sh_uint16)(fb_width-bar_x0);
bar_y0=(sh_uint16)(fb_height*0.93);
bar_y1=(sh_uint16)(fb_height*0.96);
sh_efifb_draw_rounded_bar(bar_x0,bar_y0,bar_x1,bar_y1,(bar_y1-bar_y0)/2U,fb_gray);
sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_x1-3,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,0);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_efifb_set_bar(sh_uint8 percent) {
if (!fb_present) return SH_STATUS_SUCCESS;
sh_uint16 bar_width=(sh_uint16)((bar_x1-3U)-(bar_x0+3U));
sh_uint16 bar_percent=(sh_uint16)(((double)percent/100)*(double)(bar_width));
sh_uint16 bar_xp=(sh_uint16)(bar_x0+3U+bar_percent);
sh_efifb_fill_rectangle(bar_x0,bar_y0,(bar_x1-bar_x0),(bar_y1-bar_y0),0);
sh_efifb_draw_rounded_bar(bar_x0,bar_y0,bar_x1,bar_y1,(bar_y1-bar_y0)/2U,fb_gray);
sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_x1-3,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,0);
sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_xp,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,fb_white);
return SH_STATUS_SUCCESS;
}

View File

@@ -5,6 +5,7 @@
#include "cpu/serial.h"
sh_uint8 kernel_log_level=0;
sh_bool log_disable_serial_port=SH_FALSE;
sh_bool disable_global_logging_ring=SH_FALSE;
sh_ring_RING_BUFFER_HEADER logging_ring={.head=0,.tail=0,.buffer_bytes_size=4*4096,.data_start=(sh_uint8*)SH_VMEM_LAYOUT_LOGGING_RING_BUFFER_VA,.total_bytes_written=0};
void sh_log_load_serial_setting(sh_bool is_disabled) {
log_disable_serial_port=is_disabled;
@@ -23,10 +24,13 @@ sh_uint32 sh_log_get_logging_ring_size() {
sh_uint64 sh_log_get_total_bytes_written() {
return logging_ring.total_bytes_written;
}
void sh_log_disable_global_logging_ring() {
disable_global_logging_ring=SH_TRUE;
}
void sh_log_byte(sh_uint8 byte) {
if (log_disable_serial_port) return;
sh_serial_send_byte(byte);
sh_ring_write_byte(&logging_ring,(sh_uint8)byte);
if (!disable_global_logging_ring) sh_ring_write_byte(&logging_ring,(sh_uint8)byte);
return;
}
SH_STATUS sh_log_string(const char* str) {
@@ -254,6 +258,16 @@ SH_STATUS sh_log_payload(sh_log_OUTPUT_PAYLOAD *payload) {
sh_log_string("Heap@");
} else if (payload->output_source==SH_LOG_SOURCE_STD) {
sh_log_string("STD @");
} else if (payload->output_source==SH_LOG_SOURCE_MEMS) {
sh_log_string("MemS@");
} else if (payload->output_source==SH_LOG_SOURCE_CPUF) {
sh_log_string("CpuF@");
} else if (payload->output_source==SH_LOG_SOURCE_ACPI) {
sh_log_string("ACPI@");
} else if (payload->output_source==SH_LOG_SOURCE_TSC) {
sh_log_string("TSC @");
} else if (payload->output_source==SH_LOG_SOURCE_SMP) {
sh_log_string("SMP @");
}
if (payload->output_type==SH_LOG_DEBUG) {
sh_log_string("Debug] ");
@@ -269,6 +283,8 @@ SH_STATUS sh_log_payload(sh_log_OUTPUT_PAYLOAD *payload) {
sh_log_string("Fatal] ");
} else if (payload->output_type==SH_LOG_TEST) {
sh_log_string("Test] ");
} else if (payload->output_type==SH_LOG_FAULT) {
sh_log_string("Fault] ");
}
sh_log_uint64(payload->tsc_value);
sh_log_string(" : ");
@@ -307,6 +323,16 @@ SH_STATUS sh_log_payload_format(sh_log_OUTPUT_PAYLOAD *payload,va_list args) {
sh_log_string("Heap@");
} else if (payload->output_source==SH_LOG_SOURCE_STD) {
sh_log_string("STD @");
} else if (payload->output_source==SH_LOG_SOURCE_MEMS) {
sh_log_string("MemS@");
} else if (payload->output_source==SH_LOG_SOURCE_CPUF) {
sh_log_string("CpuF@");
} else if (payload->output_source==SH_LOG_SOURCE_ACPI) {
sh_log_string("ACPI@");
} else if (payload->output_source==SH_LOG_SOURCE_TSC) {
sh_log_string("TSC @");
} else if (payload->output_source==SH_LOG_SOURCE_SMP) {
sh_log_string("SMP @");
}
if (payload->output_type==SH_LOG_DEBUG) {
sh_log_string("Debug] ");
@@ -322,6 +348,8 @@ SH_STATUS sh_log_payload_format(sh_log_OUTPUT_PAYLOAD *payload,va_list args) {
sh_log_string("Fatal] ");
} else if (payload->output_type==SH_LOG_TEST) {
sh_log_string("Test] ");
} else if (payload->output_type==SH_LOG_FAULT) {
sh_log_string("Fault] ");
}
sh_log_uint64(payload->tsc_value);
sh_log_string(" : ");
@@ -454,6 +482,23 @@ SH_STATUS sh_log_fatal(const char* str,sh_log_OUTPUT_SOURCE source) {
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_fault(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FAULT,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ltest(const char* str) {
if (str==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
@@ -566,6 +611,22 @@ SH_STATUS sh_log_lfatal(const char* str,sh_log_OUTPUT_SOURCE source) {
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_lfault(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FAULT,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ftest(const char* format,...) {
if (format==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
@@ -699,6 +760,25 @@ SH_STATUS sh_log_ffatal(const sh_log_OUTPUT_SOURCE source,const char* format,...
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ffault(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FAULT,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_mem_stats(sh_log_OUTPUT_SOURCE source) {
sh_page_MEM_STATS mem_stats;
sh_page_get_memory_stats(&mem_stats);

View File

@@ -4,7 +4,6 @@
#include "kernel/tests/payloads/test_malloc_payload.h"
#include "kernel/log.h"
#include "memory/page.h"
#include "memory/heap.h"
#include "std/mem.h"
#include "std/malloc.h"
static sh_uint64 iter_num=10000;
@@ -30,7 +29,7 @@ SH_STATUS sh_test_malloc_benchmark() {
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("sh_malloc for small size",tsc_value,iter_num);
sh_test_compute_print_stats("sh_malloc for small size",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,10000*sizeof(sh_tsc_TSC_VALUE));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
@@ -45,7 +44,7 @@ SH_STATUS sh_test_malloc_benchmark() {
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("sh_free for small size",tsc_value,iter_num);
sh_test_compute_print_stats("sh_free for small size",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,10000*sizeof(sh_tsc_TSC_VALUE));
sh_mem_set_8((sh_uint8*)address_list,0x00,sizeof(address_list));
sh_uint16 alloc_count=0;
@@ -85,8 +84,8 @@ SH_STATUS sh_test_malloc_benchmark() {
}
}
}
sh_test_compute_print_stats("sh_malloc for pages allocations",tsc_value,alloc_count);
sh_test_compute_print_stats("sh_free for pages allocations",tsc_value+1000,free_count-1000);
sh_test_compute_print_stats("sh_malloc for pages allocations",tsc_value,alloc_count,SH_FALSE);
sh_test_compute_print_stats("sh_free for pages allocations",tsc_value+1000,free_count-1000,SH_FALSE);
sh_log_mem_stats(SH_LOG_SOURCE_TEST);
return SH_STATUS_SUCCESS;
}

View File

@@ -69,9 +69,9 @@ SH_STATUS sh_test_pez_benchmark_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
}
}
}
sh_test_compute_print_stats("allocations for single page",tsc_value,alloc_single_count);
sh_test_compute_print_stats("free for single page",tsc_value+1000,unalloc_single_count-1000);
sh_test_compute_print_stats("allocations for multiple pages",tsc_value+2000,alloc_multiple_count-2000);
sh_test_compute_print_stats("free for multiple pages",tsc_value+3000,unalloc_multiple_count-3000);
sh_test_compute_print_stats("allocations for single page",tsc_value,alloc_single_count,SH_FALSE);
sh_test_compute_print_stats("free for single page",tsc_value+1000,unalloc_single_count-1000,SH_FALSE);
sh_test_compute_print_stats("allocations for multiple pages",tsc_value+2000,alloc_multiple_count-2000,SH_FALSE);
sh_test_compute_print_stats("free for multiple pages",tsc_value+3000,unalloc_multiple_count-3000,SH_FALSE);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_queues.h"
#include "kernel/tests/test_utils.h"
#include "std/mem.h"
#include "std/print.h"
#include "std/queue.h"
SH_STATUS sh_test_benchmark_queues() {
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(sh_tsc_TSC_VALUE)*10000);
sh_print(SH_TEST,"Benchmarking keyboard events queues...\n");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
SH_STATUS status;
sh_queue_KBD_EVENT queue;
status=sh_queue_event_init(&queue,4096);
if (sh_status_error(status)) {
sh_print(SH_TEST,"Test failed for initialization of queue. See detail below:\n");
sh_printf(SH_TEST,"Error code: %8s\n",status);
}
for (sh_iter64 i=0;i<10000;i++) {
sh_kbd_EVENT event={.timestamp=i};
start=sh_tsc_get_kernel_current_tsc();
status=sh_queue_event_push(&queue,event);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_print(SH_ERROR,"Test failed for pushing objects on queue. See detail below:\n");
sh_printf(SH_ERROR,"Error code: %8s\n",status);
sh_printf(SH_ERROR,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("pushing objects",tsc_value,10000,SH_TRUE);
return SH_STATUS_SUCCESS;
}

View File

@@ -35,7 +35,7 @@ SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *allo
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("insertions into radix trees",tsc_value,iter_num);
sh_test_compute_print_stats("insertions into radix trees",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
sh_page_VIRTUAL_ADDRESS temp;
@@ -58,7 +58,7 @@ SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *allo
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("reading into radix trees",tsc_value,iter_num);
sh_test_compute_print_stats("reading into radix trees",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
sh_page_VIRTUAL_ADDRESS temp;
@@ -73,7 +73,7 @@ SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *allo
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("searching value with lower bound key",tsc_value,iter_num);
sh_test_compute_print_stats("searching value with lower bound key",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
@@ -87,6 +87,6 @@ SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *allo
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deleting values",tsc_value,iter_num);
sh_test_compute_print_stats("deleting values",tsc_value,iter_num,SH_FALSE);
return SH_STATUS_SUCCESS;
}

View File

@@ -36,7 +36,7 @@ SH_STATUS sh_test_slabs_benchmark_region_physical(sh_slab_reg_phys_SLAB_ALLOCATO
indexs[i]=reg_idx;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_test_compute_print_stats("allocations",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
@@ -50,7 +50,7 @@ SH_STATUS sh_test_slabs_benchmark_region_physical(sh_slab_reg_phys_SLAB_ALLOCATO
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
sh_test_compute_print_stats("deallocations",tsc_value,iter_num,SH_FALSE);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark_region_virtual(sh_slab_reg_virt_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
@@ -77,7 +77,7 @@ SH_STATUS sh_test_slabs_benchmark_region_virtual(sh_slab_reg_virt_SLAB_ALLOCATOR
indexs[i]=reg_idx;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_test_compute_print_stats("allocations",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
@@ -91,7 +91,7 @@ SH_STATUS sh_test_slabs_benchmark_region_virtual(sh_slab_reg_virt_SLAB_ALLOCATOR
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
sh_test_compute_print_stats("deallocations",tsc_value,iter_num,SH_FALSE);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark_radix_node(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
@@ -118,7 +118,7 @@ SH_STATUS sh_test_slabs_benchmark_radix_node(struct sh_slab_radix_node_SLAB_ALLO
ptrs[i]=(sh_uint64)node_ptr;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_test_compute_print_stats("allocations",tsc_value,iter_num,SH_FALSE);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
@@ -132,7 +132,7 @@ SH_STATUS sh_test_slabs_benchmark_radix_node(struct sh_slab_radix_node_SLAB_ALLO
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
sh_test_compute_print_stats("deallocations",tsc_value,iter_num,SH_FALSE);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark(sh_slab_reg_phys_SLAB_ALLOCATOR *alloc_reg_phys,sh_slab_reg_virt_SLAB_ALLOCATOR *alloc_reg_virt,struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc_radix_node,sh_page_PAGE_TABLE_POOL *ptp) {

View File

@@ -3,6 +3,7 @@
#include "kernel/tests/test_slabs.h"
#include "kernel/tests/test_radix.h"
#include "kernel/log.h"
#include "std/print.h"
__attribute__((section(".bss")))
static sh_tsc_TSC_VALUE tsc_value[10000];
static void sort(sh_tsc_TSC_VALUE *array,sh_uint64 n) {
@@ -21,7 +22,7 @@ static sh_tsc_TSC_VALUE percentile(sh_tsc_TSC_VALUE *array,sh_uint64 n,sh_uint8
if (idx>=n) idx=n-1;
return array[idx];
}
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) {
if (tsc_value_array==SH_NULLPTR || array_size==0) return SH_STATUS_INVALID_PARAMETER;
sort(tsc_value_array,array_size);
sh_uint64 min=tsc_value_array[0];
@@ -30,22 +31,42 @@ SH_STATUS sh_test_compute_print_stats(char* benchname,sh_tsc_TSC_VALUE *tsc_valu
sh_uint64 sum=0;
for(sh_iter64 i=0;i<array_size;i++) sum+=tsc_value_array[i];
sh_uint64 avrg=sum/array_size;
sh_log_test("");
sh_log_ftest("Result for benchmark \"%s\" :\n",benchname);
sh_log_ftest("Min: %8u | Med: %8u | Avg: %8u | Max: %8u | Total : %8u (TSC)\n",min,median,avrg,max,sum);
sh_uint64 p90=percentile(tsc_value_array,array_size,90);
sh_uint64 p99=percentile(tsc_value_array,array_size,99);
const char* labels[]={"[P00-P90]","[P90-P99]","[P99-Max]"};
sh_uint64 bounds[]={min,p90,p99,max};
sh_uint64 counts[]={90,9,1};
for (int i=0;i<3;i++) {
char bar[21];
sh_uint64 fill=(counts[i]*20)/100;
sh_uint64 j=0;
for (;j<fill;j++) bar[j]='#';
for (;j<20;j++) bar[j]='-';
bar[20]='\0';
sh_log_ftest("%s %8u-%8u : [%s] %8u%%\n",labels[i],bounds[i],bounds[i+1],bar,counts[i]);
if (!use_std_print) {
sh_log_test("");
sh_log_ftest("Result for benchmark \"%s\" :\n",benchname);
sh_log_ftest("Min: %8u | Med: %8u | Avg: %8u | Max: %8u | Total : %8u (TSC)\n",min,median,avrg,max,sum);
sh_uint64 p90=percentile(tsc_value_array,array_size,90);
sh_uint64 p99=percentile(tsc_value_array,array_size,99);
const char* labels[]={"[P00-P90]","[P90-P99]","[P99-Max]"};
sh_uint64 bounds[]={min,p90,p99,max};
sh_uint64 counts[]={90,9,1};
for (int i=0;i<3;i++) {
char bar[21];
sh_uint64 fill=(counts[i]*20)/100;
sh_uint64 j=0;
for (;j<fill;j++) bar[j]='#';
for (;j<20;j++) bar[j]='-';
bar[20]='\0';
sh_log_ftest("%s %8u-%8u : [%s] %8u%%\n",labels[i],bounds[i],bounds[i+1],bar,counts[i]);
}
} else {
sh_print(SH_TEST,"\n");
sh_printf(SH_TEST,"Result for benchmark \"%s\" :\n",benchname);
sh_printf(SH_TEST,"Min: %8u | Med: %8u | Avg: %8u | Max: %8u | Total : %8u (TSC)\n",min,median,avrg,max,sum);
sh_uint64 p90=percentile(tsc_value_array,array_size,90);
sh_uint64 p99=percentile(tsc_value_array,array_size,99);
const char* labels[]={"[P00-P90]","[P90-P99]","[P99-Max]"};
sh_uint64 bounds[]={min,p90,p99,max};
sh_uint64 counts[]={90,9,1};
for (int i=0;i<3;i++) {
char bar[21];
sh_uint64 fill=(counts[i]*20)/100;
sh_uint64 j=0;
for (;j<fill;j++) bar[j]='#';
for (;j<20;j++) bar[j]='-';
bar[20]='\0';
sh_printf(SH_TEST,"%s %8u-%8u : [%s] %8u%%\n",labels[i],bounds[i],bounds[i+1],bar,counts[i]);
}
}
return SH_STATUS_SUCCESS;
}

View File

@@ -62,7 +62,6 @@ SH_STATUS sh_heap_free_pages(sh_page_VIRTUAL_ADDRESS va) {
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: couldn't find associated physical address. Status: %8s\n",status);
status=sh_page_unmap_contiguous_pages_range_ptp(default_heap->kernel_ptp,va,pages_count*SH_PAGE_SIZE);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: unmap failed. Status: %8s\n",status);
// sh_log_flog(SH_LOG_SOURCE_HEAP,"freeed va=0x%x\n",va);
status=sh_pez_free_virtual_pages(default_heap->virt_plane,&va,pages_count);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: virt_plane free failed. Status: %8s\n",status);
status=sh_pez_free_physical_pages(default_heap->phys_plane,&pa,pages_count);

View File

@@ -0,0 +1,284 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/memory.h"
#include "kernel/log.h"
#include "kernel/test.h"
#include "kernel/efifb.h"
sh_memory_MEMORY_SERVICES *memory_services=SH_NULLPTR;
SH_STATUS sh_memory_init_subsystem(sh_conf_BOOT_CONFIG *boot_config,sh_memory_MEMORY_SERVICES *services) {
if (boot_config==SH_NULLPTR || services==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_log_log("Trying to obtain memory map...",SH_LOG_SOURCE_MEMS);
SH_STATUS status=sh_page_copy_memory_map();
if (status==SH_STATUS_SUCCESS) {
sh_log_log("Successfully copied memory map.",SH_LOG_SOURCE_PAGE);
sh_log_log("Successfully obtained memory map.",SH_LOG_SOURCE_MEMS);
} else {
sh_log_error("Can't copy memory map.",SH_LOG_SOURCE_PAGE);
sh_log_fatal("Can't obtain memory map.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Checking memory map...",SH_LOG_SOURCE_MEMS);
if (status==SH_STATUS_SUCCESS) {
sh_log_log("Successfully checked memory map.",SH_LOG_SOURCE_MEMS);
} else if (status==SH_STATUS_INVALID_SIGNATURE) {
sh_log_fatal("Can't check memory map.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
} else if (status==SH_STATUS_MMAP_BUFFER_OVERFLOW) {
sh_log_fatal("Memory map is overflowing. Can't safely continue.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Initializing current page table pool...",SH_LOG_SOURCE_MEMS);
status=sh_page_init_ptp(boot_config->page_table_pool_pa,sh_page_get_boot_ptp_va(),boot_config->page_table_allocator_level,&services->kernel_ptp);
if (status==SH_STATUS_PT_POOL_NO_BITMAP_INIT) {
sh_log_fatal("Couldn't initialize current page table pool.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
} else if (status==SH_STATUS_PT_POOL_NO_PAGE_SET) {
sh_log_fatal("Couldn't initialize current page table pool.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialized current page table pool.",SH_LOG_SOURCE_MEMS);
status=sh_efifb_init_fb(&boot_config->fb_config,&services->kernel_ptp);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't initialize EFI FB subsystem. Status: %8s\n",status);
while (SH_TRUE) {};
}
sh_efifb_init_bar();
sh_log_log("Successfully initialized EFI FB subsystem.",SH_LOG_SOURCE_MEMS);
sh_log_log("Parsing memory map...",SH_LOG_SOURCE_MEMS);
status=sh_page_analyse_memory_map(&services->kernel_ptp);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't parse memory map. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Successfully parsed memory map.",SH_LOG_SOURCE_MEMS);
sh_log_mem_stats(SH_LOG_SOURCE_MEMS);
sh_log_log("Page managment subsystem successfully initialized",SH_LOG_SOURCE_MEMS);
status=sh_slab_reg_phys_alloc_init(&services->slab_reg_phys,&services->kernel_ptp);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize physical region object slab allocator.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize physical region object slab allocator.",SH_LOG_SOURCE_MEMS);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MEMS);
sh_slab_reg_phys_SLAB_STRUCT *first_slab_rp=SH_NULLPTR;
status=sh_slab_reg_phys_add_slab(&services->slab_reg_phys,&services->kernel_ptp,&first_slab_rp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MEMS);
if (first_slab_rp->free_bitmap[0]!=1 ||
first_slab_rp->slab_index!=0 ||
first_slab_rp->next!=SH_NULLPTR ||
first_slab_rp->prev!=SH_NULLPTR ||
first_slab_rp->used_count!=0) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MEMS);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MEMS);
}
}
status=sh_slab_reg_virt_alloc_init(&services->slab_reg_virt,&services->kernel_ptp);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize virtual region object slab allocator.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize virtual region object slab allocator.",SH_LOG_SOURCE_MEMS);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MEMS);
sh_slab_reg_virt_SLAB_STRUCT *first_slab_rv=SH_NULLPTR;
status=sh_slab_reg_virt_add_slab(&services->slab_reg_virt,&services->kernel_ptp,&first_slab_rv);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MEMS);
if (first_slab_rv->free_bitmap[0]!=1 ||
first_slab_rv->slab_index!=0 ||
first_slab_rv->next!=SH_NULLPTR ||
first_slab_rv->prev!=SH_NULLPTR ||
first_slab_rv->used_count!=0) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MEMS);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MEMS);
}
}
sh_pba_PAGE_BLOCK_ALLOCATOR slab_radix_node_pba;
status=sh_pba_init(&slab_radix_node_pba,SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA,SH_VMEM_LAYOUT_SLAB_RADIX_NODE_SIZE_BYTES/SH_PAGE_SIZE,SH_SLAB_RADIX_NODE_SLAB_DATA_PAGES);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize PBA for radix nodes slab allocator.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize PBA for radix nodes slab allocator.",SH_LOG_SOURCE_MEMS);
status=sh_slab_radix_node_alloc_init(&services->slab_radix_node,&slab_radix_node_pba);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize radix nodes slab allocator.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize radix nodes slab allocator.",SH_LOG_SOURCE_MEMS);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MEMS);
sh_slab_radix_node_SLAB *first_slab_rn=SH_NULLPTR;
status=sh_slab_radix_node_add_slab(&services->slab_radix_node,&services->kernel_ptp,&first_slab_rn);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MEMS);
if (first_slab_rn->free_bitmap[0]!=0x3FFFF ||
first_slab_rn->slab_index!=0 ||
first_slab_rn->next_slab!=SH_NULLPTR ||
first_slab_rn->prev_slab!=SH_NULLPTR ||
first_slab_rn->next_partial!=SH_NULLPTR ||
first_slab_rn->prev_partial!=SH_NULLPTR ||
first_slab_rn->used_count!=0 ) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MEMS);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MEMS);
}
}
if (boot_config->test_benchmark) {
status=sh_test_slabs_benchmark(&services->slab_reg_phys,&services->slab_reg_virt,&services->slab_radix_node,&services->kernel_ptp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark one of the slab allocator.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
status=sh_test_radix_benchmark(&services->slab_radix_node,&services->kernel_ptp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark radix trees subsystem.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
}
sh_log_log("Creating Pez physical plane...",SH_LOG_SOURCE_MEMS);
status=sh_pez_init_physical_plane((sh_uint8*)sh_page_get_physical_bitmap_ptr(),sh_page_get_physical_memory_amount_pages(),&services->slab_reg_phys,&services->slab_radix_node,&services->kernel_ptp,&services->physical_plane);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't create Pez physical plane. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Succesfully created Pez physical plane.",SH_LOG_SOURCE_MEMS);
if (boot_config->test_benchmark) {
status=sh_test_pez_benchmark_physical(&services->physical_plane);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark Pez physical plane.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
}
sh_log_log("Creating Pez virtual plane for kernel heap...",SH_LOG_SOURCE_MEMS);
status=sh_pez_init_virtual_plane(SH_VMEM_LAYOUT_HEAP_BIG_VA,&services->slab_reg_virt,&services->slab_radix_node,&services->kernel_ptp,&services->kernel_ptp,&services->virtual_plane_kernel_heap);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't create Pez virtual plane for kernel heap. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Succesfully created Pez virtual plane for kernel heap.",SH_LOG_SOURCE_MEMS);
sh_pez_set_available();
status=sh_heap_init_heap(&services->physical_plane,&services->virtual_plane_kernel_heap,&services->kernel_ptp,&services->kernel_heap);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't initialize kernel heap. Error code: %8s",status);
while (SH_TRUE) {};
}
sh_uint64 slab_data_pages[8]=SH_SLAB_GENERIC_SLAB_DATA_PAGES;
for (sh_iter64 i=0;i<8;i++) {
status=sh_pba_init(&services->kernel_heap.pba[i],SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA+i*SH_VMEM_LAYOUT_HEAP_SLAB_SPACING,((SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_SIZE_BYTES/SH_PAGE_SIZE)/slab_data_pages[i])*slab_data_pages[i],slab_data_pages[i]);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't create PBA for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE);
}
status=sh_slab_generic_alloc_init((sh_uint8)i,&services->kernel_heap.slabs_allocator[i],&services->kernel_heap.pba[i]);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't create slab allocator for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE);
}
sh_slab_generic_SLAB *first_slab_generic;
status=sh_slab_generic_add_slab(&services->kernel_heap.slabs_allocator[i],&services->kernel_ptp,&first_slab_generic);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MEMS,"Couldn't allocate first slab for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE) {};
} else {
if (first_slab_generic->free_bitmap[0]!=services->kernel_heap.slabs_allocator[i].bitmap_init ||
first_slab_generic->slab_index!=0 ||
first_slab_generic->next_slab!=SH_NULLPTR ||
first_slab_generic->prev_slab!=SH_NULLPTR ||
first_slab_generic->next_partial!=SH_NULLPTR ||
first_slab_generic->prev_partial!=SH_NULLPTR ||
first_slab_generic->used_count!=0 ) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MEMS);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
}
sh_log_flog(SH_LOG_SOURCE_MEMS,"Succesfully created heap slab allocator with level %8u.\n",i);
}
sh_heap_load_default_heap(&services->kernel_heap);
sh_log_log("Succesfully created kernel heap.",SH_LOG_SOURCE_MEMS);
if (boot_config->test_benchmark) {
status=sh_test_malloc_benchmark();
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark Pez physical plane.",SH_LOG_SOURCE_MEMS);
while (SH_TRUE) {};
}
}
memory_services=services;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_memory_identity_map(sh_page_PHYSICAL_ADDRESS phys_start,sh_uint64 page_count,sh_uint64 flags) {
if (phys_start==0 || page_count==0) return SH_STATUS_INVALID_PARAMETER;
if (memory_services==SH_NULLPTR) return SH_STATUS_MEMORY_SUBSYSTEM_NOT_INITIALIZED;
SH_STATUS status=sh_page_is_va_range_mapped_ptp(&memory_services->kernel_ptp,(sh_page_VIRTUAL_ADDRESS)phys_start,page_count*SH_PAGE_SIZE);
if (status!=SH_STATUS_VA_NOT_MAPPED) {
if (status==SH_STATUS_VA_MAPPED) {
return SH_STATUS_ERROR_VA_FULLY_MAPPED;
} else if (status==SH_STATUS_VA_PARTIALLY_MAPPED) {
return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED;
}
} else if (sh_status_error(status)) {
return status;
}
status=sh_page_map_contiguous_pages_range_ptp(&memory_services->kernel_ptp,(sh_page_VIRTUAL_ADDRESS)phys_start,phys_start,flags,page_count*SH_PAGE_SIZE);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_memory_devs_query(char *sub_path,sh_devs_RESULT *result) {
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 path_len=sh_string_len(sub_path);
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
if (memory_services==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
if (sh_string_compare(sub_path,"/free-pages",11)) {
if (path_len==11) {
result->type=SH_DEVS_VALUE;
result->value=memory_services->physical_plane.free_pages;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/used-pages",11)) {
if (path_len==11) {
result->type=SH_DEVS_VALUE;
result->value=memory_services->physical_plane.used_pages;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/total-pages",12)) {
if (path_len==12) {
result->type=SH_DEVS_VALUE;
result->value=sh_page_get_physical_memory_amount_pages();
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else if (sh_string_compare(sub_path,"/installed-pages",16)) {
if (path_len==16) {
result->type=SH_DEVS_VALUE;
result->value=sh_page_get_installed_memory_bytes()/SH_PAGE_SIZE;
return SH_STATUS_SUCCESS;
} else {
return SH_STATUS_NOT_FOUND;
}
} else {
return SH_STATUS_NOT_FOUND;
}
}

View File

@@ -2,6 +2,7 @@
#include "memory/page.h"
#include "kernel/log.h"
#include "std/mem.h"
#include "std/print.h"
__attribute__((section(".bss")))
static sh_uint8 memory_map_buffer[64*1024];
static sh_uint8 *physical_bitmap;
@@ -667,3 +668,6 @@ SH_STATUS sh_page_get_memory_stats(sh_page_MEM_STATS *mem_stats) {
mem_stats->memory_installed_bytes=physical_memory_installed;
return SH_STATUS_SUCCESS;
}
sh_uint64 sh_page_get_installed_memory_bytes() {
return physical_memory_installed;
}

View File

@@ -172,7 +172,7 @@ static SH_STATUS sh_pez_internal_scan_size_list_physical(sh_pez_PHYSICAL_PLANE *
sh_page_MEM_STATS mem_stats;
SH_STATUS status=sh_page_get_memory_stats(&mem_stats);
sh_log_fdebug(SH_LOG_SOURCE_PEZ,"Scanning size list radix:\n");
sh_uint64 free_region_count=0;
__attribute__((__unused__)) sh_uint64 free_region_count=0;
sh_log_byte(SH_PEZ_DEBUG_SIZE_LIST_BLOCK_HEADER);
sh_log_byte('\n');
for (sh_iter64 i=1;i<mem_stats.largest_free_block+1;i++) {

View File

@@ -22,6 +22,20 @@ SH_STATUS sh_ring_write_string(sh_ring_RING_BUFFER_HEADER *ring_buffer,char *str
}
ring_buffer->data_start[ring_buffer->head]=(sh_uint8)string[i];
ring_buffer->head=next_head;
ring_buffer->total_bytes_written++;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ring_read_bytes(sh_ring_RING_BUFFER_HEADER *ring_buffer,sh_uint32 bytes_count,void *output) {
if (ring_buffer==SH_NULLPTR || output==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (ring_buffer->buffer_bytes_size==0 || ring_buffer->data_start==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 size=ring_buffer->buffer_bytes_size;
if (bytes_count>size) return SH_STATUS_TOO_MUCH_DATA;
sh_uint32 head=ring_buffer->head;
sh_uint32 start=(head+size-bytes_count)%size;
for (sh_uint32 i=0;i<bytes_count;i++) {
sh_uint32 idx=(start+i)%size;
((sh_uint8*)output)[i]=ring_buffer->data_start[idx];
}
return SH_STATUS_SUCCESS;
}

View File

@@ -4,12 +4,15 @@
#include "memory/heap.h"
#include "memory/vmem_layout.h"
#include "kernel/log.h"
#include "std/smp.h"
sh_SPIN_LOCK malloc_lock=SH_LOCK();
SH_STATUS last_status=0;
SH_STATUS sh_malloc_get_last_status() {
return last_status;
}
void* sh_malloc(sh_uint64 size) {
if (size==0) return SH_NULLPTR;
sh_spin_lock(&malloc_lock);
sh_page_VIRTUAL_ADDRESS va=0;
SH_STATUS status;
if (size<=1024) {
@@ -19,21 +22,22 @@ void* sh_malloc(sh_uint64 size) {
status=sh_heap_allocate_pages(pages,&va);
}
last_status=status;
sh_spin_unlock(&malloc_lock);
return (sh_status_error(status))?SH_NULLPTR:(void*)va;
}
void sh_free(void *ptr) {
if (ptr==SH_NULLPTR) return;
if (ptr == SH_NULLPTR) return;
sh_spin_lock(&malloc_lock);
sh_page_VIRTUAL_ADDRESS va=(sh_page_VIRTUAL_ADDRESS)ptr;
SH_STATUS status=SH_STATUS_SUCCESS;
if (va>=SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_VA+SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_SIZE_BYTES) {
last_status=sh_heap_free_object(va);
return;
status=sh_heap_free_object(va);
} else if (va>=SH_VMEM_LAYOUT_HEAP_BIG_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA) {
status=sh_heap_free_pages(va);
if (sh_status_error(status)) sh_log_fcritical(SH_LOG_SOURCE_HEAP,"Couldn't free pages at va=0x%x\n",va);
} else {
sh_log_fcritical(SH_LOG_SOURCE_HEAP, "va=0x%x doesn't come from heap\n", va);
}
if (va>=SH_VMEM_LAYOUT_HEAP_BIG_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA) {
last_status=sh_heap_free_pages(va);
if (sh_status_error(last_status)) {
sh_log_fcritical(SH_LOG_SOURCE_HEAP,"Couldn't free pages at va=0x%x\n",va);
}
return;
}
sh_log_fcritical(SH_LOG_SOURCE_HEAP,"va=0x%x doesn't came from heap\n",va);
last_status=status;
sh_spin_unlock(&malloc_lock);
}

886
shelter/lib/src/std/print.c Normal file
View File

@@ -0,0 +1,886 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/stdlib.h"
#include "devs/apic/lapic.h"
#include "memory/ring.h"
#include "cpu/serial.h"
sh_bool are_rings_buffer_setup=SH_FALSE;
sh_ring_RING_BUFFER_HEADER *ring_buffer_array=SH_NULLPTR;
sh_SPIN_LOCK serial_lock=SH_LOCK();
SH_STATUS sh_print_setup_ring_buffers_per_ap(sh_conf_BOOT_CONFIG *boot_config) {
if (are_rings_buffer_setup==SH_TRUE || ring_buffer_array!=SH_NULLPTR || boot_config==SH_NULLPTR) return SH_STATUS_UNAVAILABLE;
sh_uint64 cpu_count=0;
sh_lapic_DEVICE **lapic_dev_array=sh_lapic_get_by_apic_id_array();
sh_uint64 max_lapic_id=sh_lapic_get_max_apic_id();
for (sh_iter64 i=0;i<max_lapic_id+1;i++) {
sh_lapic_DEVICE *lapic_dev=lapic_dev_array[i];
if (lapic_dev==SH_NULLPTR) continue;
cpu_count++;
}
ring_buffer_array=(sh_ring_RING_BUFFER_HEADER*)sh_malloc(sizeof(sh_ring_RING_BUFFER_HEADER)*cpu_count);
if (!ring_buffer_array) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)ring_buffer_array,0x0,sizeof(sh_ring_RING_BUFFER_HEADER)*cpu_count);
sh_uint64 log_ring_size_ap=boot_config->log_ring_size/cpu_count;
if (log_ring_size_ap<4) log_ring_size_ap=4;
for (sh_iter64 i=0;i<cpu_count;i++) {
ring_buffer_array[i].data_start=sh_malloc(log_ring_size_ap*SH_PAGE_SIZE);
if (ring_buffer_array[i].data_start==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
ring_buffer_array[i].buffer_bytes_size=(sh_uint32)log_ring_size_ap*SH_PAGE_SIZE;
}
are_rings_buffer_setup=SH_TRUE;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_byte(sh_uint8 byte);
SH_STATUS sh_print_int8(sh_int8 n);
SH_STATUS sh_print_int16(sh_int16 n);
SH_STATUS sh_print_int32(sh_int32 n);
SH_STATUS sh_print_int64(sh_int64 n);
SH_STATUS sh_print_uint8(sh_uint8 n);
SH_STATUS sh_print_uint16(sh_uint16 n);
SH_STATUS sh_print_uint32(sh_uint32 n);
SH_STATUS sh_print_uint64(sh_uint64 n);
SH_STATUS sh_print_uint8_hex(sh_uint8 n);
SH_STATUS sh_print_uint16_hex(sh_uint16 n);
SH_STATUS sh_print_uint32_hex(sh_uint32 n);
SH_STATUS sh_print_uint64_hex(sh_uint64 n);
SH_STATUS sh_print_uint64_hex_fixed(sh_uint64 n);
SH_STATUS sh_print_double(double value);
SH_STATUS sh_print_flush();
SH_STATUS sh_print_flush() {
char *text_to_flush=sh_malloc(sh_smp_gs_base()->per_cpu->bytes_outputed);
if (!text_to_flush) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_spin_lock(&serial_lock);
SH_STATUS status=sh_ring_read_bytes(&ring_buffer_array[sh_smp_gs_base()->per_cpu->cpu_id],sh_smp_gs_base()->per_cpu->bytes_outputed,text_to_flush);
if (sh_status_error(status)) {
sh_spin_unlock(&serial_lock);
return status;
}
sh_log_string(text_to_flush);
sh_spin_unlock(&serial_lock);
sh_free(text_to_flush);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_byte(sh_uint8 byte) {
if (!are_rings_buffer_setup) {
sh_log_byte(byte);
return SH_STATUS_SUCCESS;
} else {
SH_STATUS status=sh_ring_write_byte(&ring_buffer_array[sh_smp_gs_base()->per_cpu->cpu_id],byte);
if (sh_status_error(status)) return status;
sh_smp_gs_base()->per_cpu->bytes_outputed++;
return SH_STATUS_SUCCESS;
}
}
SH_STATUS sh_print_int8(sh_int8 n) {
return sh_print_int64((sh_int64)n);
}
SH_STATUS sh_print_int16(sh_int16 n) {
return sh_print_int64((sh_int64)n);
}
SH_STATUS sh_print_int32(sh_int32 n) {
return sh_print_int64((sh_int64)n);
}
SH_STATUS sh_print_int64(sh_int64 n) {
sh_uint64 absolute_val;
if (n<0) {
sh_print_byte('-');
absolute_val=(sh_uint64)(-(n+1))+1;
} else {
absolute_val=(sh_uint64)n;
}
return sh_print_uint64(absolute_val);
}
SH_STATUS sh_print_uint8(sh_uint8 n) {
return sh_print_uint64((sh_uint64)n);
}
SH_STATUS sh_print_uint16(sh_uint16 n) {
return sh_print_uint64((sh_uint64)n);
}
SH_STATUS sh_print_uint32(sh_uint32 n) {
return sh_print_uint64((sh_uint64)n);
}
SH_STATUS sh_print_uint64(sh_uint64 n) {
char buf[20];
sh_uint32 i=0;
if (n==0) {
sh_print_byte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]='0'+(sh_int8)(n%10);
n/=10;
}
while (i--) {
sh_print_byte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_uint8_hex(sh_uint8 n) {
return sh_print_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_uint16_hex(sh_uint16 n) {
return sh_print_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_uint32_hex(sh_uint32 n) {
return sh_print_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_uint64_hex(sh_uint64 n) {
char buf[16];
sh_uint32 i=0;
const char hex_digits[]="0123456789ABCDEF";
if (n==0) {
sh_print_byte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]=hex_digits[n & 0xF];
n>>=4;
}
while (i--) {
sh_print_byte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_uint64_hex_fixed(sh_uint64 n) {
const char hex_digits[]="0123456789ABCDEF";
for (sh_int8 i=15;i>=0;i--) {
sh_uint8 nibble=(sh_uint8)((n>>(i*4))&0xF);
sh_print_byte((sh_uint8)hex_digits[nibble]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_double(double value) {
if (value<0) {
sh_print_byte('-');
value=-value;
}
sh_uint64 integer_part=(sh_uint64)value;
double fractional_part=value-(double)integer_part;
SH_STATUS status=sh_print_uint64(integer_part);
if (status!=SH_STATUS_SUCCESS) return status;
sh_print_byte('.');
for (sh_iter64 i=0;i<6;i++) {
fractional_part*=10.0;
sh_uint64 digit=(sh_uint64)fractional_part;
sh_print_byte('0'+(sh_uint8)digit);
fractional_part-=(double)digit;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print(sh_log_OUTPUT_TYPE output_type,char *text) {
if (text==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc();
if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER;
if (output_type<sh_log_get_log_level()) {
return SH_STATUS_SUCCESS;
}
sh_smp_gs_base()->per_cpu->bytes_outputed=0;
sh_asm_cli();
char *intro="[Shelter:";
while (*intro) {
sh_print_byte((sh_uint8)*intro++);
}
sh_print_uint64(sh_smp_gs_base()->per_cpu->cpu_id);
sh_print_byte('@');
char* type=SH_NULLPTR;
if (output_type==SH_DEBUG) {
type="Debug] ";
} else if (output_type==SH_LOG) {
type="Log] ";
} else if (output_type==SH_WARNING) {
type="Warning] ";
} else if (output_type==SH_ERROR) {
type="Error] ";
} else if (output_type==SH_CRITICAL) {
type="Critical] ";
} else if (output_type==SH_FATAL) {
type="Fatal] ";
} else if (output_type==SH_TEST) {
type="Test] ";
} else if (output_type==SH_FAULT) {
type="Fault] ";
}
while (*type) {
sh_print_byte((sh_uint8)*type++);
}
sh_print_uint64(tsc_value);
char *transition=" : ";
while (*transition) {
sh_print_byte((sh_uint8)*transition++);
}
while (*text) {
sh_print_byte((sh_uint8)*text++);
}
SH_STATUS status=sh_print_flush();
if (sh_status_error(status)) return status;
sh_asm_sti();
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_printf(sh_log_OUTPUT_TYPE output_type,char* format,...) {
if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc();
if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER;
if (output_type<sh_log_get_log_level()) {
return SH_STATUS_SUCCESS;
}
sh_smp_gs_base()->per_cpu->bytes_outputed=0;
sh_asm_cli();
char *intro="[Shelter:";
while (*intro) {
sh_print_byte((sh_uint8)*intro++);
}
sh_print_uint64(sh_smp_gs_base()->per_cpu->cpu_id);
sh_print_byte('@');
char* type=SH_NULLPTR;
if (output_type==SH_DEBUG) {
type="Debug] ";
} else if (output_type==SH_LOG) {
type="Log] ";
} else if (output_type==SH_WARNING) {
type="Warning] ";
} else if (output_type==SH_ERROR) {
type="Error] ";
} else if (output_type==SH_CRITICAL) {
type="Critical] ";
} else if (output_type==SH_FATAL) {
type="Fatal] ";
} else if (output_type==SH_TEST) {
type="Test] ";
} else if (output_type==SH_FAULT) {
type="Fault] ";
}
while (*type) {
sh_print_byte((sh_uint8)*type++);
}
sh_print_uint64(tsc_value);
char *transition=" : ";
while (*transition) {
sh_print_byte((sh_uint8)*transition++);
}
va_list args;
va_start(args,format);
for (const char *p=format;*p!='\0';p++) {
if (*p!='%') {
sh_print_byte((sh_uint8)*p);
continue;
}
p++;
switch (*p) {
case 's': {
char *s=va_arg(args,char *);
while (*s) {
sh_print_byte((sh_uint8)*s++);
}
break;
}
case 'd': {
double s=va_arg(args,double);
sh_print_double(s);
break;
}
case '1': {
if (p[1]=='u') {
sh_print_uint8((sh_uint8)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_int8((sh_int8)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_uint8_hex((sh_uint8)va_arg(args,int));
p++;
}
break;
}
case '2': {
if (p[1]=='u') {
sh_print_uint16((sh_uint16)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_int16((sh_int16)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_uint16_hex((sh_uint16)va_arg(args,int));
p++;
}
break;
}
case '4': {
if (p[1]=='u') {
sh_print_uint32((sh_uint32)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_int32((sh_int32)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_uint32_hex((sh_uint32)va_arg(args,int));
p++;
}
break;
}
case '8': {
if (p[1]=='u') {
sh_print_uint64(va_arg(args,unsigned long long));
p++;
} else if (p[1]=='s') {
sh_print_int64(va_arg(args,long long));
p++;
} else if (p[1]=='U') {
sh_print_uint64_hex(va_arg(args,unsigned long long));
p++;
}
break;
}
case 'x': {
sh_uint64 x=va_arg(args,sh_uint64);
sh_print_uint64_hex_fixed(x);
break;
}
case 'c': {
sh_print_byte((sh_uint8)va_arg(args,int));
break;
}
case '%': {
sh_print_byte('%');
break;
}
default:
sh_print_byte((sh_uint8)*p);
break;
}
}
va_end(args);
SH_STATUS status=sh_print_flush();
if (sh_status_error(status)) return status;
sh_asm_sti();
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_ibyte(sh_uint8 byte);
SH_STATUS sh_print_iint8(sh_int8 n);
SH_STATUS sh_print_iint16(sh_int16 n);
SH_STATUS sh_print_iint32(sh_int32 n);
SH_STATUS sh_print_iint64(sh_int64 n);
SH_STATUS sh_print_iuint8(sh_uint8 n);
SH_STATUS sh_print_iuint16(sh_uint16 n);
SH_STATUS sh_print_iuint32(sh_uint32 n);
SH_STATUS sh_print_iuint64(sh_uint64 n);
SH_STATUS sh_print_iuint8_hex(sh_uint8 n);
SH_STATUS sh_print_iuint16_hex(sh_uint16 n);
SH_STATUS sh_print_iuint32_hex(sh_uint32 n);
SH_STATUS sh_print_iuint64_hex(sh_uint64 n);
SH_STATUS sh_print_iuint64_hex_fixed(sh_uint64 n);
SH_STATUS sh_print_idouble(double value);
SH_STATUS sh_print_ibyte(sh_uint8 byte) {
sh_serial_send_byte(byte);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_iint8(sh_int8 n) {
return sh_print_iint64((sh_int64)n);
}
SH_STATUS sh_print_iint16(sh_int16 n) {
return sh_print_iint64((sh_int64)n);
}
SH_STATUS sh_print_iint32(sh_int32 n) {
return sh_print_iint64((sh_int64)n);
}
SH_STATUS sh_print_iint64(sh_int64 n) {
sh_uint64 absolute_val;
if (n<0) {
sh_print_ibyte('-');
absolute_val=(sh_uint64)(-(n+1))+1;
} else {
absolute_val=(sh_uint64)n;
}
return sh_print_iuint64(absolute_val);
}
SH_STATUS sh_print_iuint8(sh_uint8 n) {
return sh_print_iuint64((sh_uint64)n);
}
SH_STATUS sh_print_iuint16(sh_uint16 n) {
return sh_print_iuint64((sh_uint64)n);
}
SH_STATUS sh_print_iuint32(sh_uint32 n) {
return sh_print_iuint64((sh_uint64)n);
}
SH_STATUS sh_print_iuint64(sh_uint64 n) {
char buf[20];
sh_uint32 i=0;
if (n==0) {
sh_print_ibyte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]='0'+(sh_int8)(n%10);
n/=10;
}
while (i--) {
sh_print_ibyte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_iuint8_hex(sh_uint8 n) {
return sh_print_iuint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_iuint16_hex(sh_uint16 n) {
return sh_print_iuint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_iuint32_hex(sh_uint32 n) {
return sh_print_iuint64_hex((sh_uint64)n);
}
SH_STATUS sh_print_iuint64_hex(sh_uint64 n) {
char buf[16];
sh_uint32 i=0;
const char hex_digits[]="0123456789ABCDEF";
if (n==0) {
sh_print_ibyte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]=hex_digits[n & 0xF];
n>>=4;
}
while (i--) {
sh_print_ibyte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_iuint64_hex_fixed(sh_uint64 n) {
const char hex_digits[]="0123456789ABCDEF";
for (sh_int8 i=15;i>=0;i--) {
sh_uint8 nibble=(sh_uint8)((n>>(i*4))&0xF);
sh_print_ibyte((sh_uint8)hex_digits[nibble]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_print_idouble(double value) {
if (value<0) {
sh_print_ibyte('-');
value=-value;
}
sh_uint64 integer_part=(sh_uint64)value;
double fractional_part=value-(double)integer_part;
SH_STATUS status=sh_print_iuint64(integer_part);
if (status!=SH_STATUS_SUCCESS) return status;
sh_print_ibyte('.');
for (sh_iter64 i=0;i<6;i++) {
fractional_part*=10.0;
sh_uint64 digit=(sh_uint64)fractional_part;
sh_print_ibyte('0'+(sh_uint8)digit);
fractional_part-=(double)digit;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_iprint(sh_log_OUTPUT_TYPE output_type,char *text) {
if (text==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc();
if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER;
if (output_type<sh_log_get_log_level()) {
return SH_STATUS_SUCCESS;
}
sh_bool was_locked_by_me=SH_FALSE;
if (sh_spin_wholock(&serial_lock)==sh_smp_gs_base()->lapic_id) was_locked_by_me=SH_TRUE;
if (!was_locked_by_me) {
sh_spin_lock(&serial_lock);
}
char *intro="[Shelter:";
while (*intro) {
sh_print_ibyte((sh_uint8)*intro++);
}
sh_print_iuint64(sh_smp_gs_base()->per_cpu->cpu_id);
sh_print_ibyte('@');
char* type=SH_NULLPTR;
if (output_type==SH_DEBUG) {
type="Debug] ";
} else if (output_type==SH_LOG) {
type="Log] ";
} else if (output_type==SH_WARNING) {
type="Warning] ";
} else if (output_type==SH_ERROR) {
type="Error] ";
} else if (output_type==SH_CRITICAL) {
type="Critical] ";
} else if (output_type==SH_FATAL) {
type="Fatal] ";
} else if (output_type==SH_TEST) {
type="Test] ";
} else if (output_type==SH_FAULT) {
type="Fault] ";
}
while (*type) {
sh_print_ibyte((sh_uint8)*type++);
}
sh_print_iuint64(tsc_value);
char *transition=" : ";
while (*transition) {
sh_print_ibyte((sh_uint8)*transition++);
}
while (*text) {
sh_print_ibyte((sh_uint8)*text++);
}
if (!was_locked_by_me) sh_spin_unlock(&serial_lock);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_iprintf(sh_log_OUTPUT_TYPE output_type,char* format,...) {
if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE tsc_value=sh_tsc_get_kernel_current_tsc();
if (!sh_log_output_type_valid(output_type)) return SH_STATUS_INVALID_PARAMETER;
if (output_type<sh_log_get_log_level()) {
return SH_STATUS_SUCCESS;
}
sh_bool was_locked_by_me=SH_FALSE;
if (sh_spin_wholock(&serial_lock)==sh_smp_gs_base()->lapic_id) was_locked_by_me=SH_TRUE;
if (!was_locked_by_me) {
sh_spin_lock(&serial_lock);
}
char *intro="[Shelter:";
while (*intro) {
sh_print_ibyte((sh_uint8)*intro++);
}
sh_print_iuint64(sh_smp_gs_base()->per_cpu->cpu_id);
sh_print_ibyte('@');
char* type=SH_NULLPTR;
if (output_type==SH_DEBUG) {
type="Debug] ";
} else if (output_type==SH_LOG) {
type="Log] ";
} else if (output_type==SH_WARNING) {
type="Warning] ";
} else if (output_type==SH_ERROR) {
type="Error] ";
} else if (output_type==SH_CRITICAL) {
type="Critical] ";
} else if (output_type==SH_FATAL) {
type="Fatal] ";
} else if (output_type==SH_TEST) {
type="Test] ";
} else if (output_type==SH_FAULT) {
type="Fault] ";
}
while (*type) {
sh_print_ibyte((sh_uint8)*type++);
}
sh_print_iuint64(tsc_value);
char *transition=" : ";
while (*transition) {
sh_print_ibyte((sh_uint8)*transition++);
}
va_list args;
va_start(args,format);
for (const char *p=format;*p!='\0';p++) {
if (*p!='%') {
sh_print_ibyte((sh_uint8)*p);
continue;
}
p++;
switch (*p) {
case 's': {
char *s=va_arg(args,char *);
while (*s) {
sh_print_ibyte((sh_uint8)*s++);
}
break;
}
case 'd': {
double s=va_arg(args,double);
sh_print_idouble(s);
break;
}
case '1': {
if (p[1]=='u') {
sh_print_iuint8((sh_uint8)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_iint8((sh_int8)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_iuint8_hex((sh_uint8)va_arg(args,int));
p++;
}
break;
}
case '2': {
if (p[1]=='u') {
sh_print_iuint16((sh_uint16)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_iint16((sh_int16)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_iuint16_hex((sh_uint16)va_arg(args,int));
p++;
}
break;
}
case '4': {
if (p[1]=='u') {
sh_print_iuint32((sh_uint32)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_print_iint32((sh_int32)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_print_iuint32_hex((sh_uint32)va_arg(args,int));
p++;
}
break;
}
case '8': {
if (p[1]=='u') {
sh_print_iuint64(va_arg(args,unsigned long long));
p++;
} else if (p[1]=='s') {
sh_print_iint64(va_arg(args,long long));
p++;
} else if (p[1]=='U') {
sh_print_iuint64_hex(va_arg(args,unsigned long long));
p++;
}
break;
}
case 'x': {
sh_uint64 x=va_arg(args,sh_uint64);
sh_print_iuint64_hex_fixed(x);
break;
}
case 'c': {
sh_print_ibyte((sh_uint8)va_arg(args,int));
break;
}
case '%': {
sh_print_ibyte('%');
break;
}
default:
sh_print_ibyte((sh_uint8)*p);
break;
}
}
va_end(args);
if (!was_locked_by_me) sh_spin_unlock(&serial_lock);
return SH_STATUS_SUCCESS;
}
typedef struct sh_sprint_WRITER {
sh_uint8 *out;
sh_uint8 *end;
} sh_sprint_WRITER;
static inline SH_STATUS sh_sprint_byte(sh_sprint_WRITER *w,sh_uint8 c) {
if(w->out>=w->end) return SH_STATUS_TOO_MUCH_DATA;
*w->out++=c;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_sprint_int8(sh_sprint_WRITER *w,sh_int8 n);
SH_STATUS sh_sprint_int16(sh_sprint_WRITER *w,sh_int16 n);
SH_STATUS sh_sprint_int32(sh_sprint_WRITER *w,sh_int32 n);
SH_STATUS sh_sprint_int64(sh_sprint_WRITER *w,sh_int64 n);
SH_STATUS sh_sprint_uint8(sh_sprint_WRITER *w,sh_uint8 n);
SH_STATUS sh_sprint_uint16(sh_sprint_WRITER *w,sh_uint16 n);
SH_STATUS sh_sprint_uint32(sh_sprint_WRITER *w,sh_uint32 n);
SH_STATUS sh_sprint_uint64(sh_sprint_WRITER *w,sh_uint64 n);
SH_STATUS sh_sprint_uint8_hex(sh_sprint_WRITER *w,sh_uint8 n);
SH_STATUS sh_sprint_uint16_hex(sh_sprint_WRITER *w,sh_uint16 n);
SH_STATUS sh_sprint_uint32_hex(sh_sprint_WRITER *w,sh_uint32 n);
SH_STATUS sh_sprint_uint64_hex(sh_sprint_WRITER *w,sh_uint64 n);
SH_STATUS sh_sprint_uint64_hex_fixed(sh_sprint_WRITER *w,sh_uint64 n);
SH_STATUS sh_sprint_double(sh_sprint_WRITER *w,double value);
SH_STATUS sh_sprint_int8(sh_sprint_WRITER *w,sh_int8 n) {
return sh_sprint_int64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_int16(sh_sprint_WRITER *w,sh_int16 n) {
return sh_sprint_int64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_int32(sh_sprint_WRITER *w,sh_int32 n) {
return sh_sprint_int64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_int64(sh_sprint_WRITER *w,sh_int64 n) {
sh_uint64 absolute_val;
if (n<0) {
SH_STATUS status=sh_sprint_byte(w,'-');
if (sh_status_error(status)) return status;
absolute_val=(sh_uint64)(-(n+1))+1;
} else {
absolute_val=(sh_uint64)n;
}
return sh_sprint_uint64(w,absolute_val);
}
SH_STATUS sh_sprint_uint8(sh_sprint_WRITER *w,sh_uint8 n) {
return sh_sprint_uint64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_uint16(sh_sprint_WRITER *w,sh_uint16 n) {
return sh_sprint_uint64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_uint32(sh_sprint_WRITER *w,sh_uint32 n) {
return sh_sprint_uint64(w,(sh_int64)n);
}
SH_STATUS sh_sprint_uint64(sh_sprint_WRITER *w,sh_uint64 n) {
char buf[20];
sh_uint32 i=0;
if (n==0) return sh_sprint_byte(w,'0');
while (n>0) {
buf[i++]='0'+(sh_int8)(n%10);
n/=10;
}
while (i--) {
SH_STATUS status=sh_sprint_byte(w,(sh_uint8)buf[i]);
if (sh_status_error(status)) return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_sprint_uint8_hex(sh_sprint_WRITER *w,sh_uint8 n) {
return sh_sprint_uint64_hex(w,(sh_uint64)n);
}
SH_STATUS sh_sprint_uint16_hex(sh_sprint_WRITER *w,sh_uint16 n) {
return sh_sprint_uint64_hex(w,(sh_uint64)n);
}
SH_STATUS sh_sprint_uint32_hex(sh_sprint_WRITER *w,sh_uint32 n) {
return sh_sprint_uint64_hex(w,(sh_uint64)n);
}
SH_STATUS sh_sprint_uint64_hex(sh_sprint_WRITER *w,sh_uint64 n) {
char buf[16];
sh_uint32 i=0;
const char hex_digits[]="0123456789ABCDEF";
if (n==0) return sh_sprint_byte(w,'0');
while (n>0) {
buf[i++]=hex_digits[n & 0xF];
n>>=4;
}
while (i--) {
SH_STATUS status=sh_sprint_byte(w,(sh_uint8)buf[i]);
if (sh_status_error(status)) return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_sprint_uint64_hex_fixed(sh_sprint_WRITER *w,sh_uint64 n) {
const char hex[]="0123456789ABCDEF";
for (sh_int8 i=15;i>=0;i--) {
char c=hex[(n>>(i*4))&0xF];
SH_STATUS status=sh_sprint_byte(w,(sh_uint8)c);
if (sh_status_error(status)) return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_sprint_double(sh_sprint_WRITER *w,double value) {
SH_STATUS status;
if(value<0) {
status=sh_sprint_byte(w,'-');
if (sh_status_error(status)) return status;
value= -value;
}
sh_uint64 int_part=(sh_uint64)value;
double frac=value-(double)int_part;
status=sh_sprint_uint64(w,int_part);
if (sh_status_error(status)) return status;
status=sh_sprint_byte(w,'.');
if (sh_status_error(status)) return status;
for(sh_iter64 i=0;i<6;i++) {
frac*=10.0;
sh_uint64 d=(sh_uint64)frac;
status=sh_sprint_byte(w,(sh_uint8)'0'+(sh_uint8)d);
if (sh_status_error(status)) return status;
frac-=(double)d;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_sprintf(char *output_string,sh_uint64 output_len,char *format,...) {
if (format==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_asm_cli();
sh_sprint_WRITER w={
.out=(sh_uint8*)output_string,
.end=(sh_uint8*)output_string+output_len
};
va_list args;
va_start(args,format);
for (const char *p=format;*p!='\0';p++) {
if (*p!='%') {
sh_sprint_byte(&w,(sh_uint8)*p);
continue;
}
p++;
switch (*p) {
case 's': {
char *s=va_arg(args,char *);
while (*s) {
sh_sprint_byte(&w,(sh_uint8)*s++);
}
break;
}
case 'd': {
double s=va_arg(args,double);
sh_sprint_double(&w,s);
break;
}
case '1': {
if (p[1]=='u') {
sh_sprint_uint8(&w,(sh_uint8)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_sprint_int8(&w,(sh_int8)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_sprint_uint8_hex(&w,(sh_uint8)va_arg(args,int));
p++;
}
break;
}
case '2': {
if (p[1]=='u') {
sh_sprint_uint16(&w,(sh_uint16)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_sprint_int16(&w,(sh_int16)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_sprint_uint16_hex(&w,(sh_uint16)va_arg(args,int));
p++;
}
break;
}
case '4': {
if (p[1]=='u') {
sh_sprint_uint32(&w,(sh_uint32)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_sprint_int32(&w,(sh_int32)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_sprint_uint32_hex(&w,(sh_uint32)va_arg(args,int));
p++;
}
break;
}
case '8': {
if (p[1]=='u') {
sh_sprint_uint64(&w,va_arg(args,unsigned long long));
p++;
} else if (p[1]=='s') {
sh_sprint_int64(&w,va_arg(args,long long));
p++;
} else if (p[1]=='U') {
sh_sprint_uint64_hex(&w,va_arg(args,unsigned long long));
p++;
}
break;
}
case 'x': {
sh_uint64 x=va_arg(args,sh_uint64);
sh_sprint_uint64_hex_fixed(&w,x);
break;
}
case 'c': {
sh_sprint_byte(&w,(sh_uint8)va_arg(args,int));
break;
}
case '%': {
sh_sprint_byte(&w,'%');
break;
}
default:
sh_sprint_byte(&w,(sh_uint8)*p);
break;
}
}
va_end(args);
SH_STATUS status=sh_sprint_byte(&w,'\0');
if (sh_status_error(status)) {
output_string[output_len-1]='\0';
}
sh_asm_sti();
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/queue.h"
#include "std/malloc.h"
#include "std/smp.h"
SH_STATUS sh_queue_event_init(sh_queue_KBD_EVENT *q,sh_uint32 capacity) {
if (q==SH_NULLPTR || capacity==0) return SH_STATUS_INVALID_PARAMETER;
q->buffer=(sh_kbd_EVENT*)sh_malloc(sizeof(sh_kbd_EVENT)*capacity);
if (!q->buffer) return SH_STATUS_ERROR_NULLPTR_RETURNED;
q->capacity=capacity;
q->write_index=0;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_queue_event_push(sh_queue_KBD_EVENT *q,sh_kbd_EVENT ev) {
if (q==SH_NULLPTR || q->buffer==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 idx=q->write_index % q->capacity;
q->buffer[idx]=ev;
sh_mb();
q->write_index++;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_queue_event_destroy(sh_queue_KBD_EVENT *q) {
if (q==SH_NULLPTR || q->buffer==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_free(q->buffer);
if (sh_status_error(sh_malloc_get_last_status())) return sh_malloc_get_last_status();
q->capacity=0;
q->write_index=0;
return SH_STATUS_SUCCESS;
}

10
shelter/lib/src/std/smp.c Normal file
View File

@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/smp.h"
static sh_int16 max_cpu=-1;
void sh_smp_set_cpu_count(sh_int16 cpu_count) {
max_cpu=cpu_count;
return;
}
sh_int16 sh_smp_get_cpu_count() {
return max_cpu;
}

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/string.h"
sh_uint64 sh_string_len(char *str) {
sh_uint64 i=0;
if (!str) return 0;
while (str[i]) i++;
return i;
}
sh_bool sh_string_compare(char *str1,char *str2,sh_uint64 length) {
sh_uint64 i=0;
if (!str1 || !str2) return SH_FALSE;
while (i<length) {
if (str1[i]!=str2[i]) return SH_FALSE;
if (str1[i]=='\0' && str2[i]=='\0') return SH_TRUE;
i++;
}
return 1;
}
sh_uint64 sh_string_find_char(char *str,char character) {
sh_uint64 i=0;
if (!str) return SH_UINT64_MAX;
while (str[i]) {
if (str[i]==character) return i;
i++;
}
return SH_UINT64_MAX;
}
sh_uint64 sh_string_find(char *str,char *substr) {
sh_uint64 i=0;
sh_uint64 j=0;
if (!str || !substr) return SH_UINT64_MAX;
if (!substr[0]) return 0;
while (str[i]) {
j=0;
while (str[i+j] && substr[j] && str[i+j]==substr[j]) j++;
if (!substr[j]) return i;
i++;
}
return SH_UINT64_MAX;
}
char *sh_string_substring(char *source_str,sh_uint64 start_index,sh_uint64 length,char *output) {
sh_uint64 i=0;
if (!source_str || !output) return SH_NULLPTR;
while (i<length && source_str[start_index+i]) {
output[i]=source_str[start_index+i];
i++;
}
output[i]='\0';
return output;
}
sh_uint64 sh_string_to_uint64(char *str) {
sh_uint64 result=0;
if (!str) return SH_UINT64_MAX;
while(*str) {
if (*str<'0' || *str>'9') break;
sh_uint64 digit=(sh_uint64)(*str-'0');
if (result>(SH_UINT64_MAX-digit)/10) return SH_UINT64_MAX;
result=result*10+digit;
str++;
}
return result;
}