31 changed files with 1351 additions and 806 deletions
@ -1,7 +1,7 @@ |
|||
.vscode |
|||
disk.hdd |
|||
img_moint |
|||
limine-bootloader |
|||
limine-bootloader/ |
|||
*.o |
|||
include_cp |
|||
*.elf |
Binary file not shown.
Binary file not shown.
@ -1,55 +1,153 @@ |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
|
|||
#include "acpi.h" |
|||
#include "../common.h" |
|||
#include "../debug/assert.h" |
|||
#include "../debug/dump.h" |
|||
#include "../klib/sprintf.h" |
|||
#include "acpitables.h" |
|||
|
|||
|
|||
|
|||
bool checksum(void* table, size_t size) { |
|||
uint8_t sum = 0; |
|||
uint8_t* raw = table; |
|||
|
|||
for(size_t i;size > 0; --size) { |
|||
sum += raw[i++]; |
|||
} |
|||
return sum == 0; |
|||
} |
|||
|
|||
|
|||
typedef uint64_t rsdp_entry_t; |
|||
|
|||
|
|||
|
|||
void read_acpi_tables(void* rsdp_location) { |
|||
struct RSDPDescriptor20* rsdpd = rsdp_location; |
|||
|
|||
|
|||
dump(rsdpd, sizeof(struct RSDPDescriptor20), 8, DUMP_HEX8); |
|||
|
|||
assert(rsdpd->firstPart.revision >= 2); |
|||
|
|||
// checksum for xsdt
|
|||
assert(rsdpd->length == sizeof(rsdpd)); |
|||
assert(checksum(rsdpd, rsdpd->length)); |
|||
|
|||
|
|||
// lets parse it!!
|
|||
const struct ACPISDTHeader* xsdt = (void *)rsdpd->xsdtAddress; |
|||
|
|||
size_t n_entries = (xsdt->length - sizeof(xsdt)) / sizeof(rsdp_entry_t); |
|||
|
|||
rsdp_entry_t* table = (xsdt + 1); |
|||
|
|||
for(int i = 0; i < n_entries; i++) { |
|||
|
|||
|
|||
kprintf("%3u: %s\n", table[i]) |
|||
//table[i]
|
|||
} |
|||
} |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
|
|||
#include "acpi.h" |
|||
#include "../common.h" |
|||
#include "../debug/assert.h" |
|||
#include "../debug/dump.h" |
|||
#include "../klib/sprintf.h" |
|||
#include "../klib/string.h" |
|||
#include "acpitables.h" |
|||
#include "../int/apic.h" |
|||
|
|||
|
|||
extern struct APICConfig* apic_config; |
|||
|
|||
static bool __ATTR_PURE__ checksum(const void* table, size_t size) { |
|||
uint8_t sum = 0; |
|||
const uint8_t* raw = table; |
|||
|
|||
for(size_t i;size > 0; --size) { |
|||
sum += raw[i++]; |
|||
} |
|||
return sum == 0; |
|||
} |
|||
|
|||
static void parse_madt(const struct MADT* table); |
|||
static void parse_fadt(const struct ACPISDTHeader* table); |
|||
|
|||
|
|||
#define MADT_SIGNATURE 0x43495041 |
|||
#define FACP_SIGNATURE 0x50434146 |
|||
|
|||
void read_acpi_tables(const void* rsdp_location) { |
|||
const struct RSDPDescriptor20* rsdpd = rsdp_location; |
|||
|
|||
|
|||
assert(rsdpd->firstPart.revision >= 2); |
|||
|
|||
// checksum for xsdt
|
|||
assert(rsdpd->length == sizeof(struct RSDPDescriptor20)); |
|||
assert(checksum(rsdpd, rsdpd->length)); |
|||
|
|||
|
|||
// lets parse it!!
|
|||
const struct XSDT* xsdt = (void *)rsdpd->xsdtAddress; |
|||
|
|||
|
|||
size_t n_entries = (xsdt->header.length - sizeof(xsdt->header)) / sizeof(void*); |
|||
|
|||
|
|||
bool madt_parsed = false, |
|||
fadt_parsed = false; |
|||
|
|||
for(size_t i = 0; i < n_entries; i++) { |
|||
const struct ACPISDTHeader* table = xsdt->entries[i]; |
|||
assert(checksum(&table, table->length)); |
|||
|
|||
switch(table->signature.raw) { |
|||
case MADT_SIGNATURE: |
|||
parse_madt((const struct MADT *)table); |
|||
madt_parsed = true; |
|||
break; |
|||
case FACP_SIGNATURE: |
|||
parse_fadt(table); |
|||
fadt_parsed = true; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
kprintf("%3u: %4s\n", i, table->signature.arg); |
|||
} |
|||
|
|||
asm volatile("hlt"); |
|||
assert(madt_parsed); |
|||
assert(fadt_parsed); |
|||
} |
|||
|
|||
static void parse_madt(const struct MADT* table) { |
|||
// checksum is already done
|
|||
|
|||
apic_config = (void*)(uint64_t)table->lAPIC_address; |
|||
const void* ptr = table->entries; |
|||
const void* end = (const void*)table + table->header.length; |
|||
|
|||
/// dont override the override lapic or io apic entry
|
|||
bool override_lapic_passed = false; |
|||
bool override_ioapic_passed = false; |
|||
(void)override_lapic_passed; |
|||
(void)override_ioapic_passed; |
|||
|
|||
|
|||
kprintf("table size: %u\n", end-ptr); |
|||
while(ptr < end) { |
|||
//for(int i = 10; i>0; i--) {
|
|||
const struct MADTEntryHeader* entry_header = ptr; |
|||
|
|||
|
|||
|
|||
switch(entry_header->type) { |
|||
case APIC_TYPE_LAPIC: |
|||
{ |
|||
// const struct MADT_lapic_entry* entry = ptr;
|
|||
|
|||
} |
|||
break; |
|||
case APIC_TYPE_IO_APIC: |
|||
{ |
|||
// const struct MADT_ioapic_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
case APIC_TYPE_IO_INTERRUPT_SOURCE_OVERRIDE: |
|||
{ |
|||
// const struct MADT_ioapic_interrupt_source_override_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
case APIC_TYPE_IO_NMI: |
|||
{ |
|||
// const struct MADT_IO_NMI_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
case APIC_TYPE_LOCAL_NMI: |
|||
{ |
|||
// const struct MADT_LOCAL_NMI_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
case APIC_TYPE_LAPIC_ADDRESS_OVERRIDE: |
|||
{ |
|||
// const struct MADT_LAPIC_address_override_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
case APIC_TYPE_LAPICX2: |
|||
{ |
|||
// const struct MADT_lapicx2_entry* entry = ptr;
|
|||
} |
|||
break; |
|||
default: |
|||
kprintf("WARNING: invalid APIC MADT entry %u\n", entry_header->type); |
|||
|
|||
|
|||
} |
|||
|
|||
kprintf("entry: type %u ; size %u\n", entry_header->type,entry_header->length); |
|||
|
|||
ptr += entry_header->length; |
|||
} |
|||
} |
|||
|
|||
|
|||
static void parse_fadt(const struct ACPISDTHeader* table) { |
|||
(void) table; |
|||
} |
|||
|
|||
|
@ -1,7 +1,7 @@ |
|||
#pragma once |
|||
|
|||
/*
|
|||
|
|||
read RSDP, XSDP, MADT, FADT |
|||
*/ |
|||
void read_acpi_tables(void* rsdp_location); |
|||
#pragma once |
|||
|
|||
/*
|
|||
|
|||
read RSDP, XSDP, MADT, FADT |
|||
*/ |
|||
void read_acpi_tables(const void* rsdp_location); |
|||
|
@ -1,41 +1,141 @@ |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../common.h" |
|||
|
|||
struct RSDPDescriptor { |
|||
uint8_t signature[8]; |
|||
uint8_t checksum; |
|||
uint8_t OEMID[6]; |
|||
uint8_t revision; |
|||
uint32_t rsdtAddress; |
|||
} __packed; |
|||
|
|||
struct RSDPDescriptor20 { |
|||
struct RSDPDescriptor firstPart; |
|||
|
|||
uint32_t length; |
|||
uint64_t xsdtAddress; |
|||
uint8_t extendedChecksum; |
|||
uint8_t reserved[3]; |
|||
} __packed; |
|||
|
|||
|
|||
|
|||
// plagia from
|
|||
// https://github.com/DorianXGH/Lucarnel/blob/master/src/includes/acpi.h
|
|||
//
|
|||
struct ACPISDTHeader |
|||
{ |
|||
uint8_t signature[4]; // signature of the table
|
|||
uint32_t length; // length of the table
|
|||
uint8_t revision; |
|||
uint8_t checksum; |
|||
uint8_t OEMID[6]; |
|||
uint8_t OEMtableID[8]; |
|||
uint32_t OEMrevision; |
|||
uint32_t creatorID; |
|||
uint32_t creator_revision; |
|||
} __packed; |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../common.h" |
|||
|
|||
struct RSDPDescriptor { |
|||
uint8_t signature[8]; |
|||
uint8_t checksum; |
|||
uint8_t OEMID[6]; |
|||
uint8_t revision; |
|||
uint32_t rsdtAddress; |
|||
} __packed; |
|||
|
|||
struct RSDPDescriptor20 { |
|||
struct RSDPDescriptor firstPart; |
|||
|
|||
uint32_t length; |
|||
uint64_t xsdtAddress; |
|||
uint8_t extendedChecksum; |
|||
uint8_t reserved[3]; |
|||
} __packed; |
|||
|
|||
|
|||
union acpi_signature { |
|||
char arg[4]; |
|||
uint32_t raw; |
|||
} __packed; |
|||
|
|||
|
|||
|
|||
// plagia from
|
|||
// https://github.com/DorianXGH/Lucarnel/blob/master/src/includes/acpi.h
|
|||
//
|
|||
struct ACPISDTHeader { |
|||
union acpi_signature signature; |
|||
|
|||
uint32_t length; // length of the table
|
|||
uint8_t revision; |
|||
uint8_t checksum; |
|||
uint8_t OEMID[6]; |
|||
uint8_t OEMtableID[8]; |
|||
uint32_t OEMrevision; |
|||
uint32_t creatorID; |
|||
uint32_t creator_revision; |
|||
} __packed; |
|||
|
|||
|
|||
struct XSDT { |
|||
struct ACPISDTHeader header; |
|||
struct ACPISDTHeader* entries[]; |
|||
} __packed; |
|||
|
|||
|
|||
struct RSDT { |
|||
struct ACPISDTHeader header; |
|||
uint32_t entries[]; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADTEntryHeader { |
|||
uint8_t type; |
|||
uint8_t length; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_lapic_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t proc_apic_ID; |
|||
uint8_t procID; |
|||
uint32_t flags; // bit0: enabled
|
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_ioapic_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t id; |
|||
uint8_t reserved; |
|||
uint32_t address; |
|||
uint32_t global_system_interrupt_base; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_ioapic_interrupt_source_override_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t bus_source; |
|||
uint8_t irq_source; |
|||
uint32_t global_system_interrupt; |
|||
uint16_t flags; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_IO_NMI_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t source; |
|||
uint8_t reserved; |
|||
uint32_t global_system_interrupt; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_LOCAL_NMI_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t procID; |
|||
uint16_t flags; |
|||
uint8_t lint; // 0 or 1
|
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_LAPIC_address_override_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t procID; |
|||
uint8_t flags; |
|||
uint32_t lint; // 0 or 1
|
|||
} __packed; |
|||
|
|||
|
|||
struct MADT_lapicx2_entry { |
|||
struct MADTEntryHeader header; |
|||
uint8_t proc_lapic_ID; |
|||
uint64_t flags; // bit0: enabled
|
|||
uint32_t acpi_id; |
|||
} __packed; |
|||
|
|||
|
|||
struct MADT { |
|||
struct ACPISDTHeader header; |
|||
uint32_t lAPIC_address; |
|||
uint32_t flags; |
|||
struct MADTEntryHeader* entries[]; |
|||
} __packed; |
|||
|
|||
|
|||
// MADT entry types
|
|||
#define APIC_TYPE_LAPIC 0 |
|||
#define APIC_TYPE_IO_APIC 1 |
|||
#define APIC_TYPE_IO_INTERRUPT_SOURCE_OVERRIDE 2 |
|||
#define APIC_TYPE_IO_NMI 3 |
|||
#define APIC_TYPE_LOCAL_NMI 4 |
|||
#define APIC_TYPE_LAPIC_ADDRESS_OVERRIDE 5 |
|||
#define APIC_TYPE_LAPICX2 9 |
|||
|
@ -1,109 +1,109 @@ |
|||
#pragma once |
|||
|
|||
#include <stdint.h> |
|||
|
|||
struct cpuid_regs { |
|||
uint32_t eax, ebx, ecx, edx; |
|||
}; |
|||
|
|||
void cpuid(uint32_t eax, struct cpuid_regs* out_regs); |
|||
|
|||
|
|||
// doc from
|
|||
|
|||
/**
|
|||
* |
|||
Basic CPUID Information |
|||
Initial EAX Value Register Information Provided about the Processor |
|||
0H EAX Maximum Input Value for Basic CPUID Information (see second table) |
|||
- EBX "Genu" |
|||
- ECX "ntel" |
|||
- EDX "ineI" |
|||
01H EAX Version Information: Type, Family, Model, and Stepping ID |
|||
- EBX Bits 7-0: Brand Index |
|||
- - Bits 15-8: CLFLUSH line size (Value . 8 = cache line size in bytes) |
|||
- - Bits 23-16: Number of logical processors per physical processor; two for the Pentium 4 |
|||
processor supporting Hyper-Threading Technology |
|||
- - Bits 31-24: Local APIC ID |
|||
- ECX Extended Feature Information (see fourth table) |
|||
- EDX Feature Information (see fifth table) |
|||
02H EAX Cache and TLB Information (see sixth table) |
|||
- EBX Cache and TLB Information |
|||
- ECX Cache and TLB Information |
|||
- EDX Cache and TLB Information |
|||
03H ECX Bits 00-31 of 96 bit processor serial number. (Available in Pentium III processor only; |
|||
otherwise, the value in this register is reserved.) |
|||
- EDX Bits 32-63 of 96 bit processor serial number. (Available in Pentium III processor only; |
|||
otherwise, the value in this register is reserved.) |
|||
- - NOTE: Processor serial number (PSN) is not supported in the Pentium 4 processor or later. |
|||
On all models, use the PSN flag (returned using CPUID) to check for PSN support before |
|||
accessing the feature. See AP-485, Intel Processor Identification and the CPUID Instruction |
|||
(Order Number 241618) for more information on PSN. |
|||
04H EAX Bits 4-0: Cache Type** |
|||
- - Bits 7-5: Cache Level (starts at 1) |
|||
- - Bits 8: Self Initializing cache level (does not need SW initialization) |
|||
- - Bits 9: Fully Associative cache |
|||
- - Bits 13-10: Reserved |
|||
- - Bits 25-14: Number of threads sharing this cache* |
|||
- - Bits 31-26: Number of processor cores on this die (Multicore)* |
|||
- EBX Bits 11-00: L = System Coherency Line Size* |
|||
- - Bits 21-12: P = Physical Line partitions* |
|||
- - Bits 31-22: W = Ways of associativity* |
|||
- ECX Bits 31-00: S = Number of Sets* |
|||
- EDX Reserved = 0 |
|||
- - 0 = Null - No more caches |
|||
- - 1 = Data Cache |
|||
- - 2 = Instruction Cache |
|||
- - 3 = Unified Cache |
|||
- - 4-31 = Reserved |
|||
- - NOTE: CPUID leaves > 3 < 80000000 are only visible when IA32_CR_MISC_ENABLES.BOOT_NT4 (bit |
|||
22) is clear (Default) |
|||
5H EAX Bits 15-00: Smallest monitor-line size in bytes (default is processor's monitor granularity) |
|||
- EBX Bits 15-00: Largest monitor-line size in bytes (default is processor's monitor granularity) |
|||
|
|||
*Add one to the value in the register file to get the number. For example, the number of processor cores is EAX[31:26]+1. |
|||
** Cache Types fields |
|||
|
|||
|
|||
|
|||
Extended Function CPUID Information |
|||
Initial EAX Value Register Information Provided about the Processor |
|||
80000000H EAX Maximum Input Value for Extended Function CPUID Information (see second table). |
|||
- EBX Reserved |
|||
- ECX Reserved |
|||
- EDX Reserved |
|||
80000001H EAX Extended Processor Signature and Extended Feature Bits. (Currently reserved) |
|||
- EBX Reserved |
|||
- ECX Reserved |
|||
- EDX Reserved |
|||
80000002H EAX Processor Brand String |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000003H EAX Processor Brand String Continued |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000004H EAX Processor Brand String Continued |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000005H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
80000006H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Bits 0-7: Cache Line Size |
|||
- - Bits 15-12: L2 Associativity |
|||
- - Bits 31-16: Cache size in 1K units |
|||
- EDX Reserved = 0 |
|||
- 80000007H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
80000008H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
*/ |
|||
#pragma once |
|||
|
|||
#include <stdint.h> |
|||
|
|||
struct cpuid_regs { |
|||
uint32_t eax, ebx, ecx, edx; |
|||
}; |
|||
|
|||
void cpuid(uint32_t eax, struct cpuid_regs* out_regs); |
|||
|
|||
|
|||
// doc from
|
|||
|
|||
/**
|
|||
* |
|||
Basic CPUID Information |
|||
Initial EAX Value Register Information Provided about the Processor |
|||
0H EAX Maximum Input Value for Basic CPUID Information (see second table) |
|||
- EBX "Genu" |
|||
- ECX "ntel" |
|||
- EDX "ineI" |
|||
01H EAX Version Information: Type, Family, Model, and Stepping ID |
|||
- EBX Bits 7-0: Brand Index |
|||
- - Bits 15-8: CLFLUSH line size (Value . 8 = cache line size in bytes) |
|||
- - Bits 23-16: Number of logical processors per physical processor; two for the Pentium 4 |
|||
processor supporting Hyper-Threading Technology |
|||
- - Bits 31-24: Local APIC ID |
|||
- ECX Extended Feature Information (see fourth table) |
|||
- EDX Feature Information (see fifth table) |
|||
02H EAX Cache and TLB Information (see sixth table) |
|||
- EBX Cache and TLB Information |
|||
- ECX Cache and TLB Information |
|||
- EDX Cache and TLB Information |
|||
03H ECX Bits 00-31 of 96 bit processor serial number. (Available in Pentium III processor only; |
|||
otherwise, the value in this register is reserved.) |
|||
- EDX Bits 32-63 of 96 bit processor serial number. (Available in Pentium III processor only; |
|||
otherwise, the value in this register is reserved.) |
|||
- - NOTE: Processor serial number (PSN) is not supported in the Pentium 4 processor or later. |
|||
On all models, use the PSN flag (returned using CPUID) to check for PSN support before |
|||
accessing the feature. See AP-485, Intel Processor Identification and the CPUID Instruction |
|||
(Order Number 241618) for more information on PSN. |
|||
04H EAX Bits 4-0: Cache Type** |
|||
- - Bits 7-5: Cache Level (starts at 1) |
|||
- - Bits 8: Self Initializing cache level (does not need SW initialization) |
|||
- - Bits 9: Fully Associative cache |
|||
- - Bits 13-10: Reserved |
|||
- - Bits 25-14: Number of threads sharing this cache* |
|||
- - Bits 31-26: Number of processor cores on this die (Multicore)* |
|||
- EBX Bits 11-00: L = System Coherency Line Size* |
|||
- - Bits 21-12: P = Physical Line partitions* |
|||
- - Bits 31-22: W = Ways of associativity* |
|||
- ECX Bits 31-00: S = Number of Sets* |
|||
- EDX Reserved = 0 |
|||
- - 0 = Null - No more caches |
|||
- - 1 = Data Cache |
|||
- - 2 = Instruction Cache |
|||
- - 3 = Unified Cache |
|||
- - 4-31 = Reserved |
|||
- - NOTE: CPUID leaves > 3 < 80000000 are only visible when IA32_CR_MISC_ENABLES.BOOT_NT4 (bit |
|||
22) is clear (Default) |
|||
5H EAX Bits 15-00: Smallest monitor-line size in bytes (default is processor's monitor granularity) |
|||
- EBX Bits 15-00: Largest monitor-line size in bytes (default is processor's monitor granularity) |
|||
|
|||
*Add one to the value in the register file to get the number. For example, the number of processor cores is EAX[31:26]+1. |
|||
** Cache Types fields |
|||
|
|||
|
|||
|
|||
Extended Function CPUID Information |
|||
Initial EAX Value Register Information Provided about the Processor |
|||
80000000H EAX Maximum Input Value for Extended Function CPUID Information (see second table). |
|||
- EBX Reserved |
|||
- ECX Reserved |
|||
- EDX Reserved |
|||
80000001H EAX Extended Processor Signature and Extended Feature Bits. (Currently reserved) |
|||
- EBX Reserved |
|||
- ECX Reserved |
|||
- EDX Reserved |
|||
80000002H EAX Processor Brand String |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000003H EAX Processor Brand String Continued |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000004H EAX Processor Brand String Continued |
|||
- EBX Processor Brand String Continued |
|||
- ECX Processor Brand String Continued |
|||
- EDX Processor Brand String Continued |
|||
80000005H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
80000006H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Bits 0-7: Cache Line Size |
|||
- - Bits 15-12: L2 Associativity |
|||
- - Bits 31-16: Cache size in 1K units |
|||
- EDX Reserved = 0 |
|||
- 80000007H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
80000008H EAX Reserved = 0 |
|||
- EBX Reserved = 0 |
|||
- ECX Reserved = 0 |
|||
- EDX Reserved = 0 |
|||
*/ |
|||
|
@ -1,26 +1,26 @@ |
|||
[section .text] |
|||
[global cpuid] |
|||
|
|||
;struct cpuid_regs { |
|||
; uint32_t eax, ebx, ecx, edx; |
|||
;} |
|||
|
|||
|
|||
; void cpuid(uint32_t eax, struct cpuid_regs* out_regs); |
|||
cpuid: |
|||
push ebp |
|||
mov ebp, esp |
|||
push rbx |
|||
|
|||
mov eax, edi |
|||
cpuid |
|||
|
|||
mov [rdi + 0], eax |
|||
mov [rdi + 4], ebx |
|||
mov [rdi + 8], ecx |
|||
mov [rdi + 12], edx |
|||
|
|||
|
|||
pop rbx |
|||
leave |
|||
[section .text] |
|||
[global cpuid] |
|||
|
|||
;struct cpuid_regs { |
|||
; uint32_t eax, ebx, ecx, edx; |
|||
;} |
|||
|
|||
|
|||
; void cpuid(uint32_t eax, struct cpuid_regs* out_regs); |
|||
cpuid: |
|||
push ebp |
|||
mov ebp, esp |
|||
push rbx |
|||
|
|||
mov eax, edi |
|||
cpuid |
|||
|
|||
mov [rdi + 0], eax |
|||
mov [rdi + 4], ebx |
|||
mov [rdi + 8], ecx |
|||
mov [rdi + 12], edx |
|||
|
|||
|
|||
pop rbx |
|||
leave |
|||
ret |
@ -1,116 +1,115 @@ |
|||
#include "dump.h" |
|||
#include "../klib/sprintf.h" |
|||
|
|||
/**
|
|||
* dump a memory chunk in kprintf |
|||
* addr: address of the beginning of the chunk |
|||
* size: number of bytes to dump |
|||
* line_size: number of words per line |
|||
* |
|||
* mode: either |
|||
* DUMP_HEX8 : hexadecimal integers of size 8 bits |
|||
* DUMP_HEX32 : hexadecimal integers of size 32 bits |
|||
* DUMP_HEX64 : hexadecimal integers of size 64 bits |
|||
* DUMP_DEC8 : decimal integers of size 8 bits |
|||
* DUMP_DEC32 : decimal integers of size 32 bits |
|||
* DUMP_DEC64 : decimal integers of size 64 bits |
|||
* |
|||
**/ |
|||
void dump(const void* addr, size_t size, size_t line_size, uint8_t mode) { |
|||
|
|||
char row_fmt[8], last_row_fmt[8]; |
|||
|
|||
size_t pitch; // sizeof word
|
|||
|
|||
int i = 0; |
|||
row_fmt [i] = '%'; |
|||
last_row_fmt[i] = '%'; |
|||
i++; |
|||
|
|||
|
|||
// create fmts for printf
|
|||
|
|||
// word width
|
|||
if((mode & DUMP_8) != 0) { |
|||
// byte mode
|
|||
|
|||
row_fmt [i] = '2'; |
|||
last_row_fmt[i] = '2'; |
|||
i++; |
|||
|
|||
pitch = 1; |
|||
} |
|||
else if((mode & DUMP_64) == 0) { |
|||
// normal 32bit mode
|
|||
|
|||
row_fmt [i] = '8'; |
|||
last_row_fmt[i] = '8'; |
|||
i++; |
|||
|
|||
pitch = 4; |
|||
} |
|||
else { |
|||
// long mode
|
|||
row_fmt [i] = 'l'; |
|||
last_row_fmt[i] = 'l'; |
|||
i++; |
|||
row_fmt [i] = '1'; |
|||
last_row_fmt[i] = '1'; |
|||
i++; |
|||
row_fmt [i] = '6'; |
|||
last_row_fmt[i] = '6'; |
|||
i++; |
|||
|
|||
pitch = 8; |
|||
} |
|||
|
|||
// base
|
|||
char base_id; |
|||
|
|||
|
|||
if((mode & DUMP_HEX) == 0) // hex
|
|||
base_id = 'x'; |
|||
else // dec
|
|||
base_id = 'u'; |
|||
|
|||
row_fmt [i] = base_id; |
|||
last_row_fmt[i] = base_id; |
|||
i++; |
|||
|
|||
row_fmt [i] = ' '; |
|||
last_row_fmt[i] = '\n'; |
|||
i++; |
|||
|
|||
row_fmt [i] = '\0'; |
|||
last_row_fmt[i] = '\0'; |
|||
i++; |
|||
|
|||
|
|||
|
|||
size /= pitch; |
|||
size_t lines = (size + line_size - 1) / line_size; |
|||
|
|||
// iterator ptr
|
|||
const uint8_t* ptr = addr; |
|||
|
|||
// create mask : create the complementary with 0xff...ff << n
|
|||
// then complement it
|
|||
const uint64_t mask = ~(~0llu << 8*pitch); |
|||
|
|||
for(size_t i = 0; i < lines; i++) { |
|||
// the last line might not be full
|
|||
// therefore we have to check each one
|
|||
|
|||
for(size_t j = 0; j < line_size-1; j++) { |
|||
if(size-- <= 1) |
|||
break; |
|||
else { |
|||
kprintf(row_fmt, *(uint64_t *)ptr & mask); |
|||
ptr+=pitch; |
|||
} |
|||
|
|||
} |
|||
kprintf(last_row_fmt, *(uint64_t *)ptr & mask); |
|||
ptr+=pitch; |
|||
} |
|||
} |
|||
#include "dump.h" |
|||
#include "../klib/sprintf.h" |
|||
|
|||
/**
|
|||
* dump a memory chunk in kprintf |
|||
* addr: address of the beginning of the chunk |
|||
* size: number of bytes to dump |
|||
* line_size: number of words per line |
|||
* |
|||
* mode: either |
|||
* DUMP_HEX8 : hexadecimal integers of size 8 bits |
|||
* DUMP_HEX32 : hexadecimal integers of size 32 bits |
|||
* DUMP_HEX64 : hexadecimal integers of size 64 bits |
|||
* DUMP_DEC8 : decimal integers of size 8 bits |
|||
* DUMP_DEC32 : decimal integers of size 32 bits |
|||
* DUMP_DEC64 : decimal integers of size 64 bits |
|||
* |
|||
**/ |
|||
void dump(const void* addr, size_t size, size_t line_size, uint8_t mode) { |
|||
|
|||
char row_fmt[16], last_row_fmt[16]; |
|||
|
|||
size_t pitch; // sizeof word
|
|||
|
|||
int i = 0; |
|||
row_fmt [i] = '%'; |
|||
last_row_fmt[i] = '%'; |
|||
i++; |
|||
|
|||
|
|||
// create fmts for printf
|
|||
|
|||
// word width
|
|||
if((mode & DUMP_8) != 0) { |
|||
// byte mode
|
|||
|
|||
row_fmt [i] = '2'; |
|||
last_row_fmt[i] = '2'; |
|||
i++; |
|||
|
|||
pitch = 1; |
|||
} |
|||
else if((mode & DUMP_64) == 0) { |
|||
// normal 32bit mode
|
|||
|
|||
row_fmt [i] = '8'; |
|||
last_row_fmt[i] = '8'; |
|||
i++; |
|||
|
|||
pitch = 4; |
|||
} |
|||
else { |
|||
// long mode
|
|||
row_fmt [i] = 'l'; |
|||
last_row_fmt[i] = 'l'; |
|||
i++; |
|||
row_fmt [i] = '1'; |
|||
last_row_fmt[i] = '1'; |
|||
i++; |
|||
row_fmt [i] = '6'; |
|||
last_row_fmt[i] = '6'; |
|||
i++; |
|||
|
|||
pitch = 8; |
|||
} |
|||
|
|||
// base
|
|||
char base_id; |
|||
|
|||
|
|||
if((mode & DUMP_HEX) == 0) // hex
|
|||
base_id = 'x'; |
|||
else // dec
|
|||
base_id = 'u'; |
|||
|
|||
row_fmt [i] = base_id; |
|||
last_row_fmt[i] = base_id; |
|||
i++; |
|||
|
|||
row_fmt [i] = ' '; |
|||
last_row_fmt[i] = '\n'; |
|||
i++; |
|||
|
|||
row_fmt [i] = '\0'; |
|||
last_row_fmt[i] = '\0'; |
|||
i++; |
|||
|
|||
|
|||
|
|||
size /= pitch; |
|||
size_t lines = (size + line_size - 1) / line_size; |
|||
|
|||
// iterator ptr
|
|||
const uint8_t* ptr = addr; |
|||
|
|||
// create mask : create the complementary with 0xff...ff << n
|
|||
// then complement it
|
|||
const uint64_t mask = ~(~0llu << 8*pitch); |
|||
|
|||
for(size_t i = 0; i < lines; i++) { |
|||
// the last line might not be full
|
|||
// therefore we have to check each one
|
|||
|
|||
for(size_t j = 0; j < line_size-1; j++) { |
|||
if(size-- <= 1) |
|||
break; |
|||
else { |
|||
kprintf(row_fmt, *(uint64_t *)ptr & mask); |
|||
ptr+=pitch; |
|||
} |
|||
} |
|||
kprintf(last_row_fmt, *(uint64_t *)ptr & mask); |
|||
ptr+=pitch; |
|||
} |
|||
} |
|||
|
@ -1,23 +1,23 @@ |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
|
|||
|
|||
#define DUMP_HEX 0 |
|||
#define DUMP_DEC 16 |
|||
|
|||
#define DUMP_8 32 |
|||
#define DUMP_32 0 |
|||
#define DUMP_64 1 |
|||
|
|||
#define DUMP_HEX8 (DUMP_HEX | DUMP_8) |
|||
#define DUMP_HEX32 (DUMP_HEX | DUMP_32) |
|||
#define DUMP_HEX64 (DUMP_HEX | DUMP_64) |
|||
#define DUMP_DEC8 (DUMP_DEC | DUMP_8) |
|||
#define DUMP_DEC32 (DUMP_DEC | DUMP_32) |
|||
#define DUMP_DEC64 (DUMP_DEC | DUMP_64) |
|||
|
|||
|
|||
void dump(const void* addr, size_t size, size_t line_size, uint8_t mode); |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
|
|||
|
|||
#define DUMP_HEX 0 |
|||
#define DUMP_DEC 16 |
|||
|
|||
#define DUMP_8 32 |
|||
#define DUMP_32 0 |
|||
#define DUMP_64 1 |
|||
|
|||
#define DUMP_HEX8 (DUMP_HEX | DUMP_8) |
|||
#define DUMP_HEX32 (DUMP_HEX | DUMP_32) |
|||
#define DUMP_HEX64 (DUMP_HEX | DUMP_64) |
|||
#define DUMP_DEC8 (DUMP_DEC | DUMP_8) |
|||
#define DUMP_DEC32 (DUMP_DEC | DUMP_32) |
|||
#define DUMP_DEC64 (DUMP_DEC | DUMP_64) |
|||
|
|||
|
|||
void dump(const void* addr, size_t size, size_t line_size, uint8_t mode); |
|||
|
@ -0,0 +1,95 @@ |
|||
#include <stdint.h> |
|||
|
|||
#include "../debug/assert.h" |
|||
#include "idt.h" |
|||
#include "apic.h" |
|||
#include "../klib/sprintf.h" |
|||
|
|||
#define LAPIC_TIMER_IRQ 0xff |
|||
|
|||
struct APICConfig* apic_config = NULL; |
|||
|
|||
|
|||
void outb(uint16_t dx, uint16_t al); |
|||
uint8_t inb(uint16_t dx); |
|||
|
|||
|
|||
static void pit_wait(size_t ms) { |
|||
outb(0x43, 0x30); |
|||
uint16_t val = 0x4a9 * ms; |
|||
outb(0x40, (uint8_t)val); |
|||
outb(0x40, (uint8_t)(val >> 8)); |
|||
for(;;) { |
|||
outb(0x43, 0xe2); |
|||
uint8_t status = inb(0x40); |
|||
if ((status & (1 << 7)) != 0) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
static unsigned read_pit_count(void) { |
|||
unsigned count = 0; |
|||
|
|||
// Disable interrupts
|
|||
uint64_t rf = get_rflags(); |
|||
_cli(); |
|||
|
|||
// al = channel in bits 6 and 7, remaining bits clear
|
|||
outb(0x43,0b0000000); |
|||
|
|||
count = inb(0x40); // Low byte
|
|||
count |= inb(0x40)<<8; // High byte
|
|||
|
|||
|
|||
set_rflags(rf); |
|||
|
|||
return count; |
|||
} |
|||
|
|||
|
|||
uint64_t apic_timer_clock_count = 0; |
|||
|
|||
|
|||
__attribute__((interrupt)) void lapic_timer_handler(struct IFrame* frame) { |
|||
(void) frame; |
|||
++apic_timer_clock_count; |
|||
|
|||
kprintf("%x\n", apic_timer_clock_count); |
|||
|
|||
apic_config->end_of_interrupt.reg = 0; |
|||
} |
|||
|
|||
|
|||
uint64_t clock(void) { |
|||
return apic_timer_clock_count; |
|||
} |
|||
|
|||
void apic_setup_clock(void) { |
|||
assert(apic_config != NULL); |
|||
|
|||
set_irq_handler(LAPIC_TIMER_IRQ, lapic_timer_handler); |
|||
|
|||
// disable apic and set spurious int to 32
|
|||
apic_config->spurious_interrupt_vector.reg = 0 | LAPIC_TIMER_IRQ; |
|||
|
|||
apic_config->timer_divide_configuration.reg = 2; // divide by 8
|
|||
apic_config->timer_initial_count.reg = UINT32_MAX; |
|||
|
|||
pit_wait(1); /// wait for 1 ms
|
|||
|
|||
//apic_config->timer_initial_count.reg = UINT32_MAX - apic_config->timer_current_count.reg;
|
|||
|
|||
|
|||
for(int i = 0; i < 1000000000; i++) { |
|||
kprintf("%x\t%x\n", apic_config->timer_current_count.reg, read_pit_count()); |
|||
|
|||
// asm volatile("hlt");
|
|||
} |
|||
// count
|
|||
|
|||
|
|||
// enable the clock irqs
|
|||
apic_config->spurious_interrupt_vector.reg = 0x100 | LAPIC_TIMER_IRQ; |
|||
} |
|||
|
@ -0,0 +1,53 @@ |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
#include "../debug/assert.h" |
|||
|
|||
|
|||
struct APICRegister |
|||
{ |
|||
uint32_t reg; |
|||
uint32_t reserved[3]; |
|||
}; |
|||
static_assert(sizeof(struct APICRegister) == 16); |
|||
|
|||
struct APICConfig |
|||
{ |
|||
struct APICRegister reserved1[2]; //
|
|||
struct APICRegister LAPIC_ID; // RW
|
|||
struct APICRegister LAPIC_version; // R
|
|||
struct APICRegister reserved2[4]; //
|
|||
struct APICRegister task_priority; // RW
|
|||
struct APICRegister arbitration_priority; // R
|
|||
struct APICRegister processor_priority; // R
|
|||
struct APICRegister end_of_interrupt; // W
|
|||
struct APICRegister remote_read; // R
|
|||
struct APICRegister logical_destination; // RW
|
|||
struct APICRegister destination_format; // RW
|
|||
struct APICRegister spurious_interrupt_vector; // RW
|
|||
struct APICRegister in_service[8]; // R
|
|||
struct APICRegister trigger_mode[8]; // R
|
|||
struct APICRegister interrupt_request[8]; // R
|
|||
struct APICRegister error_status; // R
|
|||
struct APICRegister reserved3[6]; //
|
|||
struct APICRegister LVT_corrected_machine_check_interrupt;// RW
|
|||
struct APICRegister interrupt_command[2]; // RW
|
|||
struct APICRegister LVT_timer; // RW
|
|||
struct APICRegister LVT_thermal_sensor; // RW
|
|||
struct APICRegister LVT_performance_monitoring_counters; // RW
|
|||
struct APICRegister LVT_LINT0; // RW
|
|||
struct APICRegister LVT_LINT1; // RW
|
|||
struct APICRegister LVT_error; // RW
|
|||
struct APICRegister timer_initial_count; // RW
|
|||
struct APICRegister timer_current_count; // R
|
|||
struct APICRegister reserved4[4]; //
|
|||
struct APICRegister timer_divide_configuration; // RW
|
|||
struct APICRegister reserved5; //
|
|||
|
|||
}; |
|||
static_assert(sizeof(struct APICConfig) == 0x400); |
|||
|
|||
|
|||
void apic_setup_clock(void); |
|||
uint64_t clock(void); |
@ -1,98 +1,124 @@ |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../common.h" |
|||
#include "idt.h" |
|||
|
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t size; |
|||
const void* offset; |
|||
} __packed IDTD; |
|||
|
|||
|
|||
typedef struct { |
|||
uint8_t gate_type: 4; |
|||
uint8_t z : 1; |
|||
uint8_t dpl : 2; |
|||
uint8_t p : 1; |
|||
} __packed type_attr_t; |
|||
|
|||
|
|||
static_assert(sizeof(type_attr_t) == 1); |
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t offset_1; // offset bits 0..15
|
|||
uint16_t selector; // a code segment selector in GDT or LDT
|
|||
uint8_t ist; // bits 0..2 holds Interrupt
|
|||
// Stack Table offset, rest of bits zero.
|
|||
|
|||
type_attr_t type_attr; // type and attributes
|
|||
uint16_t offset_2; // offset bits 16..31
|
|||
uint32_t offset_3; // offset bits 32..63
|
|||
uint32_t zero; // reserved
|
|||
} __packed IDTE; |
|||
|
|||
|
|||
|
|||
IDTE idt[256] = {0}; |
|||
|
|||
void _lidt(IDTD* idtd); |
|||
|
|||
void setup_idt(void) { |
|||
IDTD idt_descriptor = { |
|||
.size = 255 * sizeof(IDTE), |
|||
.offset = idt, |
|||
}; |
|||
|
|||
_lidt(&idt_descriptor); |
|||
} |
|||
|
|||
|
|||
static type_attr_t make_type_attr_t(uint8_t gate_type) { |
|||
|
|||
assert((gate_type & 0xf0) == 0); |
|||
|
|||
return (type_attr_t) { |
|||
.gate_type = gate_type, |
|||
.z = 0, |
|||
.dpl = 0, |
|||
.p = 1, |
|||
}; |
|||
} |
|||
|
|||
|
|||
static IDTE make_idte(void* handler, type_attr_t type_attr) { |
|||
uint64_t h = (uint64_t) handler; |
|||
|
|||
return (IDTE) { |
|||
.offset_1 = h & 0xffff, |
|||
.selector = 0x08, // kernel code segment
|
|||
.ist = 0, |
|||
.type_attr = type_attr, |
|||
.offset_2 = (h >> 16) & 0xffff, |
|||
.offset_3 = (h >> 32) & 0xffffffff, |
|||
.zero = 0, |
|||
}; |
|||
} |
|||
|
|||
static IDTE make_isr(void* handler) { |
|||
return make_idte(handler, make_type_attr_t(ATTR_64_GATE)); |
|||
} |
|||
|
|||
|
|||
void set_interrupt_handler(uint16_t number, void* handler) { |
|||
idt[number] = make_isr(handler); |
|||
} |
|||
|
|||
|
|||
void _cli(void) { |
|||
asm volatile("cli"); |
|||
} |
|||
|
|||
|
|||
void _sti(void) { |
|||
asm volatile("sti"); |
|||
} |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../common.h" |
|||
#include "idt.h" |
|||
|
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t size; |
|||
const void* offset; |
|||
} __packed IDTD; |
|||
|
|||
|
|||
typedef struct { |
|||
uint8_t gate_type: 4; |
|||
uint8_t z : 1; |
|||
uint8_t dpl : 2; |
|||
uint8_t p : 1; |
|||
} __packed type_attr_t; |
|||
|
|||
|
|||
static_assert(sizeof(type_attr_t) == 1); |
|||
|
|||
|
|||
typedef struct { |
|||
uint16_t offset_1; // offset bits 0..15
|
|||
uint16_t selector; // a code segment selector in GDT or LDT
|
|||
uint8_t ist; // bits 0..2 holds Interrupt
|
|||
// Stack Table offset, rest of bits zero.
|
|||
|
|||
type_attr_t type_attr; // type and attributes
|
|||
uint16_t offset_2; // offset bits 16..31
|
|||
uint32_t offset_3; // offset bits 32..63
|
|||
uint32_t zero; // reserved
|
|||
} __packed IDTE; |
|||
|
|||
|
|||
|
|||
IDTE idt[256] = {0}; |
|||
|
|||
void _lidt(IDTD* idtd); |
|||
|
|||
void setup_idt(void) { |
|||
IDTD idt_descriptor = { |
|||
.size = 255 * sizeof(IDTE), |
|||
.offset = idt, |
|||
}; |
|||
|
|||
_lidt(&idt_descriptor); |
|||
} |
|||
|
|||
|
|||
static type_attr_t make_type_attr_t(uint8_t gate_type) { |
|||
|
|||
assert((gate_type & 0xf0) == 0); |
|||
|
|||
return (type_attr_t) { |
|||
.gate_type = gate_type, |
|||
.z = 0, |
|||
.dpl = 0, |
|||
.p = 1, |
|||
}; |
|||
} |
|||
|
|||
|
|||
static IDTE make_idte(void* handler, type_attr_t type_attr) { |
|||
uint64_t h = (uint64_t) handler; |
|||
|
|||
return (IDTE) { |
|||
.offset_1 = h & 0xffff, |
|||
.selector = 0x08, // kernel code segment
|
|||
.ist = 0, |
|||
.type_attr = type_attr, |
|||
.offset_2 = (h >> 16) & 0xffff, |
|||
.offset_3 = (h >> 32) & 0xffffffff, |
|||
.zero = 0, |
|||
}; |
|||
} |
|||
|
|||
static IDTE make_isr(void* handler) { |
|||
return make_idte(handler, make_type_attr_t(ATTR_64_GATE)); |
|||
} |
|||
static IDTE make_irq(void* handler) { |
|||
return make_idte(handler, make_type_attr_t(ATTR_64_TRAP)); |
|||
} |
|||
|
|||
|
|||
void set_rflags(uint64_t RFLAGS); |
|||
uint64_t get_rflags(void); |
|||
|
|||
|
|||
void set_irs_handler(uint16_t number, void* handler) { |
|||
// make sure to disable interrupts
|
|||
// while updating the idt
|
|||
// then save IF to its old state
|
|||
uint64_t rflags = get_rflags(); |
|||
_cli(); |
|||
|
|||
idt[number] = make_isr(handler); |
|||
|
|||
set_rflags(rflags); |
|||
} |
|||
|
|||
|
|||
void set_irq_handler(uint16_t number, void* handler) { |
|||
// same as above
|
|||
uint64_t rflags = get_rflags(); |
|||
_cli(); |
|||
|
|||
idt[number] = make_irq(handler); |
|||
|
|||
set_rflags(rflags); |
|||
} |
|||
|
|||
|
|||
void _cli(void) { |
|||
asm volatile("cli"); |
|||
} |
|||
|
|||
|
|||
void _sti(void) { |
|||
asm volatile("sti"); |
|||
} |
|||
|
@ -1,35 +1,37 @@ |
|||
#ifndef IDT_H |
|||
#define IDT_H |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
#include "../debug/assert.h" |
|||
|
|||
#define ATTR_64_GATE 0b1110 |
|||
#define ATTR_64_TRAP 0b1110 |
|||
|
|||
|
|||
|
|||
struct IFrame { |
|||
uint64_t RIP; |
|||
uint64_t CS; |
|||
uint64_t RFLAGS; |
|||
uint64_t RSP; |
|||
uint64_t SS; |
|||
} __packed; |
|||
|
|||
static_assert(sizeof(struct IFrame) == 40); |
|||
|
|||
|
|||
|
|||
void setup_idt(void); |
|||
|
|||
void set_interrupt_handler(uint16_t number, void* handler); |
|||
void _cli(void); |
|||
void _sti(void); |
|||
|
|||
|
|||
void setup_isr(void); |
|||
|
|||
|
|||
#ifndef IDT_H |
|||
#define IDT_H |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
#include "../debug/assert.h" |
|||
#include |