diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/acpi.c | 84 | ||||
| -rw-r--r-- | src/gdt.c | 44 | ||||
| -rw-r--r-- | src/idt.c | 110 | ||||
| -rw-r--r-- | src/mem.c | 26 | ||||
| -rw-r--r-- | src/memory.c | 185 | ||||
| -rw-r--r-- | src/nrvn.c | 57 | ||||
| -rw-r--r-- | src/pic.c | 107 | ||||
| -rw-r--r-- | src/ps2.c | 216 | ||||
| -rw-r--r-- | src/vga.c | 112 | 
9 files changed, 941 insertions, 0 deletions
diff --git a/src/acpi.c b/src/acpi.c new file mode 100644 index 0000000..b4bb05e --- /dev/null +++ b/src/acpi.c @@ -0,0 +1,84 @@ +#include <acpi.h> +#include <vga.h> +#include <mem.h> +#include <stdbool.h> + +static bool checksum_rsdp(const struct rsdp *rsdp) { +	size_t chksm = 0; +	for (uint8_t *byte = (uint8_t*) rsdp; byte < (uint8_t*)rsdp + sizeof(*rsdp); byte++) +		chksm += *byte; +	return (chksm & 0xFF) == 0; +} + +static bool checksum_xsdp(const struct xsdp *rsdp) { +	return true; +	size_t chksm = 0; +	for (uint8_t *byte = (uint8_t*) rsdp; byte < (uint8_t*)rsdp + sizeof(*rsdp); byte++) +		chksm += *byte; +	return (chksm & 0xFF) == 0; +} + +static bool checksum_sdt(const struct acpi_sdt_header *header) { +	uint8_t chksm = 0; +	for (size_t i = 0; i < header->len; i++) { +		chksm += ((int8_t *) header)[i]; +	} +	return chksm == 0; +} + +void print_rsdp(const struct rsdp *rsdp) { +	vga_puts("sig: "); +	vga_putsn(rsdp->signature, 8); +	vga_putc('\n'); + +	vga_puts("checksum: "); +	vga_putn(rsdp->checksum); +	vga_putc(' '); +	vga_puts(checksum_rsdp(rsdp) ? "PASS" : "FAIL"); +	vga_putc('\n'); + +	vga_puts("oem id: "); +	vga_putsn(rsdp->oemid, 6); +	vga_putc('\n'); + +	vga_puts("revision: "); +	vga_putn(rsdp->revision); +	vga_putc('\n'); + +	vga_puts("addr: "); +	vga_putx(rsdp->rsdt_address); +	vga_putc('\n'); +} + +struct fadt *find_facp(struct xsdt *root_sdt) { +	if (root_sdt == NULL) +		return NULL; +	size_t entries = (root_sdt->header.len - sizeof(root_sdt->header)) / 4; +	for (size_t i = 0; i < entries; i++) { +		struct acpi_sdt_header *header = (struct acpi_sdt_header *) root_sdt->sdt_pointers[i]; +		if (memcmp(header->signature, "FACP", 4) == 0 && checksum_sdt(header)) { +			return (struct fadt *) header; +		} +	} +	return NULL; +} + +struct xsdp *find_rsdp() { +	struct xsdp *rsdp = NULL; + +	char *ebda = (char*)((uintptr_t) *(uint16_t *)0x40e << 4); +	for (char *ptr = ebda; ptr < ebda + 128; ptr += 16) { +		if (memcmp(ptr, "RSD PTR ", 8) == 0 && checksum_xsdp((struct xsdp*) ptr)) { +			rsdp = (struct xsdp *) ptr; +		} +	} + +	for (char *ptr = (char*)0x000E0000; ptr < (char*)0x000FFFFF; ptr += 16) { +		if (memcmp(ptr, "RSD PTR ", 8) == 0 && checksum_xsdp((struct xsdp*) ptr)) { +			if (rsdp == NULL) +				rsdp = (struct xsdp *) ptr; +		} +	} +	//print_rsdp(rsdp); +	return rsdp; +} diff --git a/src/gdt.c b/src/gdt.c new file mode 100644 index 0000000..22489ac --- /dev/null +++ b/src/gdt.c @@ -0,0 +1,44 @@ +#include <gdt.h> + +struct gdt_entry { +	uint16_t limit_low; +	uint16_t base_low; +	uint8_t base_middle_low; +	uint8_t access; +	uint8_t gran; +	uint8_t base_middle_high; +	uint32_t base_high; +	uint32_t reseved; +} __attribute__((packed)); + +struct gdt { +	uint16_t limit; +	uint64_t base; +} __attribute__((packed)); + +struct gdt_entry gdt[3]; +struct gdt gdt_ptr; + +extern void gdt_flush(); + +void gdt_set_gate(size_t num, uint64_t base, uint32_t limit, uint8_t access, uint8_t gran) { +	gdt[num] = (struct gdt_entry) { +		.base_low = base & 0xFFFF, +		.base_middle_low = (base >> 16) & 0xFF, +		.base_middle_high = (base >> 24) & 0xFF, +		.base_high = (base >> 32) & 0xFFFFFFFF, +		.limit_low = limit & 0xFFFF, +		.gran = ((limit >> 16) & 0x0F) | (gran & 0xF0), +		.access = access +	}; +} + +void gdt_install() { +	gdt_ptr.limit = (sizeof(struct gdt_entry) * 3) - 1; +	gdt_ptr.base = (uint64_t) &gdt; + +	gdt_set_gate(0, 0, 0, 0, 0); +	gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); +	gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); +	gdt_flush(); +} diff --git a/src/idt.c b/src/idt.c new file mode 100644 index 0000000..a78847d --- /dev/null +++ b/src/idt.c @@ -0,0 +1,110 @@ +#include <stdbool.h> +#include <idt.h> +#include <vga.h> +#include <mem.h> + +extern void idt_load(); + +struct idt_entry { +	uint16_t offset_low; +	uint16_t sel; +	uint8_t ist; +	uint8_t flags; +	uint16_t offset_middle; +	uint32_t offset_high; +	uint32_t reserved; +} __attribute__((packed)); + +struct idt { +	uint16_t limit; +	uint64_t base; +} __attribute__((packed)); + +struct idt_entry idt[256]; +struct idt idt_ptr; +static void (*handlers[256])(uint64_t, uint64_t) = { 0 }; +static const char *exception_msg[] = { +	"Division By Zero Exception", +	"Debug Exception", +	"Non Maskable Interrupt Exception", +	"Breakpoint Exception", +	"Into Detected Overflow Exception", +	"Out of Bounds Exception", +	"Invalid Opcode Exception", +	"No Coprocessor Exception", +	"Double Fault Exception", +	"Coprocessor Segment Overrun Exception", +	"Bad TSS Exception", +	"Segment Not Present Exception", +	"Stack Fault Exception", +	"General Protection Fault Exception", +	"Page Fault Exception", +	"Unknown Interrupt Exception", +	"Coprocessor Fault Exception", +	"Alignment Check Exception (486+)", +	"Machine Check Exception (Pentium/586+)", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +	"Reserved Exceptions", +}; + + +void exception_handler(uint64_t num, uint64_t error) { +	vga_puts("\n\neto bleh: "); +	vga_puts(exception_msg[num]); +	vga_puts("\nerror info: "); +	vga_putx(error); +	while (1); +} + +void interrupt_handler(uint64_t num, uint64_t data) { +	handlers[num](num, data); +} + +void idt_set_isr(uint8_t num, uint64_t offset, uint16_t sel, uint8_t flags) { +	idt[num] = (struct idt_entry) { +		.offset_low = offset & 0xFFFF, +		.offset_middle = (offset >> 16) & 0xFFFF, +		.offset_high = (offset >> 32) & 0xFFFFFFFF, +		.sel = sel, +		.ist = 0, +		.flags = flags, +		.reserved = 0, +	}; +} + +void idt_init() { +	idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1; +	idt_ptr.base = (uint64_t) &idt; +	memset(idt, 0, (sizeof(struct idt_entry) * 256)); +	idt_load(); + +	for (size_t i = 0; i < 32; i++) { +		idt_set_isr(i, isr_table[i], 0x08, 0x8E); +		handlers[i] = exception_handler; +	} +} + +bool idt_register_isr(size_t num, void (*func)(uint64_t, uint64_t)) { +	if (handlers[num]) +		return false; +	handlers[num] = func; +	return true; +} + +bool idt_remove_isr(size_t num, void (*func)(uint64_t, uint64_t)) { +	if (handlers[num] != func) +		return false; +	handlers[num] = NULL; +	return true; +} diff --git a/src/mem.c b/src/mem.c new file mode 100644 index 0000000..dd302fb --- /dev/null +++ b/src/mem.c @@ -0,0 +1,26 @@ +#include <mem.h> +#include <stdint.h> + +void *memcpy(void *restrict dest, const void *restrict src, size_t n) { +	for (size_t i = 0; i < n; i++) +		((char *) dest)[i] = ((char *) src)[i]; +	return dest; +} + +void *memmove(void *dest, const void *src, size_t n) { +	for (size_t i = 0; i < n; i++) +		((char *) dest)[i] = ((char *) src)[i]; +	return dest; +} + +void *memset(void *s, int c, size_t n) { +	for (size_t i = 0; i < n; i++) +		((char *) s)[i] = c; +	return s; +} + +int memcmp(const void *s1, const void *s2, size_t n) { +	while (n && *(uint8_t*)s1 == *(uint8_t*)s2) +		n--, s1++, s2++; +	return n ? *(uint8_t*)s1 - *(uint8_t*)s2 : 0; +} diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..eac0718 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,185 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#include <vga.h> +#include <multiboot.h> +#include <memory.h> +#include <mem.h> + +extern uint64_t multiboot_magic; +extern struct multiboot_info *multiboot_header; +extern void *kernel_end; + +extern uint64_t pml4[512]; + +struct memory { +	struct memory *prev, *next; +	bool free; +	size_t size; +	uint8_t block[]; +} *blocklist; + +void print_blocks() { +	struct memory *block = NULL; +	for (block = blocklist; block; block = block->next) { +		vga_puts("block at: "); +		vga_putx((size_t)block); +		vga_puts(", size: "); +		vga_putx(block->size); +		if (block->free) +			vga_puts(", free"); +		vga_putc('\n'); +	} +} + +void *kmalloc_a(size_t size, size_t alignment) { +	struct memory *block = NULL; +	for (block = blocklist; block; block = block->next) { +		if (!block->free || block->size < size + sizeof(struct memory)) +			continue; +		size_t offset = (uintptr_t)block->block % alignment; +		if (offset) { +			if (block->size < (2 * sizeof(struct memory)) + size + (alignment - offset)) { +				continue; +			} + +			struct memory *new_block = (void *)block + (alignment - offset); +			*new_block = (struct memory) { +				.size = block->size - (alignment - offset), +				.free = true, +				.prev = block, +				.next = block->next, +			}; +			block->next = new_block; +			block->size = alignment - offset; + +			block = new_block; +			break; +		} +	} +	if (!block) { +		print_blocks(); +		vga_puts("\n\noom"); +		while(1); +	} +	 +	struct memory *nextblock = (void *)block->block + size; +	*nextblock = (struct memory) { +		.size = block->size - size, +		.free = true, +		.prev = block, +		.next = block->next +	}; +	block->next = nextblock; +	block->size = size; +	block->free = false; +	return block->block; +} + +void *kmalloc(size_t size) { +	struct memory *block = NULL; +	for (block = blocklist; block && (!block->free || block->size < size + sizeof(struct memory)); block = block->next); +	if (!block) { +		print_blocks(); +		vga_puts("\n\noom"); +		while(1); +	} +	 +	struct memory *nextblock = (void *)block->block + size; +	*nextblock = (struct memory) { +		.size = block->size - size, +		.free = true, +		.prev = block, +		.next = block->next +	}; +	block->next = nextblock; +	block->size = size; +	block->free = false; + +	return block->block; +} + +void kfree(void *ptr) { +	struct memory *header = ptr - sizeof(struct memory); +	if (header->next && header->next == (void*)header->block + header->size && header->next->free) { +		header->size += header->next->size + sizeof(struct memory); +		header->next = header->next->next; +		if (header->next) +			header->next->prev = header; +	} +	if (header->prev && header == (void*)header->prev->block + header->prev->size && header->prev->free) { +		header->prev->size += header->size + sizeof(struct memory); +		header->prev->next = header->next; +		if (header->next) +			header->next->prev = header->prev; +		header = header->prev; +	} + +	header->free = true; +} + +uint64_t alloc_page() { +	uint64_t *page = kmalloc_a(sizeof(uint64_t) * 512, 0x1000); +	memset(page, 0, sizeof(uint64_t) * 512); +	return (uint64_t)page | 0x3; +} + +uint64_t *addr_to_page(uint64_t addr) { +	size_t index = (addr >> 39) & 0x1ff; +	if (!(pml4[index] & 0x1)) +		pml4[index] = alloc_page(); + +	uint64_t *pdpr = (uint64_t*)(pml4[index] & ~0xfff); +	index = (addr >> 30) & 0x1ff; +	if (!(pdpr[index] & 0x1)) +		pdpr[index] = alloc_page(); + +	uint64_t *pd = (uint64_t*)(pdpr[index] & ~0xfff); +	index = (addr >> 21) & 0x1ff; +	if (!(pd[index] & 0x1)) +		pd[index] = alloc_page(); + +	uint64_t *pt = (uint64_t*)(pd[index] & ~0xfff); +	index = (addr >> 12) & 0x1ff; +	return &pt[index]; +}; + +bool paging_init() { +	blocklist = (void *)0x7e00; +	*blocklist = (struct memory) { +		.size = 0x7ffff - 0x7e00, +		.free = true +	}; + +	if (multiboot_magic != 0x2badb002) +		return false; + +	for (size_t i = 0; i < multiboot_header->mmap_length / sizeof(struct multiboot_mmap_entry); i++) { +		struct multiboot_mmap_entry *mmap = &((struct multiboot_mmap_entry *) (uintptr_t) multiboot_header->mmap_addr)[i]; + +		if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE && mmap->addr > 0x1000) { +			struct memory *header = mmap->addr > (uint64_t)&kernel_end ? (void*) mmap->addr : (void *)&kernel_end; + +			// map the first header, in case we need to use this region for paging itself +			uint64_t *page = addr_to_page((uintptr_t) header); +			*page = ((uintptr_t)header & ~0xfff) | 0x3; + +			*header = (struct memory) { +				.size = mmap->len, +				.free = true +			}; +			struct memory *last; +			for (last = blocklist; last->next; last = last->next); +			last->next = header; +			header->prev = last; +		} + +		size_t end = mmap->addr + mmap->len; +		for (size_t addr = mmap->addr & ~0xfff; addr < end; addr += 0x1000) { +			uint64_t *page = addr_to_page(addr); +			*page = addr | 0x3; +		} +	} +	return true; +} diff --git a/src/nrvn.c b/src/nrvn.c new file mode 100644 index 0000000..84b297f --- /dev/null +++ b/src/nrvn.c @@ -0,0 +1,57 @@ +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <nrvn.h> +#include <vga.h> +#include <idt.h> +#include <pic.h> +#include <acpi.h> +#include <ps2.h> +#include <multiboot.h> +#include <mem.h> +#include <memory.h> + +/* Check if the compiler thinks you are targeting the wrong operating system. */ +#if defined(__linux__) +#error "You are not using a cross-compiler, you will most certainly run into trouble" +#endif + +/* This tutorial will only work for the 32-bit ix86 targets. */ +//#if !defined(__i386__) | !defined(__x86_64__) +//#error "This tutorial needs to be compiled with a ix86-elf compiler" +//#endif + +void kernel_main(void) { +	vga_init(); +	vga_puts("hello world\n"); +	vga_puts("welcome to nirvanna\n\n"); + +	vga_puts("initializing interrupt tables..."); +	idt_init(); +	vga_puts("interrupt tables initialized\n"); + + +	vga_puts("initializing the pic..."); +	pic_init(); +	vga_puts("pic initialized\n"); + +	vga_puts("initializing memory pages... "); +	if (paging_init()) { +		vga_puts("memory pages allocated\n"); +	} else { +		vga_puts("failed to allocate memory pages\n"); +		asm volatile ("cli"); +		asm volatile ("hlt"); +	} + +	// TODO -- fix acpi + +	vga_puts("initializing ps/2...\n"); +	if (ps2_init(NULL)) +		vga_puts("ps/2 initialized.\n"); +	else +		vga_puts("ps/2 initialization failed.\n"); + +	while (1); +} diff --git a/src/pic.c b/src/pic.c new file mode 100644 index 0000000..ad2c15d --- /dev/null +++ b/src/pic.c @@ -0,0 +1,107 @@ +#include <nrvn.h> +#include <pic.h> +#include <idt.h> +#include <vga.h> + +extern void toggle_interrupts(bool enable); + +#define pic1 0x20 +#define pic2 0xA0 +#define pic1_d (pic1 + 1) +#define pic2_d (pic2 + 2) + +void pic_remap(uint32_t offset1, uint32_t offset2) { +	uint8_t a1, a2; + +	a1 = inb(pic1_d); +	a2 = inb(pic2_d); + +	outb(pic1, 0x10 | 0x01); +	io_wait(); +	outb(pic2, 0x10 | 0x01); +	io_wait(); +	outb(pic1_d, offset1); +	io_wait(); +	outb(pic2_d, offset2); +	io_wait(); +	outb(pic1_d, 4); +	io_wait(); +	outb(pic2_d, 2); +	io_wait(); + +	outb(pic1_d, 0x01); +	io_wait(); +	outb(pic2_d, 0x01); +	io_wait(); + +	outb(pic1_d, a1); +	outb(pic2_d, a2); +} + +void pic_set_mask(uint8_t irq_line) { +	uint32_t port; +	uint8_t value; + +	if (irq_line < 8) +		port = pic1_d; +	else { +		port = pic2_d; +		irq_line -= 8; +	} +	value = inb(port) | (1 << irq_line); +	outb(port, value); +} + +void pic_clear_mask(uint8_t irq_line) { +	uint32_t port; +	uint8_t value; + +	if (irq_line < 8) +		port = pic1_d; +	else { +		port = pic2_d; +		irq_line -= 8; +	} +	value = inb(port) & ~(1 << irq_line); +	outb(port, value); +} + +void pic_set_all_masks(void) { +	outb(pic1_d, 0xFF); +	outb(pic2_d, 0xFF); +} + +void pic_clear_all_masks(void) { +	outb(pic1_d, 0x00); +	outb(pic2_d, 0x00); +} + +void pic_eoi(uint8_t irq) { +	if (irq >= 8) +		outb(pic2, 0x20); +	outb(pic1, 0x20); +} + +void keyboard_handler(uint64_t num, uint64_t _unused) { +	(void)num; +	(void)_unused; +	uint8_t key = inb(0x60); +	vga_puts("key pressed: "); +	vga_putx(key); +	vga_putc('\n'); +	pic_eoi(0x1); +} + +void pic_init(void) { +	pic_set_all_masks(); +	pic_clear_mask(1); +	//pic_clear_mask(12); +	pic_remap(32, 40); + +	for (size_t i = 32; i < 48; i++) +		idt_set_isr(i, isr_table[i], 0x08, 0x8E); + +	idt_register_isr(33, keyboard_handler); + +	toggle_interrupts(true); +} diff --git a/src/ps2.c b/src/ps2.c new file mode 100644 index 0000000..6491aed --- /dev/null +++ b/src/ps2.c @@ -0,0 +1,216 @@ +#include <stdbool.h> +#include <nrvn.h> +#include <acpi.h> +#include <vga.h> + +#define data_port 0x60 +#define status_reg 0x64 +#define cmd_reg 0x64 + +#define config_rcmd 0x20 +#define config_wcmd 0x60 +#define ctrl_test_cmd 0xaa + +static inline void print_port_status(bool second_port, const char *msg) { +	vga_puts("ps/2 port "); +	vga_puts(second_port ? "2 " : "1 "); +	vga_puts(msg); +} + +static inline void send_cmd(uint8_t cmd) { +	while (inb(status_reg) & 0x2); +	outb(cmd_reg, cmd); +} + +static inline bool read_data(uint8_t *data_out) { +	size_t counter = 50; +	while (!(inb(status_reg) & 0x1) && --counter > 0); +	if (counter == 0) +		return false; +	*data_out = inb(data_port); +	return true; +} + +static inline void send_data(uint8_t data, bool second_device) { +	if (second_device) +		send_cmd(0xd4); +	while (inb(status_reg) & 0x2); +	outb(data_port, data); +} + +// TODO: ps/2 mouse interface is weird. +static bool interface_test(bool second_device) { +	uint8_t rply; + +	// Test port +	send_cmd(second_device ? 0xa9 : 0xab); +	read_data(&rply); +	switch (rply) { +		case 0x00: +			print_port_status(second_device, "port test PASS\n"); +			break; +		case 0x01: +			print_port_status(second_device, "FAIL clock line stuck low\n"); +			return false; +		case 0x02: +			print_port_status(second_device, "FAIL clock line stuck high\n"); +			return false; +		case 0x03: +			print_port_status(second_device, "FAIL data line stuck low\n"); +			return false; +		case 0x04: +			print_port_status(second_device, "FAIL data line stuck data\n"); +			return false; +	} + +	// Re-enable interface +	send_cmd(second_device ? 0xa8 : 0xae); + +	// reset and self test device +	send_data(0xff, second_device); +	if (!read_data(&rply)) { +		print_port_status(second_device, "self-test FAIL: no reply\n"); +		return false; +	} + +	switch (rply) { +		case 0xFA: +			if (read_data(&rply), rply == 0xaa) { +				print_port_status(second_device, "self-test PASS\n"); +			} else { +				print_port_status(second_device, "self-test FAIL"); +				vga_putx(rply); +				vga_putc('\n'); +				return false; +			} +			(void) inb(data_port); // PS/2 mouses send their id, we need to flush +			break; +		case 0xFC: +			print_port_status(second_device, "self-test FAIL: "); +			vga_putx(rply); +			vga_putc('\n'); +			return false; +		default: +			print_port_status(second_device, "self-test unknown reply: "); +			vga_putx(rply); +			vga_putc('\n'); +			return false; +	} + +	// Disable device +	print_port_status(second_device, "disabling scanning.\n"); +	send_data(0xf5, second_device); +	if (!read_data(&rply)) { +		print_port_status( second_device, "failed to disable: "); +		return false; +	} + +	if (rply != 0xfa && rply != 0xaa) { +		print_port_status( second_device, "failed to disable: "); +		vga_putx(rply); +		vga_putc('\n'); +		return false; +	} + +	print_port_status(second_device, "scanning disabled.\n"); + +	print_port_status(second_device, "detecting device type.\n"); +	send_data(0xf2, second_device); +	if (read_data(&rply), rply != 0xfa) { +		print_port_status(second_device, "failed to identify: "); +		vga_putx(rply); +		vga_putc('\n'); +		return false; +	} +	print_port_status(second_device, "id ack: "); +	vga_putx((read_data(&rply), rply)); +	vga_putc(' '); +	if (read_data(&rply)) +		vga_putx(rply); +	vga_putc('\n'); + +	// Enable device +	send_data(0xf4, second_device); +	if (read_data(&rply), rply != 0xfa) { +		print_port_status(second_device, "failed to enable: "); +		vga_putx(rply); +		vga_putc('\n'); +		return false; +	} + +	print_port_status(second_device, "scanning enabled.\n"); + +	return true; +} + +bool ps2_init(struct fadt *fadt) { +	if (fadt != NULL && !(fadt->boot_arch_flags & 0x2)) { +		vga_puts("fadt boot arch bit 1 not set: "); +		vga_putx(fadt->boot_arch_flags); +		vga_putc(' '); +		vga_putx(((char*)fadt)[109]); +		vga_putc('\n'); +	} + +	uint8_t rply; + +	// Disable ps/2 devices +	vga_puts("disabling first device\n"); +	send_cmd(0xad); +	vga_puts("disabling second device\n"); +	send_cmd(0xa7); + +	// flush output buffer +	(void) inb(data_port); + +	// set controller config, clearing bits 0, 1, and 6 +	send_cmd(config_rcmd); +	uint8_t config = (read_data(&rply), rply) & ~0b01000011; + +	// check if dual channel is already set +	bool dual_channel = !(config & 0x5); + +	send_cmd(config_wcmd); +	send_data(config, false); + +	// perform controller self test +	send_cmd(ctrl_test_cmd); +	if (read_data(&rply), rply != 0x55) { +		vga_puts("ps/2 controller self test failed: "); +		vga_putx(rply); +		vga_putc('\n'); +		return false; +	} + +	// re-set config in case the self tests reset the device +	send_cmd(config_wcmd); +	send_data(config, false); + +	// determine if there are two ports +	if (!dual_channel) { +		// attempt to enable second channel +		send_cmd(0xa8); + +		// check if configuration show second port +		// and disable it again if it shows. +		send_cmd(0x20); +		if ((dual_channel = !((read_data(&rply), rply) & 0x5))) +			send_cmd(0xa7); +	} + +	// enable and reset devices +	if (!interface_test(false)) +		vga_puts("failed to test port 1 interface\n"); + +	if (dual_channel && !interface_test(true)) +		vga_puts("failed to test port 2 interface\n"); + +	// re enabled bits 1 and 2 (interrupts) +	send_cmd(0x20); +	config = (read_data(&rply), rply) | 0x3; + +	send_cmd(0x60); +	send_data(config, false); + +	return true; +} diff --git a/src/vga.c b/src/vga.c new file mode 100644 index 0000000..150af9b --- /dev/null +++ b/src/vga.c @@ -0,0 +1,112 @@ +#include <nrvn.h> +#include <vga.h> + +static size_t vga_x, vga_y; +static uint8_t vga_color; +static uint16_t *vga_buffer; + +void vga_init(void) { +	vga_x = vga_y = 0; +	vga_set_color(VGA_LIGHT_MAGENTA, VGA_BLACK); +	vga_buffer = (uint16_t *)0xB8000; +	for (size_t y = 0; y < VGA_HEIGHT; y++) +		for (size_t x = 0; x < VGA_WIDTH; x++) +			vga_buffer[y * VGA_WIDTH + x] = ' ' | (vga_color << 8); +} + +void vga_scroll() { +	if (vga_y < VGA_HEIGHT) +		return; + +	for (size_t y = 0; y < VGA_HEIGHT - 1; y++) { +		for (size_t x = 0; x < VGA_WIDTH; x++) { +			const size_t from = (y + 1) * VGA_WIDTH + x; +			const size_t to = y * VGA_WIDTH + x; +			vga_buffer[to] = vga_buffer[from]; +		} +	} +	vga_y = VGA_HEIGHT - 1; +	for (size_t x = 0; x < VGA_HEIGHT; x++) { +		vga_buffer[vga_y * VGA_WIDTH + x] = ' ' | (vga_color << 8); +	} +} + +void vga_update_cursor(void) { +	size_t index = vga_y * VGA_WIDTH + vga_x; + +	outb(0x3D4, 14); +	outb(0x3D5, index >> 8); +	outb(0x3D4, 15); +	outb(0x3D5, index); +} + +void vga_putn(const size_t number) { +	char digits[32] = { 0 }; +	size_t num = number, count = 0; +	do { +		digits[count] = (num % 10) + '0'; +		count++; +	} while ((num /= 10) > 0); + +	do { +		vga_putc(digits[count]); +	} while (count-- > 0); +} + +void vga_putx(const size_t hex) { +	char digits[32] = { 0 }; +	size_t num = hex, count = 0; +	do { +		digits[count] = "0123456789abcdef"[num % 16]; +		count++; +	} while ((num /= 16) > 0); + +	vga_puts("0x"); +	do { +		vga_putc(digits[count]); +	} while (count-- > 0); +} + +void vga_putc(const char c) { +	switch (c) { +		case '\n': +			vga_x = 0; +			vga_y++; +			break; +		case '\b': +			if (vga_x > 0) +				vga_x--; +			break; +		case '\r': +			vga_x = 0; +			break; +		case '\t': +			break; +		default: +			// Any character greater than and including a space, is a printable character +			if (c >= ' ') +				vga_buffer[vga_y * VGA_WIDTH + vga_x++] = (uint16_t) c | ((uint16_t) vga_color << 8); +	} + +	if (vga_x >= VGA_WIDTH) { +		vga_x = 0; +		vga_y++; +	} + +	vga_scroll(); +	vga_update_cursor(); +} + +void vga_puts(const char *s) { +	while (*s) +		vga_putc(*s++); +} + +void vga_putsn(const char *s, const size_t len) { +	for (size_t i = 0; i < len; i++) +		vga_putc(s[i]); +} + +void vga_set_color(const uint8_t fg, const uint8_t bg) { +	vga_color = fg | bg << 4; +}  | 
