diff options
| author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 | 
|---|---|---|
| committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 | 
| commit | 866912eb5f7906da2545f27f7bbef01a7d61c87f (patch) | |
| tree | 2472110bcf868837d84893bc257edcbafefe5a59 /src | |
| parent | 5e12467c860372dfa10323365fb0df9db79c8f9b (diff) | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/acpi.c | 89 | ||||
| -rw-r--r-- | src/apic.c | 121 | ||||
| -rw-r--r-- | src/keyboard.c | 25 | 
3 files changed, 235 insertions, 0 deletions
diff --git a/src/acpi.c b/src/acpi.c new file mode 100644 index 0000000..5cee000 --- /dev/null +++ b/src/acpi.c @@ -0,0 +1,89 @@ +#include "aplos.h" + +enum { +	SDT_HEADER_SIZE = 36, +	SDT_LENGTH_OFFSET = 4, + +	RSDT_VERSION_OFFSET = 15, +	RSDT_VENDOR_OFFSET = 9, +	RSDT_VENDOR_SIZE = 6, +	RSDT_RSDP_OFFSET = 16 +}; + +static uint8_t *rsdp; +static uint8_t *rsdt; +static uint8_t *madt; + +static void parse_rsdt(uint64_t); +static void parse_madt(struct ioapic_info *); +static uint8_t *map_sdt(uint64_t); + +void +setup_acpi(uint64_t rsdp_physical, struct ioapic_info *ioapic) +{ +	rsdp = (uint8_t *)map_page(rsdp_physical, 1, true); +	uint8_t version = rsdp[RSDT_VERSION_OFFSET]; +	char8_t vendor[RSDT_VENDOR_SIZE+1]; +	memcpy(vendor, rsdp+RSDT_VENDOR_OFFSET, RSDT_VENDOR_SIZE);	 +	vendor[RSDT_VENDOR_SIZE] = 0; + +	switch(version){ +	case 0: +		parse_rsdt(read_uint32_le(rsdp+RSDT_RSDP_OFFSET)); +		break; +	default: +		print(u8"Unknown RSDP version :(\n"); +		panic(); +	} + +	parse_madt(ioapic); +} + +void +parse_rsdt(uint64_t rsdt_physical) +{ +	rsdt = map_sdt(rsdt_physical); +	uint32_t length = read_uint32_le(rsdt+SDT_LENGTH_OFFSET); +	uint32_t entries = (length - SDT_HEADER_SIZE) / 4; + +	uint32_t *ptrs = (uint32_t *)(((uint64_t)rsdt)+SDT_HEADER_SIZE); +	for(uint32_t i = 0; i < entries; i++){ +		uint8_t *ptr = map_sdt(ptrs[i]); +		if(utf8_cmp_n(ptr, u8"APIC", 4) == 0) +			madt = ptr; +	} +} + +void +parse_madt(struct ioapic_info *ioapic) +{ +	assert(madt != NULL); + +	uint32_t length = read_uint32_le(madt+SDT_LENGTH_OFFSET); +	uint32_t offset = SDT_HEADER_SIZE + 8; +	while(offset < length){ +		uint8_t type = madt[offset]; +		uint8_t record_length = madt[offset+1]; +		switch(type){ +		case 1: +			/* I/O APIC */ +			ioapic->base = read_uint32_le(madt+offset+4); +			ioapic->interrupt_base = read_uint32_le(madt+offset+8); +			break; +		} +		offset += record_length; +	} +} + +static uint8_t * +map_sdt(uint64_t sdt_physical) +{ +	uint8_t *p = (uint8_t *)map_page(sdt_physical, 1, true);	 +	uint32_t length = read_uint32_le(p+4); +	uint32_t pages = (length + PAGE_SIZE - 1) / PAGE_SIZE; +	if(pages > 1){ +		/* Remap the thing */ +		p = (uint8_t *)map_page(sdt_physical, pages, true); +	} +	return p; +} diff --git a/src/apic.c b/src/apic.c new file mode 100644 index 0000000..26adfae --- /dev/null +++ b/src/apic.c @@ -0,0 +1,121 @@ +#include "aplos.h" + +enum { +	APIC_BASE = 0x1B, + +	SPURIOUS_INTERRUPT_VECTOR = 0xF0, +	END_OF_INTERRUPT = 0xB0 +}; + +static volatile uint32_t *apic_base; +static volatile uint8_t *ioapic_reg; +static volatile uint32_t *ioapic_data; +static uint8_t ioapic_max_entries; + +static uint32_t read_apic_reg(uint64_t); +static void write_apic_reg(uint64_t, uint32_t); +static uint32_t read_ioapic_reg(uint8_t); +static void write_ioapic_reg(uint8_t, uint32_t); + +void +setup_apic(struct ioapic_info *ioapic) +{ +	uint64_t v = get_msr(APIC_BASE); +	uint64_t addr = v & 0x0000000FFFFFF000; + +	apic_base = (uint32_t *)map_page(addr, 1, false); +	write_apic_reg(SPURIOUS_INTERRUPT_VECTOR, read_apic_reg(SPURIOUS_INTERRUPT_VECTOR) | 0x1FF); + +	uint8_t *ioapic_base = (uint8_t*)map_page(ioapic->base, 1, false); +	ioapic_reg = ioapic_base; +	ioapic_data = (uint32_t*)(ioapic_base+16); + +	ioapic_max_entries = (read_ioapic_reg(1) >> 16)&0xFF; +} + +void +apic_end_of_interrupt(void) +{ +	write_apic_reg(END_OF_INTERRUPT, 0); +} + +struct ioapic_redirection +read_redirection(uint8_t n) +{ +	assert(n <= ioapic_max_entries); +	struct ioapic_redirection r; + +	uint32_t low = read_ioapic_reg(0x10+2*n); +	uint32_t high = read_ioapic_reg(0x11+2*n); + +	r.vector = low & 0xFF; +	r.delivery_mode = (low >> 8) & 0x7; +	r.destination_mode = (low >> 11) & 0x1; +	r.delivery_status = (low >> 12) & 0x1; +	r.pin_polarity = (low >> 13) & 0x1; +	r.remote_irr = (low >> 14) & 0x1; +	r.trigger_mode = (low >> 15) & 0x1; +	r.mask = (low >> 16) & 0x1; +	r.reserved = (low >> 17) & 0xFF; +	r.reserved |= high & 0xFFFFFF; +	if(r.destination_mode) +		r.destination = (high >> 24) & 0xF; +	else +		r.destination = (high >> 24) & 0xFF; +	return r; +} + +void +write_redirection(uint8_t n, struct ioapic_redirection r) +{ +	uint32_t high, low; +	high = low = 0; +	assert(n <= ioapic_max_entries); +	assert(r.vector >= 0x10 && r.vector <= 0xFE); + +	low |= r.vector & 0xFF; +	low |= (r.delivery_mode & 0x7) << 8; +	low |= (r.destination_mode & 0x1) << 11; +	low |= (r.delivery_status & 0x1) << 12; +	low |= (r.pin_polarity & 0x1) << 13; +	low |= (r.remote_irr & 0x1) << 14; +	low |= (r.trigger_mode & 0x1) << 15; +	low |= (r.mask & 0x1) << 16; +	low |= (r.reserved & 0xF) << 17; +	high |= (r.reserved & 0xFFFFFF00) >> 8; +	if(r.destination_mode) +		high |= (r.destination & 0xF) << 24; +	else +		high |= (r.destination & 0xFF) << 24; + +	write_ioapic_reg(0x10+2*n, low); +	write_ioapic_reg(0x11+2*n, high); +} + +static uint32_t +read_apic_reg(uint64_t r) +{ +	r /= 4; +	return apic_base[r]; +} + +static void +write_apic_reg(uint64_t r, uint32_t v) +{ +	r /= 4; +	apic_base[r] = v; +} + +static uint32_t +read_ioapic_reg(uint8_t r) +{ +	*ioapic_reg = r; +	return *ioapic_data; +} + +static void +write_ioapic_reg(uint8_t r, uint32_t v) +{ +	*ioapic_reg = r; +	*ioapic_data = v; +} diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..4c9803c --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,25 @@ +#include "aplos.h" + +void +setup_keyboard(void) +{ +	uint8_t n = 1; /* TODO: it isn't always at 1, the ACPI tables should tell us if not */ + +	struct ioapic_redirection r = read_redirection(n); + +	r.vector = 32; +	r.delivery_mode = 0; +	r.destination_mode = 0; +	r.mask = 0; +	r.destination = boot_apic_id(); + +	write_redirection(n, r); +} + +bool +keyboard_interrupt_handler(uint32_t) +{ +	uint8_t scancode = in_uint8(0x60); +	print(u8"KBD INTR: %x8\n", scancode); +	return true; +}  |