forked from lolo859/vystem
Vystem 0.2
This commit is contained in:
56
shelter/lib/include/cpu/ap.h
Normal file
56
shelter/lib/include/cpu/ap.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
17
shelter/lib/include/cpu/pic.h
Normal file
17
shelter/lib/include/cpu/pic.h
Normal 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
|
||||
7
shelter/lib/include/cpu/pit.h
Normal file
7
shelter/lib/include/cpu/pit.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
65
shelter/lib/include/devs/acpi.h
Normal file
65
shelter/lib/include/devs/acpi.h
Normal 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
|
||||
53
shelter/lib/include/devs/acpi_tables/madt.h
Normal file
53
shelter/lib/include/devs/acpi_tables/madt.h
Normal 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
|
||||
70
shelter/lib/include/devs/apic/ioapic.h
Normal file
70
shelter/lib/include/devs/apic/ioapic.h
Normal 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
|
||||
83
shelter/lib/include/devs/apic/lapic.h
Normal file
83
shelter/lib/include/devs/apic/lapic.h
Normal 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
|
||||
21
shelter/lib/include/devs/devs.h
Normal file
21
shelter/lib/include/devs/devs.h
Normal 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
|
||||
39
shelter/lib/include/devs/input/event.h
Normal file
39
shelter/lib/include/devs/input/event.h
Normal 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
|
||||
52
shelter/lib/include/devs/input/kbd.h
Normal file
52
shelter/lib/include/devs/input/kbd.h
Normal 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
|
||||
105
shelter/lib/include/devs/input/ps2.h
Normal file
105
shelter/lib/include/devs/input/ps2.h
Normal 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
|
||||
126
shelter/lib/include/irq/gdt.h
Normal file
126
shelter/lib/include/irq/gdt.h
Normal 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
|
||||
62
shelter/lib/include/irq/gsi.h
Normal file
62
shelter/lib/include/irq/gsi.h
Normal 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
|
||||
41
shelter/lib/include/irq/idt.h
Normal file
41
shelter/lib/include/irq/idt.h
Normal 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
|
||||
57
shelter/lib/include/irq/irq.h
Normal file
57
shelter/lib/include/irq/irq.h
Normal 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
|
||||
39
shelter/lib/include/irq/tss.h
Normal file
39
shelter/lib/include/irq/tss.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
12
shelter/lib/include/kernel/efifb.h
Normal file
12
shelter/lib/include/kernel/efifb.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
10
shelter/lib/include/kernel/tests/payloads/test_pez_payload.h
Normal file
10
shelter/lib/include/kernel/tests/payloads/test_pez_payload.h
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8
shelter/lib/include/kernel/tests/test_queues.h
Normal file
8
shelter/lib/include/kernel/tests/test_queues.h
Normal 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
|
||||
@@ -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.
|
||||
|
||||
26
shelter/lib/include/memory/memory.h
Normal file
26
shelter/lib/include/memory/memory.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
29
shelter/lib/include/std/print.h
Normal file
29
shelter/lib/include/std/print.h
Normal 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
|
||||
19
shelter/lib/include/std/queue.h
Normal file
19
shelter/lib/include/std/queue.h
Normal 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
|
||||
74
shelter/lib/include/std/smp.h
Normal file
74
shelter/lib/include/std/smp.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
17
shelter/lib/include/std/string.h
Normal file
17
shelter/lib/include/std/string.h
Normal 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
151
shelter/lib/src/cpu/ap.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
112
shelter/lib/src/cpu/ap_boot.asm
Normal file
112
shelter/lib/src/cpu/ap_boot.asm
Normal 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
45
shelter/lib/src/cpu/pic.c
Normal 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);
|
||||
}
|
||||
9
shelter/lib/src/cpu/pit.c
Normal file
9
shelter/lib/src/cpu/pit.c
Normal 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));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
97
shelter/lib/src/devs/acpi.c
Normal file
97
shelter/lib/src/devs/acpi.c
Normal 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;
|
||||
}
|
||||
102
shelter/lib/src/devs/acpi_tables/madt.c
Normal file
102
shelter/lib/src/devs/acpi_tables/madt.c
Normal 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;
|
||||
}
|
||||
175
shelter/lib/src/devs/apic/ioapic.c
Normal file
175
shelter/lib/src/devs/apic/ioapic.c
Normal 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;
|
||||
}
|
||||
286
shelter/lib/src/devs/apic/lapic.c
Normal file
286
shelter/lib/src/devs/apic/lapic.c
Normal 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;
|
||||
}
|
||||
56
shelter/lib/src/devs/devs.c
Normal file
56
shelter/lib/src/devs/devs.c
Normal 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;
|
||||
}
|
||||
}
|
||||
340
shelter/lib/src/devs/input/kbd.c
Normal file
340
shelter/lib/src/devs/input/kbd.c
Normal 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;
|
||||
}
|
||||
777
shelter/lib/src/devs/input/ps2.c
Normal file
777
shelter/lib/src/devs/input/ps2.c
Normal 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
83
shelter/lib/src/irq/gdt.c
Normal 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;
|
||||
}
|
||||
21
shelter/lib/src/irq/gdt_reload.asm
Normal file
21
shelter/lib/src/irq/gdt_reload.asm
Normal 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
182
shelter/lib/src/irq/gsi.c
Normal 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
109
shelter/lib/src/irq/idt.c
Normal 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
243
shelter/lib/src/irq/irq.c
Normal 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;
|
||||
}
|
||||
}
|
||||
86
shelter/lib/src/irq/irq_handler.asm
Normal file
86
shelter/lib/src/irq/irq_handler.asm
Normal 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
30
shelter/lib/src/irq/tss.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
95
shelter/lib/src/kernel/efifb.c
Normal file
95
shelter/lib/src/kernel/efifb.c
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
35
shelter/lib/src/kernel/tests/test_queues.c
Normal file
35
shelter/lib/src/kernel/tests/test_queues.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
284
shelter/lib/src/memory/memory.c
Normal file
284
shelter/lib/src/memory/memory.c
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
886
shelter/lib/src/std/print.c
Normal 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;
|
||||
}
|
||||
28
shelter/lib/src/std/queue.c
Normal file
28
shelter/lib/src/std/queue.c
Normal 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
10
shelter/lib/src/std/smp.c
Normal 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;
|
||||
}
|
||||
62
shelter/lib/src/std/string.c
Normal file
62
shelter/lib/src/std/string.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user