summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authorBrett Weiland <brett_weiland@bpcspace.com>2021-08-24 14:09:29 -0500
committerBrett Weiland <brett_weiland@bpcspace.com>2021-08-24 14:09:29 -0500
commit9b22a6965579ea1867aea291d910c96f386b518b (patch)
treed06dbb9c4708f1cc713bcb115b32ff9bce4cf9b9 /src/kernel
parentbad4b0e9bdfee336bfc1c23761408279eaec1558 (diff)
major backup 8.24.21
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/acpi.c179
-rw-r--r--src/kernel/drivers/serial.c39
-rw-r--r--src/kernel/heap.c211
-rw-r--r--src/kernel/int.c253
-rw-r--r--src/kernel/io.c24
-rw-r--r--src/kernel/isv.c12
-rw-r--r--src/kernel/isv_asm.asm65
-rw-r--r--src/kernel/kernel.c46
-rw-r--r--src/kernel/klog.c100
-rw-r--r--src/kernel/libc.c19
-rw-r--r--src/kernel/madt.c179
-rw-r--r--src/kernel/page.c573
-rw-r--r--src/kernel/panic.c80
-rw-r--r--src/kernel/printf.c6
-rw-r--r--src/kernel/random.c36
-rw-r--r--src/kernel/smp.c80
-rw-r--r--src/kernel/smp_trampoline.asm140
-rw-r--r--src/kernel/testmalloc.c35
-rw-r--r--src/kernel/timer.c296
-rw-r--r--src/kernel/video.c (renamed from src/kernel/drivers/video.c)3
20 files changed, 2051 insertions, 325 deletions
diff --git a/src/kernel/acpi.c b/src/kernel/acpi.c
index 0c22fe4..e5a6e4d 100644
--- a/src/kernel/acpi.c
+++ b/src/kernel/acpi.c
@@ -1,58 +1,169 @@
#include <acpi.h>
#include <stdint.h>
#include <printf.h>
+#include <kernel.h>
+#include <stdbool.h>
+#include <kernel.h>
+#include <io.h>
+#include <int.h>
+#include <libc.h>
+#include <panic.h>
-static int RSDP_verify(void *rsdp_pointer) {
- printf("Verifying potential RSDP at address 0x%p... ", rsdp_pointer);
- union rsdp_t *rsdp = rsdp_pointer;
+
+//finding rsdp
+typedef struct rsdp {
+ char sig[8];
+ uint8_t checksum;
+ char OEMID[6];
+ uint8_t revision;
+ uint32_t rsdt;
+
+ //these only exist on REV > 1
+ uint32_t len;
+ uint64_t xsdt;
+ uint8_t extended_checksum;
+ uint8_t reserved[3];
+
+} __attribute__((packed)) root_sdp;
+
+
+//root descriptor SDTs
+struct rsdt {
+ sdt_head header;
+ uint32_t sdt_pointers[];
+} __attribute__((packed));
+
+struct xsdt {
+ sdt_head header;
+ uint64_t sdt_pointers[];
+} __attribute__((packed));
+
+root_sdp *rsdp;
+
+
+
+void debug_acpi() {
+ sdt_head *sdt;
+ int sdt_i, sdt_cnt;
+
+ if(rsdp->revision) {
+ struct xsdt *root = PHYS_TO_VIRT(rsdp->xsdt);
+ sdt_cnt = (root->header.length - sizeof(root->header)) / 8;
+ printf("sdts found in apic headers: %i\n", sdt_cnt);
+ for(sdt_i = 0; sdt_i < sdt_cnt; sdt_i++) {
+ sdt = PHYS_TO_VIRT(root->sdt_pointers[sdt_i]);
+ printf("ACPI debug:%.4s\n", sdt->sig);
+ }
+ }
+ else {
+ struct rsdt *root = PHYS_TO_VIRT((uint64_t)rsdp->rsdt);
+ sdt_cnt = (root->header.length - sizeof(root->header)) / 4;
+ printf("sdts found in apic headers: %i\n", sdt_cnt);
+ for(sdt_i = 0; sdt_i < sdt_cnt; sdt_i++) {
+ sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]);
+ printf("ACPI debug:%.4s\n", sdt->sig);
+ }
+ }
+}
+
+//TODO clean up confusing variable name rsdt
+void *find_sdt(int type) {
+ char sig[4];
+ sdt_head *sdt;
+ int sdt_i, sdt_cnt;
+
+ //If we never need to expand this, then you can clean it up.
+ switch(type) {
+ case SDT_MADT:
+ strcpy(sig, "APIC");
+ break;
+ case SDT_HPET:
+ strcpy(sig, "HPET");
+ break;
+ }
+
+ if(rsdp->revision) {
+ struct xsdt *root = PHYS_TO_VIRT(rsdp->xsdt);
+ sdt_cnt = (root->header.length - sizeof(root->header)) / 8;
+ for(sdt_i = 0; sdt_i < sdt_cnt - 1; sdt_i++) {
+ sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]);
+ if(!(strncmp(sdt->sig, sig, 4))) {
+ return sdt;
+ }
+ }
+ }
+ else {
+ struct rsdt *root = PHYS_TO_VIRT((uint64_t)rsdp->rsdt);
+ sdt_cnt = (root->header.length - sizeof(root->header)) / 4;
+ for(sdt_i = 0; sdt_i < sdt_cnt - 1; sdt_i++) {
+ sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]);
+ if(!(strncmp(sdt->sig, sig, 4))) {
+ return sdt;
+ }
+ }
+ }
+ return 0;
+}
+
+bool verify_sdt(sdt_head *sdt) {
uint8_t checksum = 0;
- char *rsdp_csm_ptr = rsdp_pointer;
+ for(int i = 0; i < sdt->length; i++) checksum += ((uint8_t *)sdt)[i];
+ return checksum == 0;
+}
+
+static root_sdp *verify_sdp(root_sdp *uv_rsdp) {
+ char *rsdp_char_ptr = (char *)uv_rsdp;
int i;
- if(checksum) return 0;
- if(rsdp->v1.version) {
- printf("APCI revision > 2.\n");
- checksum = 0;
- printf("len : %i\n", rsdp->v2.len);
- for(i = 0; i < rsdp->v2.len; i++) {
- checksum += rsdp_csm_ptr[i];
+ uint8_t checksum = 0;
+ if(uv_rsdp->revision) {
+ for(i = 0; i < uv_rsdp->len; i++) {
+ checksum += rsdp_char_ptr[i];
}
}
else {
- printf("APCI revision 1.\n");
for(i = 0; i <= 20; i++) {
- checksum += rsdp_csm_ptr[i];
+ checksum += rsdp_char_ptr[i];
}
}
- if(checksum) {
- return 0;
- printf("Invalid, searching on.\n");
+ if(!checksum) {
+ printf("Found RSDP revision %i at address %x.\n", uv_rsdp->revision, uv_rsdp);
+ return uv_rsdp;
}
- printf("RSDP Verified!\n");
- return 1;
+ printf("Skipped over invalid RSDP at 0x%p.\n", uv_rsdp);
+ return 0;
}
-rsdp_t *find_RSDP() {
+
+void find_root_sdp() {
const char sig[9] = "RSD PTR ";
uintptr_t *p = (void *)0x040e;
uintptr_t *ebda_unshifted = (void *)p;
+ bool rsdt_verified;
- void *ebda = (void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff);
+ void *ebda = PHYS_TO_VIRT((void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff));
- for(void *i = ebda; i <= ebda + 64000; i += 16) {
- if(!(memcmp(sig, i, 8))) {
- if(RSDP_verify(i)) {
- return(i);
- }
- }
+
+
+ for(void *i = ebda; i <= ebda + 64000; i += 16)
+ if(!(memcmp(sig, i, 8)) && ((rsdp = verify_sdp(i)))) break;
+
+
+ for(void *i = PHYS_TO_VIRT(0xe0000); i <= PHYS_TO_VIRT(0xfffff); i += 16)
+ if(!(memcmp(sig, i, 8)) && ((rsdp = verify_sdp(i)))) break;
+
+ if(!(rsdp)) {
+ printf("Couldn't find the RSDP... not sure what to do now.\n");
+ PANIC(KERNEL_PANIC_RSDP_UNFOUND);
+ }
+
+ if(rsdp->revision) {
+ rsdt_verified = verify_sdt(PHYS_TO_VIRT(rsdp->xsdt));
+ }
+ else {
+ rsdt_verified = verify_sdt(PHYS_TO_VIRT((uint64_t)rsdp->rsdt));
}
- for(void *i = (void *)0xe0000; i <= (void *)0xfffff; i += 16) {
- if(!(memcmp(sig, i, 8))) {
- if(RSDP_verify(i)) {
- return(i);
- }
- }
+ if(!(rsdt_verified)) {
+ PANIC(KERNEL_PANIC_INVALID_RSDT);
}
}
-
-
diff --git a/src/kernel/drivers/serial.c b/src/kernel/drivers/serial.c
deleted file mode 100644
index 25f89ad..0000000
--- a/src/kernel/drivers/serial.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdint.h>
-#include <serial.h>
-static inline void outb(uint16_t port, uint8_t value) {
- asm volatile(
- "outb %0, %1" :: "a"(value), "Nd"(port)
- );
-}
-
-static inline uint8_t inb(uint16_t port) {
- uint8_t ret;
- asm volatile(
- "inb %1, %0" : "=a"(ret) : "Nd"(port)
- );
- return(ret);
-}
-
-int init_serial(uint16_t port) {
- outb(port + 1, 0x00);
- outb(port + 3, 0x80);
- outb(port + 0, 0x06);
- outb(port + 1, 0x00);
- outb(port + 3, 0x03);
- outb(port + 2, 0xc7);
- outb(port + 4, 0x0b);
- outb(port + 4, 0x1e);
-
- outb(port + 0, 0xae); // test char
-
- if(inb(port + 0) != 0xae)
- return 1;
-
- outb(port + 4, 0x0f); // dissable interupts
- return 0;
-}
-
-void _putchar_serial(uint16_t port, char msg) {
- while(!(inb(port + 5) & 0x20)); //wait for transmit to be done
- outb(port, msg);
-}
diff --git a/src/kernel/heap.c b/src/kernel/heap.c
new file mode 100644
index 0000000..db6392f
--- /dev/null
+++ b/src/kernel/heap.c
@@ -0,0 +1,211 @@
+#include <paging.h>
+#include <printf.h>
+#include <libc.h>
+#include <io.h>
+
+/** a disclaimer-
+ * I've never made an OS, so I don't know what kind of structures I'll have.
+ * Because of this, I'm not YET using a slab allocator.
+ * This allocator allocates sizes of 2^n, starting at 32, which can waste lots of space.
+ * In other places, you'll see me reallocating when it's not nessesary,
+ * as if my allocator doesn't over-allocate.
+ *
+ * Later in development, I will create a slab allocator, making it so that this isn't an issue.
+**/
+
+
+
+#define MIN_CHUNK_ORDER 5 //equal to 32 bytes for heap_chunk struct. Keeping away from 24 for easy division.
+#define MAX_CHUNK_I 6
+#define CHUNK_LIST_LEN MAX_CHUNK_I + 1
+#define LOG_SUB 63 - MIN_CHUNK_ORDER
+#define PAGE_SIZE 0x1000 //TODO [minor] maybe move this to some header somewhere
+
+#define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + MIN_CHUNK_ORDER)))
+#define CHUNK_INDEX_FROM_SIZE(s) ((63 - MIN_CHUNK_ORDER - __builtin_clzl((s))))
+
+
+typedef struct __attribute__((packed)) heap_chunk {
+ unsigned int free:1;
+ unsigned int size:4; //will use with flags later if needed
+ unsigned int lsize:4;
+ unsigned long reserved:55;
+ struct heap_chunk *fd;
+ struct heap_chunk *bk;
+} chunk;
+
+struct heap_chunk_roots {
+ void *fd;
+};
+
+
+//TODO this wastes some memory
+chunk arena[CHUNK_LIST_LEN];
+
+
+void debug_heap() {
+ chunk *on_chunk, *last_chunk;
+ size_t chunk_expected_size;
+ size_t chunk_actual_size;
+ for(unsigned int l = 0; l < CHUNK_LIST_LEN; l++) {
+ chunk_expected_size = CHUNK_SIZE_FROM_INDEX(l);
+ printf("\n%i sized chunks:\n", chunk_expected_size);
+ for(on_chunk = arena[l].fd; on_chunk != 0; on_chunk = on_chunk->fd) {
+ chunk_actual_size = CHUNK_SIZE_FROM_INDEX(on_chunk->size);
+ printf("\t%p", on_chunk);
+ if(chunk_expected_size != chunk_actual_size) {
+ printf("\nFound chunk of size %i in %i sized freebin!!!!\n", chunk_actual_size, chunk_expected_size);
+ hlt();
+ }
+ if(!on_chunk->free) {
+ printf("\nChunk found in freebin isn't free!\n");
+ hlt();
+ }
+ //may take a while
+ if((uintptr_t)on_chunk & (0x1000 - 1)) {
+ last_chunk = (void *)on_chunk - CHUNK_SIZE_FROM_INDEX(on_chunk->lsize);
+ if(last_chunk->size != on_chunk->lsize) {
+ printf("\nChunk before this one is a different size then lsize!");
+ hlt();
+ }
+ }
+ }
+ }
+ printf("\n\n");
+}
+
+
+
+void malloc_init() {
+ bzero(&arena, sizeof(arena));
+}
+
+void free(void *addr) {
+ chunk *on_chunk, *buddy_chunk, *next_chunk, *chunk_iter;
+ on_chunk = addr - 24;
+
+
+ for(;;) {
+ if(on_chunk->size == (MAX_CHUNK_I + 1)) {
+ pfree(on_chunk, 0x1000);
+ printf("freeing page %p\n", on_chunk);
+ return;
+ }
+ unsigned int chunk_size = CHUNK_SIZE_FROM_INDEX(on_chunk->size);
+ if((uintptr_t)on_chunk & ((chunk_size * 2) - 1)) {
+
+ buddy_chunk = (void *)on_chunk - CHUNK_SIZE_FROM_INDEX(on_chunk->lsize);
+ if((buddy_chunk->size != on_chunk->size) || !(buddy_chunk->free)) {
+ next_chunk = (void *)on_chunk + chunk_size;
+ break;
+ }
+ chunk_iter = buddy_chunk;
+
+ }
+ else {
+
+ buddy_chunk = (void *)on_chunk + chunk_size;
+ if((buddy_chunk->size != on_chunk->size) || !(buddy_chunk->free)) {
+ next_chunk = buddy_chunk;
+ break;
+ };
+ chunk_iter = on_chunk;
+
+ }
+
+ if(buddy_chunk->fd) (buddy_chunk->fd)->bk = buddy_chunk->bk;
+ (buddy_chunk->bk)->fd = buddy_chunk->fd;
+ on_chunk = chunk_iter;
+ on_chunk->size++;
+
+ }
+
+
+ next_chunk->lsize = on_chunk->size;
+ on_chunk->free = 1;
+
+ on_chunk->bk = (chunk *)&arena[on_chunk->size];
+ on_chunk->fd = arena[on_chunk->size].fd;
+ if(arena[on_chunk->size].fd) (arena[on_chunk->size].fd)->bk = on_chunk;
+ arena[on_chunk->size].fd = on_chunk;
+
+
+
+}
+
+
+static void split_chunk(chunk *full_chunk, unsigned int full_size, unsigned int req_size) {
+ chunk *on_chunk;
+
+ full_chunk->size = req_size;
+ full_chunk->free = 0;
+
+ //chunk isn't newly allocated page
+ //our free funciton won't check lsize if addr is divisible by 0x1000
+ if(full_chunk->bk) {
+ if(full_chunk->fd) (full_chunk->fd)->bk = (chunk *)&arena[full_size];
+ arena[full_size].fd = full_chunk->fd;
+ on_chunk = (void *)full_chunk + CHUNK_SIZE_FROM_INDEX(full_size);
+ if((uintptr_t)on_chunk & (0x1000 - 1)) on_chunk->lsize = full_size - 1;
+ }
+
+ on_chunk = (void *)full_chunk + CHUNK_SIZE_FROM_INDEX(req_size);
+
+ for(unsigned int sz = req_size; sz < full_size; sz++) {
+ on_chunk->lsize = (sz == req_size) ? req_size : sz - 1;
+ on_chunk->fd = arena[sz].fd;
+ on_chunk->bk = (chunk *)&arena[sz];
+ on_chunk->size = sz;
+ on_chunk->free = 1;
+
+ arena[sz].fd = on_chunk;
+ on_chunk = (void *)on_chunk + CHUNK_SIZE_FROM_INDEX(sz);
+ }
+}
+
+
+void *malloc(size_t size) {
+ size += sizeof(chunk);
+ chunk *on_chunk;
+ unsigned int chunk_sz_i; //desired chunk size index
+ unsigned int chunk_ck_i; //backup chunk size index in case we need to count up
+ //rounding size to nearest 2^n to find which size it fits into
+
+ if(size < 32) size = 32;
+
+ chunk_sz_i = CHUNK_INDEX_FROM_SIZE(size);
+ if(size & (size - 1)) chunk_sz_i++;
+
+ if(chunk_sz_i > MAX_CHUNK_I) return(void *)0;
+
+ //search for direct hits
+ if(arena[chunk_sz_i].fd) {
+ on_chunk = arena[chunk_sz_i].fd;
+ if(on_chunk->fd) (on_chunk->fd)->bk = (chunk *)&arena[chunk_sz_i];
+ arena[chunk_sz_i].fd = on_chunk->fd;
+ on_chunk->free = 0;
+ return (void *)on_chunk + sizeof(chunk);
+ }
+
+ //search for chunks above our size
+ for(chunk_ck_i = chunk_sz_i + 1; chunk_ck_i < CHUNK_LIST_LEN; chunk_ck_i++) {
+ if(arena[chunk_ck_i].fd) {
+ on_chunk = arena[chunk_ck_i].fd;
+ split_chunk(on_chunk, chunk_ck_i, chunk_sz_i);
+ return (void *)on_chunk + sizeof(chunk);
+ }
+ }
+
+ on_chunk = (void *)palloc(0x1000);
+ printf("allocating page %p\n", on_chunk);
+
+ split_chunk(on_chunk, 7, chunk_sz_i);
+ return (void *)on_chunk + sizeof(chunk);
+
+}
+void *realloc(void *old_chunk, size_t size) {
+ void *new_chunk = malloc(size);
+ memcpy(new_chunk, old_chunk, CHUNK_SIZE_FROM_INDEX(((chunk *)(old_chunk-24))->size));
+ free(old_chunk);
+ return new_chunk;
+}
diff --git a/src/kernel/int.c b/src/kernel/int.c
new file mode 100644
index 0000000..34f1c78
--- /dev/null
+++ b/src/kernel/int.c
@@ -0,0 +1,253 @@
+#include <int.h>
+#include <acpi.h>
+#include <io.h>
+#include <paging.h>
+#include <printf.h>
+#include <isv.h>
+#include <kernel.h>
+#include <libc.h>
+#include <madt.h>
+#include <timer.h>
+#include <panic.h>
+
+#define SEGMENT_GDT 0
+#define SEGMENT_LDT 1
+
+
+
+//io commands
+#define ICW1_ICW4 0x01
+#define ICW1_INIT 0x10
+
+#define ICW4_8086 0x01
+
+
+// PIC
+#define PICM_COMMAND 0x20
+#define PICM_DATA 0x21
+
+#define PICS_COMMAND 0xa0
+#define PICS_DATA 0xa1
+
+#define KERNEL_IDT_DESC_GATE(addr) \
+ ((struct idt_descriptor) { \
+ .offset_1 = (uint16_t)((uint64_t)addr & 0xffff), \
+ .offset_2 = (uint16_t)((uint64_t)addr >> 16), \
+ .offset_3 = (uint32_t)((uint64_t)addr >> 32), \
+ .segment = 0x8, \
+ .ist = 0, \
+ .type = INT_GATE_64, \
+ .priv = 0, \
+ .reserved = 0, \
+ .reserved_1 = 0, \
+ .reserved_2 = 0, \
+ .present = 1 \
+})
+
+#define GDT_ADDR (uint64_t)PHYS_TO_VIRT(0x7e22)
+
+#define IOAPICR_VER 1
+
+struct idt_descriptor {
+ uint16_t offset_1;
+ uint16_t segment;
+ unsigned int ist:3; //interupt stack table offset
+ unsigned int reserved:5;
+ unsigned int type:4;
+ unsigned int reserved_1:1;
+ unsigned int priv:2;
+ unsigned int present:1;
+ uint16_t offset_2;
+ uint32_t offset_3;
+ uint32_t reserved_2;
+} __attribute__((packed));
+
+
+struct segment_descriptor {
+ unsigned int priv:2;
+ unsigned int type:1;
+ unsigned int index:13;
+} __attribute__((packed));
+
+struct idt_reg {
+ uint16_t size;
+ uint64_t offset;
+} __attribute__((packed));
+
+struct gdt_reg {
+ uint16_t size;
+ uint64_t offset;
+} __attribute__((packed));
+
+struct idt_descriptor *idt;
+
+static struct idt_reg idtr;
+struct gdt_reg gdtr = {
+ .size = 0x17,
+ .offset = GDT_ADDR
+};
+
+
+lapic_t lapic; //would make this static but it's needed by timer.c
+static struct ioapic_fixedlen ioapic;
+static uint64_t isr_bitmap[4]; //first 32 is for exceptions;
+
+
+void disable_pic() {
+ //remapping PIC
+ outb_wait(PICM_COMMAND, ICW1_INIT | ICW1_ICW4); //initilizing
+ outb_wait(PICS_COMMAND, ICW1_INIT | ICW1_ICW4);
+
+ outb_wait(PICM_DATA, 32); //IRQ offsets
+ outb_wait(PICS_DATA, 40);
+
+ outb_wait(PICM_DATA, 4); //notify master of slave
+ outb_wait(PICS_DATA, 2); //nofity slave of mediocore social ethical standards
+
+ outb_wait(PICM_DATA, ICW4_8086);
+ outb_wait(PICS_DATA, ICW4_8086);
+
+
+ //masking.
+ outb_wait(PICS_DATA, 0xff);
+ outb_wait(PICM_DATA, 0xff);
+}
+
+void write_ioapic(void *ioapic_addr, uint32_t reg, uint32_t value) {
+ uint32_t *ioapic_r = ioapic_addr;
+ ioapic_r[0] = reg & 0xff;
+ ioapic_r[4] = value;
+}
+
+uint32_t read_ioapic(void *ioapic_addr, uint32_t reg) {
+ uint32_t *ioapic_r = ioapic_addr;
+ ioapic_r[0] = reg & 0xff;
+ return ioapic_r[4];
+}
+
+void create_fixed_interrupt(unsigned int irq, struct apic_vt *redirect) {
+ irq = irq_to_gsi(irq); //make sure there's no redirection entries.
+
+ struct ioapic_t *ioapic_smi = (void *)0;
+ for(unsigned int i = 0; i < ioapic.count; i++) {
+ if((irq >= ioapic.ioapic[i].gsi_base) &&
+ (irq < (ioapic.ioapic[i].gsi_base + ioapic.ioapic[i].gsi_count))) {
+ ioapic_smi = ioapic.ioapic[i].address;
+ break;
+ }
+ }
+ if(!ioapic_smi) PANIC(KERNEL_PANIC_INVALID_IOAPIC_VEC);
+
+
+ write_ioapic(ioapic_smi, (0x10 + (irq * 2)), *(uint32_t *)redirect);
+ write_ioapic(ioapic_smi, ((0x10 + (irq * 2)) + 1), *(uint64_t *)redirect >> 32);
+}
+
+unsigned int alloc_idt(struct idt_entry *entry) {
+ unsigned int b, i;
+ for(b = 0; b < (sizeof(isr_bitmap) / 8); b++) {
+ for(i = 0; i < 64; i++) {
+ if(!((isr_bitmap[b] >> i) & 1)) {
+ isr_bitmap[b] |= (uint64_t)1 << i;
+ idt[(b * 64) + i] = (struct idt_descriptor) {
+ .offset_1 = (uint16_t)((uint64_t)entry->addr & 0xffff),
+ .offset_2 = (uint16_t)((uint64_t)entry->addr >> 16),
+ .offset_3 = (uint32_t)((uint64_t)entry->addr >> 32),
+ .segment = 0x8,
+ .ist = entry->ist,
+ .type = entry->type,
+ .priv = entry->priv,
+ .reserved = 0,
+ .reserved_1 = 0,
+ .reserved_2 = 0,
+ .present = 1
+ };
+ return i;
+ }
+ }
+ }
+ return 0;
+}
+
+void modify_idt(struct idt_entry *entry, unsigned int vector) {
+ idt[vector] = (struct idt_descriptor) {
+ .offset_1 = (uint16_t)((uint64_t)entry->addr & 0xffff),
+ .offset_2 = (uint16_t)((uint64_t)entry->addr >> 16),
+ .offset_3 = (uint32_t)((uint64_t)entry->addr >> 32),
+ .segment = 0x8,
+ .ist = entry->ist,
+ .type = entry->type,
+ .priv = entry->priv,
+ .reserved = 0,
+ .reserved_1 = 0,
+ .reserved_2 = 0,
+ .present = 1
+ };
+}
+
+void free_idt(unsigned int entry) {
+ isr_bitmap[entry / 64] ^= ((uint64_t)1 << (entry & 63));
+ idt[entry].present = 0;
+}
+
+inline void clear_int() {
+ lapic[44] = 0;
+}
+
+
+void init_exceptions() {
+ //for idt index explainations, see include/panic.h
+ //TODO maybe utalize add_idt_entry?
+ unsigned int e;
+ idt[0] = KERNEL_IDT_DESC_GATE(fatal_hwexception);
+ idt[8] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode);
+ idt[16] = KERNEL_IDT_DESC_GATE(fatal_hwexception);
+ idt[17] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode);
+ idt[30] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode);
+ for(e = 5; e < 8; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception);
+ for(e = 10; e < 15; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode);
+ for(e = 18; e < 21; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception);
+}
+//void new_idt
+
+
+void init_interrupts() {
+ init_madt();
+ debug_madt();
+ lapic = get_lapic();
+
+ get_ioapic(&ioapic);
+ for(unsigned int i = 0; i < ioapic.count; i++) {
+ ioapic.ioapic[i].gsi_count = ((read_ioapic(ioapic.ioapic[i].address, IOAPICR_VER) >> 16) & 0xff);
+ printf("Found ioapic %i at addr %p, gsi %i to %i\n", i, ioapic.ioapic[i].address,
+ ioapic.ioapic[0].gsi_base, ioapic.ioapic[0].gsi_base + ioapic.ioapic[0].gsi_count);
+ }
+
+ disable_pic();
+
+ idt = palloc(0x1000);
+ idtr.size = 0x1000;
+ idtr.offset = (uint64_t)idt;
+
+ bzero(&isr_bitmap, sizeof(isr_bitmap));
+ isr_bitmap[0] = (((uint64_t)1 << 32) - 1);
+
+ //set idt and new gdt
+ asm("lgdt [%0]\n"
+ "lidt [%1]\n":: "m"(gdtr), "m"(idtr));
+
+
+ //Spurrious Interrupt (permanent, required for APIC)
+ idt[SPURRIOUS_VECTOR] = KERNEL_IDT_DESC_GATE(spurrious_int);
+
+ //Spurrious interrupt on IDT
+ lapic[60] = 0x1ff; //page 395
+
+ //initlize exceptions
+ init_exceptions();
+
+
+ //initilize the timers
+ init_timer();
+ asm("sti\n");
+}
diff --git a/src/kernel/io.c b/src/kernel/io.c
new file mode 100644
index 0000000..1974c35
--- /dev/null
+++ b/src/kernel/io.c
@@ -0,0 +1,24 @@
+#include <io.h>
+#include <stdint.h>
+//these functions are assumed not to be time-sensitive.
+void outb_wait(uint16_t port, uint8_t value) {
+ outb(port, value);
+ io_wait();
+}
+
+void read_msr(uint32_t addr, uint64_t *value) {
+ uint32_t low, high;
+ asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
+ *value = low | ((uint64_t)high << 32);
+}
+
+void write_msr(uint32_t addr, uint64_t value) {
+ uint32_t low = value & UINT32_MAX;
+ uint32_t high = value >> 32;
+ asm volatile("wrmsr"::"a"(low), "d"(high), "c"(addr));
+}
+
+void hlt() {
+ asm("cli\nhlt");
+}
+
diff --git a/src/kernel/isv.c b/src/kernel/isv.c
new file mode 100644
index 0000000..fbc60c0
--- /dev/null
+++ b/src/kernel/isv.c
@@ -0,0 +1,12 @@
+#include <printf.h>
+#include <stdint.h>
+#include <isv.h>
+#include <panic.h>
+
+
+__attribute__((interrupt)) void spurrious_int(void *unused) {
+ printf("Detected spurrious interrupt, doing nothing.\n");
+}
+
+
+
diff --git a/src/kernel/isv_asm.asm b/src/kernel/isv_asm.asm
new file mode 100644
index 0000000..b770aaa
--- /dev/null
+++ b/src/kernel/isv_asm.asm
@@ -0,0 +1,65 @@
+global timer_init_pit
+global kernel_block
+global fatal_hwexception
+global fatal_hwexception_errcode
+global lapic_timer_racefixer
+
+extern clear_int
+extern panic
+extern calibrate_lapic_waiting
+
+;I need to get my timing right and consistently boot smp,
+;_then_ I'll work on cleaning this up.
+
+timer_init_pit:
+cli
+mov ecx, DWORD [rbx + 0x390]
+mov DWORD [rbx + 0x380], 0
+in al, 0x61
+and al, 0xfe
+out 0x61, al
+mov DWORD [rbx + 0xb0], 0
+iretq
+
+
+kernel_block:
+call clear_int
+iretq
+
+
+fatal_hwexception:
+push qword rdi
+push qword rsi
+push qword rdx
+push qword rcx
+push qword rbx
+push qword rax
+mov rdi, 0
+mov rdx, rsp
+mov rsi, rdx
+add rsi, 48
+call panic
+
+; rdi: reason
+; rsi: frame
+; rdx: regs
+
+; 0xffff80000010af70
+fatal_hwexception_errcode:
+push qword rdi
+push qword rsi
+push qword rdx
+push qword rcx
+push qword rbx
+push qword rax
+mov rdi, 1
+mov rdx, rsp
+mov rsi, rdx
+add rsi, 48
+call panic
+
+lapic_timer_racefixer: ;in case the lapic makes it to zero, impliment me
+inc rbx
+call clear_int
+mov QWORD [rsp], calibrate_lapic_waiting
+iretq
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
index 50e0578..50b8359 100644
--- a/src/kernel/kernel.c
+++ b/src/kernel/kernel.c
@@ -1,31 +1,45 @@
#include <stdbool.h>
+#include <smp.h>
#include <serial.h>
#include <printf.h>
#include <paging.h>
#include <video.h>
#include <acpi.h>
#include <panic.h>
+#include <kernel.h>
+#include <stdbool.h>
+#include <int.h>
+#include <io.h>
+#include <cpuid.h>
+#include <heap.h>
+#include <random.h>
+#include <timer.h>
+#include <libc.h>
+
+//testing headers
+#include <testmalloc.h>
-void main() {
- if(!(init_serial(COM1))) {
- printf("\nKernal started on CPU 1!\n"); // will detect cpu later
- }
-
- rsdp_t *rsdp;
- rsdp = find_RSDP();
- if(!(rsdp)) {
- printf("Couldn't find the RSDP... not sure what to do now.\n");
- panic(KERNEL_PANIC_RSDP_UNFOUND, KERNEL_PANIC_INVOKED);
- }
- dump_video();
- debug_print_memory();
+void main() {
+#ifndef SCREEN_OUTPUT
+ if(init_serial(COM1)) printf("\nKernal started on CPU 1!\n");
+#endif
+ get_mem_capabilities();
+ init_pmap(map_complete_physical());
+ unmap_lowmem();
+
+
+ find_root_sdp();
+ debug_acpi();
+
+ init_interrupts();
- init_pmap();
- debug_pmap();
+
+ randinit();
- panic(KERNEL_PANIC_KERNEL_RETURNED, KERNEL_PANIC_INVOKED);
+ smp_boot();
+ PANIC(KERNEL_PANIC_KERNEL_RETURNED);
}
diff --git a/src/kernel/klog.c b/src/kernel/klog.c
new file mode 100644
index 0000000..52444b1
--- /dev/null
+++ b/src/kernel/klog.c
@@ -0,0 +1,100 @@
+#include <stdint.h>
+#include <serial.h>
+#include <io.h>
+#include <printf.h>
+#include <kernel.h>
+#include <stdbool.h>
+#include <libc.h>
+
+//README
+//this file has some temporary workarounds until I get further into development
+//this isn't going to be the serial driver I end up keeping
+
+#define VIDEO_BUFFER PHYS_TO_VIRT(0xb8000)
+#define MAX_LOOPBACK_ATTEMPTS 20
+
+//later we'll set it up for interrupting instead of polling
+bool init_serial(uint16_t port) {
+ outb_wait(port + 1, 0x00);
+ outb_wait(port + 2, 0x00);
+ outb_wait(port + 3, 0x80);
+ outb_wait(port + 0, 0x01); //here
+ outb_wait(port + 1, 0x00);
+ outb_wait(port + 3, 0x03);
+ outb_wait(port + 2, 0xc7);
+ outb_wait(port + 4, 0x0b);
+ outb_wait(port + 4, 0x1e);
+
+
+ //we shouldn't accept this as a loopback success.
+ //I'm making an exception because my dell desktop has a faulty serial port
+ //that requires some extra effort.
+
+ uint8_t loopback_byte;
+ for(int attempts = 0; attempts < MAX_LOOPBACK_ATTEMPTS; attempts++) {
+ outb_wait(port + 0, 0xae); // test char
+ loopback_byte = inb(port);
+ if(loopback_byte == 0xae) break;
+ }
+
+ if(loopback_byte != 0xae) {
+ //I'm sorry if these next few lines give you a stroke. They gave me one.
+
+ //My old Dell test desktop has disfunctional serial hardware that only works after a reboot.
+ //Seeing we don't have ACPI set up yet, we can't reboot without crashing.
+ //IM GOING TO REMOVE THIS ONCE I DEVELOP THE "REAL" SERIAL DRIVER!!!!
+ asm("mov rax, 0\n"
+ "div rax\n");
+ return false;
+ }
+
+ outb_wait(port + 4, 0x0f);
+ return true;
+}
+
+void _putchar_serial(uint16_t port, char msg) {
+ while(!(inb(port + 5) & 0x20)); //wait for transmit to be done
+ outb_wait(port, msg);
+}
+
+static unsigned int on_char = 0;
+static unsigned int on_line = 0;
+
+
+void clear_screen() {
+ char *screen_buffer = (void *)VIDEO_BUFFER;
+ for(unsigned int i = 0; i <= (80 * 25); i++) screen_buffer[i * 2] = ' ';
+ on_char = 0;
+ on_line = 0;
+}
+
+void next_line() {
+ if(on_line >= 25) {
+ on_line = 0;
+ clear_screen();
+ }
+ else {
+ on_line++;
+ }
+ on_char = 0;
+}
+
+void move_cursor(unsigned int x, unsigned int y) {
+ //yeah yeah yeah, it doens't test for overflows... I'm gonna delete this once i get serial working
+ //on my second desktop
+ on_char = x;
+ on_line = y;
+}
+
+//until we get serial working on hp
+void _putchar_screen(char msg) {
+ if(on_char >= 80) {
+ next_line();
+ } else if(msg == '\n') {
+ next_line();
+ return;
+ }
+ char *screen_buffer = (void *)((uint64_t)VIDEO_BUFFER + ((on_line * 160) + (on_char * 2)));
+ *screen_buffer = msg;
+ on_char++;
+}
diff --git a/src/kernel/libc.c b/src/kernel/libc.c
index c786cd0..4278281 100644
--- a/src/kernel/libc.c
+++ b/src/kernel/libc.c
@@ -3,7 +3,7 @@
// TODO clean up variable names
int strncmp(const char *s1, const char *s2, unsigned int n) {
int i;
- for(i = 0; ((i <= n) && (s1[i] != '\0') && (s2[i] != '\0')); i++) {
+ for(i = 0; ((i < (n - 1)) && (s1[i] != '\0') && (s2[i] != '\0')); i++) {
if(s1[i] != s2[i]) {
return(s1[i] - s2[i]);
}
@@ -11,6 +11,13 @@ int strncmp(const char *s1, const char *s2, unsigned int n) {
return(s1[i] - s2[i]);
}
+//this one hasn't been tested
+size_t strlen(const char *s) {
+ size_t len = 0;
+ while(s[len + 1] != '\0') len++;
+ return(len);
+}
+
int strcmp(const char *s1, const char *s2) {
int i;
for(i = 0; ((s1[i] != '\0') && (s2[i] != '\0')); i++) {
@@ -25,7 +32,7 @@ int memcmp(const void *s1, const void *s2, size_t n) {
const unsigned char *p1 = s1;
const unsigned char *p2 = s2;
int i;
- for(i = 0; i < n; i++) {
+ for(i = 0; i < n - 1; i++) {
if(p1[i] != p2[i]) {
return(p1[i] - p2[i]);
}
@@ -41,7 +48,7 @@ void strcpy(char *dest, char *src) {
void *memcpy(void *dest, char *src, size_t n) {
char *p = dest;
- for(unsigned int i = 0; i <= n; i++) {
+ for(unsigned int i = 0; i < n; i++) {
p[i] = src[i];
}
return(dest);
@@ -56,12 +63,16 @@ void *bzero(void *dest, size_t size) {
}
//TODO move this function to a seperate math library
-unsigned int ceil(double n) {
+int ceil(double n) {
int low_n = (int)n;
if(n == (double)low_n) return(low_n);
return(low_n + 1);
}
+int round(double n) {
+ return(int)(n + 0.5);
+}
+
void *memset(void *s, char c, size_t n) {
char *p = s;
for(size_t i = 0; i < n; i++) {
diff --git a/src/kernel/madt.c b/src/kernel/madt.c
new file mode 100644
index 0000000..62e0535
--- /dev/null
+++ b/src/kernel/madt.c
@@ -0,0 +1,179 @@
+#include <stdint.h>
+#include <libc.h>
+#include <acpi.h>
+#include <int.h>
+#include <kernel.h>
+#include <stddef.h>
+#include <heap.h>
+#include <printf.h>
+#include <smp.h>
+#include <madt.h>
+#include <cpuid.h>
+
+//madt entry types. there's more, we don't need em yet
+#define LOCAL_APIC 0
+#define IO_APIC 1
+#define IO_INT_OVERRIDE 2
+#define IO_APIC_NMI_SOURCE 3
+#define IO_APIC_NMI 4
+#define MADT_LOCAL_APIC_ADDR_OVERRIDE 5
+
+struct madt_sdt {
+ sdt_head header;
+ uint32_t apic_base;
+ uint32_t flags;
+} __attribute__((packed));
+
+struct madt_entry {
+ uint8_t type;
+ uint8_t length;
+} __attribute__((packed));
+
+struct madt_local_apic {
+ uint8_t processor_id;
+ uint8_t apic_id;
+ uint32_t flags;
+} __attribute__((packed));
+
+struct madt_local_apic_override {
+ uint16_t reserved;
+ void *apic_base;
+} __attribute__((packed));
+
+struct madt_ioapic {
+ uint8_t apic_id;
+ uint8_t reserved;
+ uint32_t addr;
+ uint32_t gsi_base;
+} __attribute__((packed));
+
+struct madt_io_int_override {
+ uint8_t bus_src; //not sure what this is used for.
+ uint8_t irq;
+ uint32_t global_vector;
+ uint16_t flags;
+} __attribute__((packed));
+
+static struct madt_sdt *madt;
+
+
+void init_madt() {
+ madt = find_sdt(SDT_MADT);
+}
+
+void debug_madt() {
+ struct madt_entry *entry;
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+ printf("MADT debug: ");
+ switch(entry->type) {
+ case LOCAL_APIC:
+ printf("local APIC\n");
+ break;
+ case IO_APIC:
+ printf("IOAPIC\n");
+ break;
+ case IO_INT_OVERRIDE:
+ printf("IOAPIC interupt override\n");
+ break;
+ case IO_APIC_NMI_SOURCE:
+ printf("IOAPIC NMI\n");
+ break;
+ case IO_APIC_NMI:
+ printf("Local APIC NMI\n");
+ break;
+ case MADT_LOCAL_APIC_ADDR_OVERRIDE:
+ printf("APIC addr override\n");
+ break;
+ default:
+ printf("other\n");
+ break;
+ }
+ }
+}
+
+unsigned int irq_to_gsi(unsigned int irq) {
+ struct madt_io_int_override *irq_override;
+ struct madt_entry *entry;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == IO_INT_OVERRIDE) {
+ irq_override = (void *)entry + 2;
+ if(irq_override->irq == irq) return irq_override->global_vector;
+ }
+ }
+ return (uint32_t)irq; //no entry found
+}
+
+void get_ioapic(struct ioapic_fixedlen *ret) {
+ struct madt_entry *entry;
+ struct madt_ioapic *mpio_entry;
+
+ ret->count = 0;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+ if(entry->type == IO_APIC) {
+ mpio_entry = (void *)entry + 2;
+ if(ret->count) {
+ ret->ioapic = realloc(ret->ioapic, ++ret->count * sizeof(struct ioapic_t));
+ }
+ else {
+ ret->ioapic = malloc(++ret->count * sizeof(struct ioapic_t));
+ }
+ ret->ioapic[ret->count - 1].address = PHYS_TO_VIRT((uintptr_t)mpio_entry->addr);
+ ret->ioapic[ret->count - 1].gsi_base = mpio_entry->gsi_base;
+ }
+ }
+}
+
+lapic_t get_lapic() {
+ struct madt_local_apic_override *ap_override;
+ struct madt_entry *entry;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == MADT_LOCAL_APIC_ADDR_OVERRIDE) {
+ ap_override = (void *)entry + 2;
+
+ return (lapic_t)PHYS_TO_VIRT(ap_override->apic_base);
+ }
+ }
+ return (lapic_t)PHYS_TO_VIRT((uint64_t)madt->apic_base);
+}
+
+void get_coreinfo(struct cores_info *cores) {
+ struct madt_local_apic *ap_info;
+ struct madt_entry *entry;
+ uint32_t unused_cpuid, ebx;
+
+ __get_cpuid(1, &unused_cpuid, &ebx, &unused_cpuid, &unused_cpuid);
+ cores->bsp = ebx << 24;
+
+ bzero(cores, sizeof(*cores));
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == LOCAL_APIC) {
+ ap_info = (void *)entry + 2;
+ if(ap_info->flags & 1) {
+ cores->apic_id[cores->corecount] = ap_info->processor_id;
+ cores->corecount++;
+ }
+ }
+ }
+}
diff --git a/src/kernel/page.c b/src/kernel/page.c
index de4f557..9db8660 100644
--- a/src/kernel/page.c
+++ b/src/kernel/page.c
@@ -1,12 +1,106 @@
#include <printf.h>
-#include <paging.h>
#include <stdint.h>
#include <libc.h>
#include <limits.h>
+#include <panic.h>
+#include <math.h>
#include <kernel.h>
+#include <stdbool.h>
+#include <cpuid.h>
+
+//just using char because c is a lil bitch and won't let us use void
+extern char _kernel_shared_zone_begin;
+
+
+
+// PAGE MAPPING
+#define PAGEMAP_LOCATION 0x10000
+
+#define MAX_BUDDY_ORDER 8
+#define PALLOC_AUTO_BLEVEL MAX_BUDDY_ORDER
+
+typedef struct phys_map {
+ struct phys_map *next;
+ unsigned int max_buddy;
+ uint64_t bsize[MAX_BUDDY_ORDER];
+ uint64_t *buddy[MAX_BUDDY_ORDER];
+} pmap_t;
+
+static pmap_t *first_pmap;
+
+#define MEM_AVAILABLE 1
+#define MEM_RESERVED 2
+#define MEM_APCI_RECLAIMABLE 3
+#define MEM_APCI_NVS 4
+#define MEM_BAD 5
+
+// ZONES
+#define ZONE_MAP_PLOC 0x7000
+#define ZONE_MAP PHYS_TO_VIRT(ZONE_MAP_PLOC)
+
+
+
+//reorganized (moved) from header
+typedef struct __attribute__((packed)) {
+ unsigned int present : 1; // present, must be one when accessed.
+ unsigned int read_write : 1; // if set to one, read and write is set
+ unsigned int user : 1; // For seperating CPL 0-2 and 3+
+ unsigned int writethrough_cache : 1; // honestly maybe I should look into caching
+ unsigned int cachable : 1; // hardware chaching. 0 is enabled, whats the worst that could happen?
+ unsigned int accessed : 1; // we'll never use any of these!
+ unsigned int zg0 : 1; // needs to be (and will be) zero'd
+ unsigned int size : 1; // if set to 1, this entry points to physical memory
+ unsigned int zg1 : 1; // needs to be (and will be) zero'd
+ unsigned int software_marks : 3; // available for our own use, I doubt we'll use it in such a simple thing
+
+ uintptr_t base_ptr : 40;
+ unsigned int avail:11;
+ unsigned int no_exec:1;
+} page_table;
+
+
+struct memory_table {
+ void *base;
+ uint64_t length;
+ uint32_t type;
+ uint32_t ACPI;
+} __attribute__((packed));
+
+static bool NX_capable;
+static bool huge_page_capable;
+
+
+void get_mem_capabilities() {
+ uint32_t unused, edx;
+ __get_cpuid(0x80000001, &unused, &unused, &unused, &edx);
+ huge_page_capable = (edx >> 26) & 1;
+ NX_capable = (edx >> 20) & 1;
+}
+
+
+void unmap_lowmem() {
+ struct stack_frame *frame;
+
+ asm("addq rsp, %0\n"
+ "addq rbp, %0\n"
+ "mov %0, rbp"
+ :"=r"(frame)
+ :"r"(PA_OFFSET));
+
+ while(frame->next != 0) {
+ printf("%p\n", frame->function_base);
+ frame->next = PHYS_TO_VIRT((void *)frame->next);
+ frame = frame->next;
+ }
+
+ //[future]
+ //eventually, you should use the function that unmaps pages when you write it
+ page_table *entry = (page_table *)PAGEMAP_LOCATION;
+ entry[0].present = 0;
+}
void debug_print_memory() {
- struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
+ struct memory_table *memtable = (void *)ZONE_MAP;
printf(" __________________________________________________________________________\n");
printf("| type\tstart\t\t\tend\t\t\tsize\t\t |\n");
printf("|--------------------------------------------------------------------------|\n");
@@ -16,32 +110,39 @@ void debug_print_memory() {
printf("----------------------------------------------------------------------------\n");
}
+void ram_stresser() {
+ struct memory_table *memtable = (void *)ZONE_MAP - PA_OFFSET;
+ memtable[6].length = 0x10000;
+}
+
void debug_pmap() {
- struct phys_map* pmap;
+ pmap_t *pmap = first_pmap;
int pmap_i = 0, order;
- uint64_t buddy_size, blong_i, bbit_i, buddy_chunksize, omit_cnt;
- printf("Maximum buddy order: %u (up to %#x sized chunks)\n", MAX_BUDDY_ORDER, (0x1000 << MAX_BUDDY_ORDER - 1));
- for(pmap = (struct phys_map*)&_stage2_pagetable; pmap != 0; pmap = pmap->next) {
+ uint64_t blong_i, bbit_i, buddy_chunksize, omit_cnt;
+ printf("Maximum buddy order: %u (up to %#x sized chunks)\n", MAX_BUDDY_ORDER, ((0x1000 << MAX_BUDDY_ORDER) - 1));
+ for(; pmap != 0; pmap = pmap->next) {
printf("Table %u:\n"
- "\tPhysical Start:\t%#p\n"
- "\tTable location:\t%#p\n", pmap_i, pmap->zone_paddr, pmap);
+ "\tPhysical/pmap start:\t%#p\n"
+ "\tTable Size:\t%u\n", pmap_i, pmap,
+ (uint64_t)(pmap->buddy[MAX_BUDDY_ORDER - 1] + pmap->bsize[MAX_BUDDY_ORDER - 1]) - (uint64_t)pmap);
+
for(order = 0; order <= MAX_BUDDY_ORDER - 1; order++) {
buddy_chunksize = (0x1000 << order); //TODO just put it in the for loop
- buddy_size = (((order == MAX_BUDDY_ORDER - 1)
- ? (uint64_t *)pmap->next : pmap->buddy[order + 1]) - pmap->buddy[order]);
printf("\tbuddy[%u]:\n"
- "\t\tAddress:\t%#x\n"
+ "\t\tAddress:\t%#p\n"
"\t\tSize:\t\t%u\n"
- "\t\tBuddies:\t\t\n", order, pmap->buddy[order], buddy_size);
+ "\t\tBuddies:\t\t\n", order, pmap->buddy[order], pmap->bsize[order]);
omit_cnt = 0;
- for(blong_i = 0; blong_i < buddy_size; blong_i++) {
+ for(blong_i = 0; blong_i < pmap->bsize[order]; blong_i++) {
for(bbit_i = 0; bbit_i < 64; bbit_i++) {
- if(*(pmap->buddy[order] + blong_i) & ((uint64_t)1 << bbit_i)) {
- if((omit_cnt < 20) || (blong_i == buddy_size - 1)) {
- printf("address %#x\tbit %u: %p\t is free\n",
- pmap->buddy[order] + blong_i, bbit_i, (uint64_t)pmap->zone_paddr + (((blong_i * 64) + bbit_i) * buddy_chunksize));
+ if((pmap->buddy[order][blong_i]) & ((uint64_t)1 << bbit_i)) {
+ if((omit_cnt < 20) || (blong_i == pmap->bsize[order] - 1)) {
+ printf("address %#p\tbit %u: %p\t is free\n",
+ pmap->buddy[order] + blong_i,
+ bbit_i,
+ ((uint64_t)pmap - PA_OFFSET) + ((((blong_i * 64) + bbit_i) * buddy_chunksize)));
}
omit_cnt++;
if(omit_cnt == 20) {
@@ -55,237 +156,291 @@ void debug_pmap() {
}
}
-void init_pmap() {
- struct memory_table *zones = (struct memory_table *)&_meminfo_loc;
- struct phys_map *pmap = (struct phys_map*)&_stage2_pagetable;
+//TODO I know you don't want to, but you need to thoroughly check this.
+void pfree(void *addr, size_t size) {
+ int blevel = 0;
+ uint64_t *onbyte; //the byte out buddy resides on in the current level
+ uint64_t page_bitloc; // how many bits we are away from buddy[0]. Helps calculate bitshifts
+ int bbitlen; //length of free'd area in current level
+ int lshift; //lshift is how many bits we shift over, rightbit is what it sounds like dumbass
+ pmap_t *pmap = first_pmap;
+
+ /* note: there's no security check to see if the page is actually allocated,
+ * or if we are freeing the table itself.
+ * This should be okay, as only the kernel will be calling it.
+ * If it gets too messy we can always come back.
+ */
- unsigned int zone_i, pmap_i = 0;
- int budorder;
- //we keep this info out of the struct because we won't need it after setting up
- uint64_t zone_len[MAX_ZONE_CNT], buddy_bitlen[MAX_ZONE_CNT][MAX_BUDDY_ORDER], *buddy_end;
- uint64_t pmap_size, pmap_bbitsize, pmap_blongsize, buddy_size, buddy_bit, pmap_bit;
- uint64_t threshold_bitsize, threshold_longsize = 0;
+ if(((uintptr_t)addr & 4095) || (size & 4095)) {
+ PANIC(KERNEL_PANIC_INVALID_PFREE);
+ return; //TODO [minor] some more specificity, not a huge deal
+ }
+ size /= 0x1000;
+ for(; pmap != 0; pmap = pmap->next) {
+ page_bitloc = (addr - (void *)pmap) / 0x1000;
+ onbyte = pmap->buddy[0] + (page_bitloc / 64);
+ if((addr >= (void *)pmap) && onbyte < pmap->buddy[1]) break;
+ }
-
- void *paged_mem = (void *)&_stage2_pagetable + 0x200000;
- map_page(&_stage2_pagetable, &_stage2_pagetable, PAGE_SIZE_2M);
+ while(blevel < MAX_BUDDY_ORDER) {
+ lshift = (page_bitloc / (1 << blevel)) & 63;
+ onbyte = pmap->buddy[blevel] + ((page_bitloc / 64) / (1 << blevel));
+ bbitlen = size / (1 << blevel);
- for(zone_i = 0; zones[zone_i].length > 0; zone_i++) {
- if((zones[zone_i].type == MEM_AVAILABLE) && (zones[zone_i].ACPI & 1)) {
+ //TODO clean up this part ------------------------------------------------------------- (below)
+ if(bbitlen <= 1) {
+ if(lshift & 1) {
+ if((*onbyte >> (lshift - 1)) & 1) {
+ *onbyte &= ~(((uint64_t)1 << (lshift - 1)) | ((uint64_t)1 << lshift));
+ size += (1 << blevel);
+ page_bitloc -= (1 << blevel);
+ bbitlen = size / (1 << blevel);
+ }
+ }
+ else if((*onbyte >> (lshift + 1)) & 1) {
+ *onbyte &= ~(((uint64_t)1 << (lshift + 1)) | ((uint64_t)1 << lshift));
+ size += (1 << blevel);
+ bbitlen = size / (1 << blevel);
+ }
+ }
+ else if(((lshift + bbitlen) & 1) && ((*onbyte >> (lshift + bbitlen)) & 1)) {
+ *onbyte ^= ((uint64_t)1 << (lshift + bbitlen));
+ size += (1 << blevel);
+ bbitlen = size / (1 << blevel);
+ }
+ //TODO clean up this part ------------------------------------------------------------- (above)
- //hopefully this should never happen...
- //I should dig into the docs to check before removing this.
- //We also could forget about MAX_ZONE_CNT if we did.
-
- if(zone_i >= MAX_ZONE_CNT) {
- printf("Only %u zones can be used! Modify MAX_ZONE_CNT in paging.h to use all memory.\n", MAX_ZONE_CNT);
+ if((!((size - 1) & size)) && (bbitlen != 1)) {
+ blevel = 63 - __builtin_clzl(size);
+ }
+ else {
+ if(bbitlen <= 1) {
+ *onbyte |= ((uint64_t)1 << lshift);
break;
+ } else if(bbitlen & 1) { //check me
+ size -= (1 << blevel);
+ *onbyte |= ((uint64_t)1 << (bbitlen + lshift));
}
+ blevel++;
+ }
+ }
+}
- if((zones[zone_i].base <= (void*)&_stage2_pagetable) &&
- (zones[zone_i].base + zones[zone_i].length >= (void *)&_stage2_pagetable)) {
- pmap->zone_paddr = &_stage2_pagetable;
- zone_len[pmap_i] = zones[zone_i].length - (pmap->zone_paddr - zones[zone_i].base);
- }
- else {
- pmap->zone_paddr = zones[zone_i].base;
- zone_len[pmap_i] = zones[zone_i].length;
- }
+void *palloc(size_t size) {
+ bool self_alloc;
+ int min_blevel, blevel;
+ uint64_t bbit, unshifted_entry, threshold, bloc; //TODO move when you've confirmed casting stuff
+ uint64_t buddy_i, *ret, *bentry;
+ int itercount;
+ pmap_t *pmap = first_pmap;
- pmap->buddy[0] = (void *)pmap + sizeof(*pmap);
- for(budorder = 1; budorder < MAX_BUDDY_ORDER; budorder++) {
- buddy_bitlen[pmap_i][budorder - 1] = GET_BUDDY_BITLEN(zone_len[pmap_i], budorder - 1);
- pmap->buddy[budorder] = (uint64_t *)pmap->buddy[budorder - 1] +
- LSIZE_FROM_BITLEN(buddy_bitlen[pmap_i][budorder - 1]);
- }
+ if(size == 0) return 0;
+ if(size & 4095) {
+ size = DIV_ROUND_UP(size, 0x1000);
+ }
+ else {
+ size = size / 0x1000;
+ }
+
+ //checking if pmap has been initilized; if not we've been called to self allocate
+ //the first buddy should never be allocated; that's where our pmap lives
+ if(pmap->buddy[pmap->max_buddy][0] & 1) {
+ self_alloc = true;
+ min_blevel = pmap->max_buddy;
+ }
+ else {
+ //log(size, 2)
+ self_alloc = false;
+ min_blevel = 63 - __builtin_clzl(size);
+ if(size & (size - 1)) min_blevel++;
+ if(min_blevel > MAX_BUDDY_ORDER - 1) return 0;
+ }
- buddy_bitlen[pmap_i][MAX_BUDDY_ORDER - 1] = GET_BUDDY_BITLEN(zone_len[pmap_i], MAX_BUDDY_ORDER - 1);
- pmap->next = (void *)pmap->buddy[MAX_BUDDY_ORDER - 1] +
- (LSIZE_FROM_BITLEN(buddy_bitlen[pmap_i][MAX_BUDDY_ORDER - 1]) * 8);
+ for(blevel = min_blevel; blevel < MAX_BUDDY_ORDER; blevel++) {
+ for(pmap = first_pmap; pmap != 0; pmap = pmap->next) {
- pmap = pmap->next;
- pmap_i++;
+ for(buddy_i = 0; buddy_i < pmap->bsize[blevel]; buddy_i++) {
+ if(pmap->buddy[blevel][buddy_i] > (uint64_t)0) {
+ bentry = &pmap->buddy[blevel][buddy_i];
+ bbit = __builtin_ctzl(*bentry);
+ bloc = bbit;
- //allocates by an extra sizeof(struct phys_map),
- //but were about to discard anyway
- while((void *)pmap + sizeof(*pmap) >= paged_mem) {
- map_page(paged_mem, paged_mem, PAGE_SIZE_2M);
- paged_mem += 0x200000;
- }
+ *bentry ^= (uint64_t)1 << bbit;
+
+ ret = (((buddy_i * 64) + bbit) * (0x1000 << blevel)) + (void *)pmap;
+
+ threshold = 0b11;
+
+ itercount = 1;
+ for(blevel--; blevel >= 0; blevel--) {
+ bentry = pmap->buddy[blevel] + ((bentry - pmap->buddy[blevel + 1]) * 2);
+ itercount++;
+ if(bloc >= 32) bentry += 1;
+ bloc = (bloc * 2) & 63; // will be the amount we need to shift
+ bbit = ceil((float)size / (1 << blevel));
+
+ unshifted_entry = ((uint64_t)1 << bbit) & threshold;
+ if(unshifted_entry) {
+ threshold = ((uint64_t)1 << (bbit * 2)) - 1;
+ }
+ else {
+ threshold = (threshold << 2) | threshold;
+ }
+ *bentry |= (unshifted_entry << bloc);
+ }
+ if(!self_alloc) bzero(ret, size * 0x1000);
+ return ret;
+ }
+ }
}
}
- pmap_size = (void*)(pmap) - (void*)&_stage2_pagetable;
- if(pmap_size >= zone_len[0]) panic(); //TODO debugging
+ return 0;
+}
- pmap_i = 0;
- for(pmap = (struct phys_map*)&_stage2_pagetable; pmap->next != 0; pmap = pmap->next) {
- for(budorder = MAX_BUDDY_ORDER - 1; budorder >= 0; budorder--) {
- pmap_bbitsize = ceil((float)pmap_size / ((uint64_t)0x1000 << budorder));
- pmap_blongsize = pmap_bbitsize / 64;
- if(budorder == MAX_BUDDY_ORDER - 1) {
- buddy_size = (uint64_t *)pmap->next - pmap->buddy[budorder];
- buddy_end = (uint64_t *)pmap->next - 1;
+//returns size of pages needed
+size_t map_complete_physical() {
+ uint64_t total_mem;
+ unsigned int pdpe_cnt, pde_cnt, pde_max_i;
+ int zone_i, entry_i;
+ struct memory_table *zones = (void *)ZONE_MAP_PLOC;
+
- threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2;
- }
- else {
- buddy_size = pmap->buddy[budorder + 1] - pmap->buddy[budorder];
- buddy_end = pmap->buddy[budorder + 1] - 1;
+ page_table *pml4 = (page_table *)PAGEMAP_LOCATION;
+ page_table *pdpe = (page_table *)&_kernel_shared_zone_begin;
+ page_table *pde;
- threshold_longsize = threshold_bitsize / 64;
- }
- pmap_bit = pmap_bbitsize & 63;
- buddy_bit = buddy_bitlen[pmap_i][budorder] & 63;
+ for(zone_i = 0; zones[zone_i].length > 0; zone_i++);
+ total_mem = (uint64_t)zones[zone_i - 1].base + zones[zone_i - 1].length;
+
+ pdpe_cnt = (total_mem + (0x40000000 - 1)) / 0x40000000;
+
+ entry_i = (PA_OFFSET >> 39) & 0x1ff;
+ pml4[entry_i].base_ptr = (uintptr_t)&_kernel_shared_zone_begin >> 12;
+ pml4[entry_i].read_write = 1;
+ pml4[entry_i].user = 0;
+ pml4[entry_i].size = 0;
+ pml4[entry_i].no_exec = 1;
+ pml4[entry_i].present = 1;
- if((pmap_bbitsize >= BITLEN_FROM_LSIZE(buddy_size)) && (pmap == (void *)&_stage2_pagetable)) {
- bzero(pmap->buddy[budorder], buddy_size * 8);
+ if(huge_page_capable) {
+ for(int pdpe_i = 0; pdpe_i < pdpe_cnt; pdpe_i++) {
+ pdpe[pdpe_i].base_ptr = pdpe_i << 18;
+ pdpe[pdpe_i].read_write = 1;
+ pdpe[pdpe_i].user = 0;
+ pdpe[pdpe_i].size = 1;
+ pdpe[pdpe_i].no_exec = NX_capable;
+ pdpe[pdpe_i].present = 1;
+ }
+ return pdpe_cnt * 0x1000;
+ }
+ else {
+ pde_cnt = (total_mem + 0x100000) / 0x200000;
+ for(int pdpe_i = 0; pdpe_i < pdpe_cnt; pdpe_i++) {
+ pde = (page_table *)(&_kernel_shared_zone_begin + (pdpe_cnt * 0x1000) + (pdpe_i * 0x1000));
+
+ if((pdpe_i < pdpe_cnt - 1) || (!(pde_cnt & 511))) {
+ pde_max_i = 512;
}
else {
- if(budorder == MAX_BUDDY_ORDER - 1) {
- if(pmap == (void*)&_stage2_pagetable) {
- if(pmap_blongsize) bzero(pmap->buddy[budorder], (pmap_blongsize - 1) * 8);
- if(pmap_bit) {
- *(pmap->buddy[budorder] + pmap_blongsize) = ~(((uint64_t)1 << pmap_bit) - 1);
- }
- else {
- *(pmap->buddy[budorder] + pmap_blongsize) = UINT64_MAX;
- }
- if(pmap_blongsize + 1 == buddy_size) {
- *buddy_end &= ((uint64_t)1 << buddy_bit) - 1;
- }
- else {
- memset(pmap->buddy[budorder] + pmap_blongsize + 1, UINT8_MAX, (buddy_size - 1) * 8);
- if(buddy_bit) {
- *buddy_end = ((uint64_t)1 << buddy_bit) - 1;
- }
- else {
- *buddy_end = UINT64_MAX;
- }
- }
- threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2;
- }
- else {
- memset(pmap->buddy[budorder], UINT8_MAX, (buddy_size - 1) * 8);
- if(buddy_bit) {
- *buddy_end = ((uint64_t)1 << buddy_bit) - 1;
- }
- else {
- *buddy_end = UINT64_MAX;
- }
- }
- }
- else if(pmap == (void *)&_stage2_pagetable) {
- if(threshold_longsize) bzero(pmap->buddy[budorder], (threshold_longsize - 1) * 8);
+ pde_max_i = pde_cnt & 511;
+ }
+
+ pdpe[pdpe_i].base_ptr = (uintptr_t)pde >> 12;
+ pdpe[pdpe_i].read_write = 1;
+ pdpe[pdpe_i].user = 0;
+ pdpe[pdpe_i].size = 0;
+ pdpe[pdpe_i].no_exec = NX_capable;
+ pdpe[pdpe_i].present = 1;
- if(threshold_bitsize > pmap_bbitsize)
- *(pmap->buddy[budorder] + threshold_longsize) = ((uint64_t)1 << ((threshold_bitsize - 1) & 63));
-
- if(buddy_size - threshold_longsize)
- bzero(pmap->buddy[budorder] + threshold_longsize + 1, buddy_size - threshold_longsize);
- if(buddy_bit & 1) {
- *buddy_end = ((uint64_t)1 << (buddy_bit - 1));
- }
- threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2;
- }
- else {
- bzero(pmap->buddy[budorder], buddy_size);
- if(buddy_bit & 1) {
- *buddy_end = ((uint64_t)1 << ((buddy_bit) - 1));
- }
- }
+ for(int pde_i = 0; pde_i < pde_max_i; pde_i++) {
+ pde[pde_i].base_ptr = ((pdpe_i << 9) + pde_i) << 9;
+ pde[pde_i].read_write = 1;
+ pde[pde_i].user = 0;
+ pde[pde_i].size = 1;
+ pde[pde_i].no_exec = NX_capable;
+ pde[pde_i].present = 1;
}
}
- pmap_i++;
+ return (pdpe_cnt * 2) * 0x1000;
}
}
+pmap_t *init_pmap(size_t pagetable_size) {
+ pmap_t *pmap, *last_pmap;
+ struct memory_table *zones = (void *)ZONE_MAP;
+ int budorder, zone_i;
+ uint64_t pmap_size, pmap_bbitsize, zone_size;
+ bool first_pmap_i = true;
-/**
- * BIG TODO:
- * Paging turned out to be simpler then I thought. I've temporarily fixed the code, but needs to be rewritten/simplified.
- * Let's get rid of those nasty GOTOs if we can.
- * Also, once we get physical memory allocator up and running, impliment that in this function.
-**/
+
-bool map_page(void *virtual_addr, void *physical_addr, uint8_t size) {
- //printf("map page called\n");
- uintptr_t va_ptr = (uintptr_t)virtual_addr;
- uintptr_t pa_ptr = (uintptr_t)physical_addr;
- if((va_ptr % (1 << size)) || (pa_ptr % (1 << size))) {
- return 0;
- }
- page_table *table = (page_table *)PAGEMAP_LOCATION;
- int pte_i = (va_ptr >> 12) & 0x1ff;
- int pde_i = (va_ptr >> 21) & 0x1ff;
- int pdpe_i = (va_ptr >> 30) & 0x1ff;
- int pml4e_i = (va_ptr >> 39) & 0x1ff;
-
- if(table->pml4e[pml4e_i].present) {
- if(table->pml4e[pml4e_i].base_ptr != (uintptr_t)&table->pdpe[pdpe_i] >> 12) goto error;
- if(table->pdpe[pdpe_i].present) {
- if(size == PAGE_SIZE_1G) {
- if(table->pdpe[pdpe_i].base_ptr == ((uintptr_t)pa_ptr >> 30 & 0x1ff))
- return true;
- goto error;
+ for(zone_i = 0; zones[zone_i].length > 0; zone_i++) {
+ if((zones[zone_i].type == MEM_AVAILABLE) && (zones[zone_i].ACPI & 1) &&
+ zones[zone_i].length >= (0x2000)) {
+ printf("found allocatable map at %p\n", zones[zone_i].base);
+ last_pmap = pmap;
+ if(zones[zone_i].base == (void *)0x100000) {
+ zone_size = zones[zone_i].length - (((uint64_t)&_kernel_shared_zone_begin - 0x100000) + pagetable_size);
+ pmap = PHYS_TO_VIRT((void *)&_kernel_shared_zone_begin + pagetable_size);
+ }
+ else {
+ zone_size = zones[zone_i].length;
+ pmap = PHYS_TO_VIRT(zones[zone_i].base);
}
- if(table->pdpe[pdpe_i].base_ptr != (uintptr_t)&table->pde[pde_i] >> 12) goto error;
- if(table->pde[pde_i].present) {
- if(size == PAGE_SIZE_2M) {
- if(table->pde[pde_i].base_ptr == ((uintptr_t)pa_ptr >> 21 & 0x1ff))
- return true;
- goto error;
+ if(first_pmap_i) {
+ pmap->next = NULL;
+ first_pmap_i = false;
+ }
+ else {
+ pmap->next = last_pmap;
+ }
+
+ for(budorder = 0; budorder < MAX_BUDDY_ORDER; budorder++) {
+ pmap_bbitsize = zone_size / (0x1000 << budorder);
+ pmap->bsize[budorder] = DIV_ROUND_UP(pmap_bbitsize , 64);
+ if(budorder) {
+ pmap->buddy[budorder] = pmap->buddy[budorder - 1] + pmap->bsize[budorder - 1];
+ }
+ else {
+ pmap->buddy[0] = (void *)pmap + sizeof(*pmap);
+ }
+ if(budorder < MAX_BUDDY_ORDER - 1) {
+ bzero(pmap->buddy[budorder], pmap->bsize[budorder] * 8);
+ if(pmap_bbitsize & 1) {
+ pmap->buddy[budorder][pmap->bsize[budorder] - 1] =
+ ((uint64_t)1 << ((pmap_bbitsize - 1) & 63));
+ }
+ if(pmap_bbitsize == 1) {
+ pmap->max_buddy = budorder;
+ for(budorder++; budorder < MAX_BUDDY_ORDER; budorder++) {
+ pmap->buddy[budorder] = 0;
+ pmap->bsize[budorder] = 0;
+ }
+ break;
+ }
}
- if(table->pde[pde_i].base_ptr != (uintptr_t)&table->pte[pte_i] >> 12) goto error;
- if(table->pte[pte_i].present) {
- if(table->pte[pte_i].base_ptr != ((pa_ptr >> 12) & 0x1ff)) goto error;
- return true;
+ else {
+ pmap->max_buddy = MAX_BUDDY_ORDER - 1;
+ memset(pmap->buddy[budorder], UINT8_MAX, pmap->bsize[budorder] * 8);
+ if((pmap_bbitsize / 64) != (pmap->bsize[budorder])) {
+ pmap->buddy[budorder][pmap->bsize[budorder] - 1] =
+ (((uint64_t)1 << (pmap_bbitsize & 63)) - 1);
+ }
}
- else goto mod_page_pte;
}
- else goto mod_page_pde;
- }
- else goto mod_page_pdpe;
- }
- else {
- table->pml4e[pml4e_i].base_ptr = (uintptr_t)&table->pdpe[pdpe_i] >> 12;
- table->pdpe[pml4e_i].read_write = 1;
- table->pml4e[pml4e_i].present = 1;
-mod_page_pdpe:
- table->pdpe[pdpe_i].read_write = 1;
- //TODO you just found out things are a lot more simple then you thought!
- if(size == PAGE_SIZE_1G) {
- table->pdpe[pdpe_i].size = 1;
- table->pdpe[pdpe_i].base_ptr = pa_ptr >> 12;
- table->pdpe[pdpe_i].present = 1;
- return true;
- }
- table->pdpe[pdpe_i].base_ptr = (uintptr_t)&table->pde[pde_i] >> 12;
- table->pdpe[pdpe_i].present = 1;
-mod_page_pde:
- table->pde[pde_i].read_write = 1;
- if(size == PAGE_SIZE_2M) {
- table->pde[pde_i].size = 1;
- table->pde[pde_i].base_ptr = pa_ptr >> 12;
- table->pde[pde_i].present = 1;
- return true;
+
+ pmap_size = (uint64_t)(pmap->buddy[pmap->max_buddy] + pmap->bsize[pmap->max_buddy]) - (uint64_t)pmap;
+ first_pmap = pmap; //we spoof palloc into allocating from the specific required pmap.
+ palloc(pmap_size);
}
- table->pde[pde_i].base_ptr = (uintptr_t)&table->pte[pte_i] >> 12;
- table->pde[pde_i].present = 1;
-mod_page_pte:
- table->pte[pte_i].base_ptr = pa_ptr >> 12;
- table->pte[pte_i].read_write = 1;
- table->pte[pte_i].present = 1;
- return true;
}
-error:
- printf("Page allocation error!\n");
- return false;
+ return pmap;
}
diff --git a/src/kernel/panic.c b/src/kernel/panic.c
index 851684a..82a761f 100644
--- a/src/kernel/panic.c
+++ b/src/kernel/panic.c
@@ -1,13 +1,15 @@
#include <panic.h>
#include <stdint.h>
#include <printf.h>
+#include <kernel.h>
+#include <serial.h>
+#include <isv.h>
-void panic(int reason, int type) { // will fill with debugging info latter
+void panic(int reason, void *eframe_p, struct registers *regs) { // will fill with debugging info latter
+
- struct stack_frame *frame;
-
#ifdef EASTEREGG_BLOATWARE
- printf("Kernel PANIC!!!!!!!\n");
+ printf("\nKernel PANIC!!!!!!!\n");
printf(
" _.-^^---....,,-- \n"
" _-- --_ \n"
@@ -24,31 +26,65 @@ void panic(int reason, int type) { // will fill with debugging info latter
printf("Kernel Panic!\n");
#endif
- printf("Reason:\n");
-
switch(reason) {
- case KERNEL_PANIC_PMAPSIZE :
- printf("\tThe physical map can't fit in the first memory zone.\n"
- "\tNote: If you have this issue, please contact me.\n"
- "\tIt's a fixable bug caused by an unlikely scenario.\n");
- break;
- case KERNEL_PANIC_RSDP_UNFOUND:
- printf("\tRSDP unfound!\n");
- break;
- case KERNEL_PANIC_KERNEL_RETURNED:
- printf("\tThe kernel (almost) reached its return!\n");
- break;
+ case KERNEL_PANIC_HW_EXCEPTION:
+ case KERNEL_PANIC_HW_EXCEPTION_ERR:
+ printf("\nHardware exception in kernel space!\n");
+ break;
+
+ case KERNEL_PANIC_RSDP_UNFOUND:
+ printf("\nRSDP unfound!\n");
+ break;
+ case KERNEL_PANIC_KERNEL_RETURNED:
+ printf("\nThe kernel (almost) reached its return!\n");
+ break;
+ case KERNEL_PANIC_INVALID_PFREE:
+ printf("\npfree was called with invalid paramaters.\n");
+ break;
+ case KERNEL_PANIC_INVALID_RSDT:
+ printf("\nInvalid RSDT or XSDT after RSDP verification.\nIf this happens, go buy some lottery tickets.\n");
+ break;
+ case KERNEL_PANIC_INVALID_IOAPIC_VEC:
+ printf("\nThe kernel tried to make a vector that was too high for the IOAPIC to handle.\n");
+ break;
+ case KERNEL_PANIC_HPET_REQUIRED:
+ printf("\nHPET is required. \nIf you get this error, let know;\nif enough people share this issue, I'll impliment PIT usage.\n");
+ default:
+ printf("\nUnknown panic code %i\n.", reason);
+ break;
}
- printf("\nStack trace:\n");
+ struct stack_frame *frame;
- asm("mov %%rbp,%0" : "=r"(frame) ::);
+ char reg_str[156];
+ if((reason == KERNEL_PANIC_HW_EXCEPTION) || (reason == KERNEL_PANIC_HW_EXCEPTION_ERR)) {
+ sprintf(reg_str, "rax:\t0x%lx\n"
+ "rbx:\t0x%lx\n"
+ "rcx:\t0x%lx\n"
+ "rdx:\t0x%lx\n"
+ "rsi:\t0x%lx\n"
+ "rdi:\t0x%lx\n", regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);
+ }
+ if(reason == KERNEL_PANIC_HW_EXCEPTION) {
+ struct int_frame *ex_frame = eframe_p;
+ printf("Offending instruction:\t0x%p\n", ex_frame->rip);
+ printf(reg_str);
+ }
+ else if (reason == KERNEL_PANIC_HW_EXCEPTION_ERR) {
+ struct exception_frame *ex_frame = eframe_p;
+ printf("Offending instruction: 0x%p\nError value: %x\n", ex_frame->frame.rip, ex_frame->err);
+ printf(reg_str);
+ }
+ asm("mov %0, rbp" : "=r"(frame) ::);
+ printf("\nCall trace:\n");
+
for(; frame->next != 0; frame = frame->next) {
- printf("\t%x\n", frame->function_base);
+ printf("\t0x%p\n", frame->function_base);
}
+
- //It's not public yet, but it will be
+ //It's not public yet, but if I ever get somewhere it will be
printf("\nAfter ensuring your computer meets the requirements specified, if you think this is a bug, please open an issue on the git repo or email me at %s.\n", DEV_EMAIL);
- for(;;);
+ asm("cli\nhlt");
}
diff --git a/src/kernel/printf.c b/src/kernel/printf.c
index 14c897d..8267755 100644
--- a/src/kernel/printf.c
+++ b/src/kernel/printf.c
@@ -39,10 +39,12 @@
#include <serial.h>
//and my options
+/**
#define PRINTF_DISABLE_SUPPORT_FLOAT
#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL
#define PRINTF_DISABLE_SUPPORT_LONG_LONG
#define PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+**/
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
@@ -159,7 +161,11 @@ static inline void _out_char(char character, void* buffer, size_t idx, size_t ma
{
(void)buffer; (void)idx; (void)maxlen;
if (character) {
+#ifdef SCREEN_OUTPUT
+ _putchar_screen(character);
+#else
_putchar_serial(COM1, character); // later we should figure out a way to not specifify exclusively com1
+#endif
}
}
diff --git a/src/kernel/random.c b/src/kernel/random.c
new file mode 100644
index 0000000..404223a
--- /dev/null
+++ b/src/kernel/random.c
@@ -0,0 +1,36 @@
+#include <stdbool.h>
+#include <cpuid.h>
+#include <printf.h>
+#include <stdint.h>
+
+static bool hw_random = false;
+static unsigned long int seed = -1;
+
+void randinit() {
+ unsigned int unused, eax, ecx;
+ eax = 0;
+ ecx = 0;
+ __get_cpuid(1, &eax, &unused, &ecx, &unused);
+ hw_random = (ecx >> 30) & 1;
+ printf("Kernel random source: %s.\n", (hw_random) ? "rdrand" : "pseudo");
+}
+
+//As of now, this function isn't nessesarily meant to be fast.
+unsigned int randint() {
+ uint64_t random_long = 0;
+ if(hw_random) {
+ asm("rand:\n"
+ "rdrand %0\n"
+ "jc finished\n"
+ "pause\n"
+ "jmp rand\n"
+ "finished:" :"=r"(random_long)::"rax" );
+ }
+ else {
+ //TODO FUCKING ENTROPY!!!!!!!111
+ seed = 1103515245 * seed + 12345;
+ return(unsigned int)(seed / 65536) % 32768;
+ }
+ return 0;
+}
+
diff --git a/src/kernel/smp.c b/src/kernel/smp.c
new file mode 100644
index 0000000..d3c74fe
--- /dev/null
+++ b/src/kernel/smp.c
@@ -0,0 +1,80 @@
+#include <kernel.h>
+#include <madt.h>
+#include <timer.h>
+#include <cpuid.h>
+#include <int.h>
+#include <libc.h>
+
+#define LAPIC_ICR_LOW 192
+#define LAPIC_ICR_HIGH 196
+
+extern lapic_t lapic;
+extern char __load_start_smp_bootloader, __load_stop_smp_bootloader;
+extern uint8_t *smp_bootstrap_corecount;
+
+struct icr_reg {
+ uint8_t vector;
+ unsigned int deliv_mode:3;
+ unsigned int dest_mode:1;
+ unsigned int deliv_status:1;
+ unsigned int reserved:1;
+ unsigned int level:1; //0 = de-assert
+ unsigned int trig_mode:1;
+ unsigned int reserved_1:2;
+ unsigned int dest_shorthand:2;
+ unsigned int reserved_2:12;
+}__attribute__((packed));
+
+//1: get bsp number 2
+//2: get list of lapics 3
+//3: copy code 1
+//4:
+
+
+static inline void write_icr(uint8_t dest, uint32_t message) {
+ lapic[LAPIC_ICR_HIGH] = (uint32_t)dest << 24;
+ lapic[LAPIC_ICR_LOW] = message;
+}
+
+void smp_boot() {
+ uint8_t cores_active = 0; //TODO change in asm
+ struct cores_info cores;
+ unsigned int ci;
+
+ struct icr_reg icr;
+ bzero(&icr, sizeof(icr));
+
+ memcpy(PHYS_TO_VIRT((void *)0x8000), PHYS_TO_VIRT(&__load_start_smp_bootloader),
+ &__load_stop_smp_bootloader - &__load_start_smp_bootloader);
+ *(uint8_t **)PHYS_TO_VIRT(&smp_bootstrap_corecount) = &cores_active;
+
+
+ get_coreinfo(&cores);
+
+ icr.deliv_mode = 0b101;
+ icr.dest_shorthand = 0b11;
+ icr.level = 1;
+ write_icr(0, *(uint32_t *)&icr);
+ usleep(10000);
+
+ icr.deliv_mode = 0b110;
+ icr.vector = 8;
+ write_icr(0, *(uint32_t *)&icr);
+ usleep(200);
+ write_icr(0, *(uint32_t *)&icr);
+
+ /**
+ if(cores_active != cores.corecount) {
+ write_icr(0, *(uint32_t *)&icr);
+ usleep(200);
+ }
+ **/
+ /**
+ for(ci = 0; ci < cores.corecount; ci++) {
+ if(ci == cores.bsp) continue;
+ //send init sipi
+ write_icr(ci, *(uint32_t *)&icr);
+ }
+ **/
+
+}
diff --git a/src/kernel/smp_trampoline.asm b/src/kernel/smp_trampoline.asm
new file mode 100644
index 0000000..f723aa6
--- /dev/null
+++ b/src/kernel/smp_trampoline.asm
@@ -0,0 +1,140 @@
+global smp_bootstrap_corecount;
+
+[bits 16]
+smp_trampoline:
+cli
+hlt
+hlt
+
+xor ax, ax
+mov ds, ax
+lgdt [.gdt_descriptor_p]
+mov eax, cr0
+or eax, 0x1
+mov cr0, eax ; now in long mode
+
+jmp 0x8:.smp_protected
+
+
+;________________________________________________________________________________________
+
+;TODO find how to use old gdt
+.gdt_start_p: ; we need to start with a null gdt
+dd 0
+dd 0
+
+.gdt_code_p:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10011010b
+db 11001111b
+db 0x0000
+
+.gdt_data_p:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10010010b
+db 11001111b
+db 0x0000
+
+.gdt_end_p:
+
+.gdt_descriptor_p:
+ dw .gdt_end_p - .gdt_start_p - 1
+dq .gdt_start_p
+
+SMP_PROTECTED_CODE_SEGMENT equ .gdt_code_p - .gdt_start_p
+SMP_PROTECTED_DATA_SEGMENT equ .gdt_data_p - .gdt_start_p
+
+;________________________________________________________________________________________
+
+.smp_protected
+
+[bits 32]
+mov ax, SMP_PROTECTED_DATA_SEGMENT
+mov ds, ax
+mov ss, ax
+mov es, ax
+mov fs, ax
+mov gs, ax
+
+mov eax, 0x10000 ;TODO clarify _why_ this is a thing
+mov cr3, eax
+
+;setting up misc features
+mov eax, cr4
+; PAE, OSFXSR, OSXMMEXCPT
+or eax, 1 << 5 | 1 << 9 | 1 << 10
+mov cr4, eax
+
+
+;set NX and LME
+mov eax, 0x80000001
+cpuid
+and edx, 1 << 20
+shr edx, 9
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8 | 1 << 11
+or eax, edx
+wrmsr
+
+;enable paging
+mov eax, cr0
+or eax, 1 << 31 | 1 << 0;
+and ax, ~(1 << 2)
+mov cr0, eax
+
+jmp SMP_LONG_CODE_SEGMENT:.counter
+
+;________________________________________________________________________________________
+
+[bits 64]
+;TODO do we really need all this?
+.gdt_start_l:
+;and now we set up a temporary GDT creating a 1:1 mapping
+dw 0xffff
+dw 0
+db 0 ;this is the invalid GDT
+db 0
+db 1
+db 0
+
+;now for the code GDT:
+.gdt_code_l:
+dw 0 ; segment limit 15:00 (I don't think this matters in 64 bit mode!)
+dw 0 ; base address 15:00
+db 0 ; base address 23:16
+db 10011010b
+db 00100000b
+db 0
+
+.gdt_data_l:
+dw 0
+dw 0
+db 0
+db 10010010b
+db 00100000b
+db 0
+
+.gdt_end_l: ; later calculates offset in defs below
+
+
+.descriptor_l:
+ dw .gdt_end_l - .gdt_start_l - 1
+dq .gdt_start_l
+
+SMP_LONG_CODE_SEGMENT equ .gdt_code_l - .gdt_start_l
+SMP_LONG_DATA_SEGMENT equ .gdt_data_l - .gdt_start_l
+
+.counter:
+mov rax, [smp_bootstrap_corecount]
+inc QWORD [rax]
+cli
+hlt
+;TODO set up stack; enter kernel
+
+smp_bootstrap_corecount: db 0
diff --git a/src/kernel/testmalloc.c b/src/kernel/testmalloc.c
new file mode 100644
index 0000000..5733c7c
--- /dev/null
+++ b/src/kernel/testmalloc.c
@@ -0,0 +1,35 @@
+#define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + 5)))
+
+#include <printf.h>
+#include <heap.h>
+#include <libc.h>
+#include <random.h>
+
+//will delete later
+
+void test_malloc(unsigned int cnt) {
+ void *testchunks[cnt];
+ unsigned int rindex[cnt], testchunk_size, i, x;
+
+ bzero(rindex, cnt * sizeof(unsigned int));
+ for(x = 0; x < cnt; x++) {
+ testchunk_size = (CHUNK_SIZE_FROM_INDEX(randint() % 7) - 24);
+ testchunks[x] = malloc(testchunk_size);
+ //printf("ALLOCATING CHUNK %p SIZE %i\n", (void *)testchunks[x] - 24, testchunk_size);
+ }
+ for(x = 0; x < cnt;) {
+ i = randint() % cnt;
+ if(rindex[i]) continue;
+ rindex[i] = x;
+ x++;
+ }
+ for(x = 0; x < cnt; x++) {
+ //printf("FREEING CHUNK %p\n", (void *)testchunks[rindex[x]]);
+ free(testchunks[rindex[x]]);
+ }
+ printf("\nmalloc tester:\n");
+ printf("THIS NEEDS TO BE EMPTY______________\n");
+ debug_heap();
+ printf("____________________________________\n");
+
+}
diff --git a/src/kernel/timer.c b/src/kernel/timer.c
new file mode 100644
index 0000000..aed42ba
--- /dev/null
+++ b/src/kernel/timer.c
@@ -0,0 +1,296 @@
+#include <acpi.h>
+#include <stdbool.h>
+#include <io.h>
+#include <printf.h>
+#include <libc.h>
+#include <kernel.h>
+#include <cpuid.h>
+#include <panic.h>
+#include <int.h>
+#include <isv.h>
+
+
+#define PIT_COMMAND 0x43
+#define PIT_FREQ 1193182
+
+#define PIT_CHANNEL_0 0x40
+#define PIT_CHANNEL_2 0x42
+#define PIT_INPUT_2 0x61
+//you can move these if it makes more sense to put them in a lapic.h
+#define LAPIC_TIMER_LVT 200
+#define LAPIC_TIMER_INIT_COUNT 224
+#define LAPIC_TIMER_CURRENT_COUNT 228
+#define LAPIC_TIMER_DIVIDE 248
+
+#define LAPIC_TIMER_MODE_ONESHOT 0b00
+#define LAPIC_TIMER_MODE_PERIODIC 0b01
+#define LAPIC_TIMER_MODE_TSC_DEADLINE 0b10
+
+#define IA32_TSC_DEADLINE 0x6E0
+
+
+struct acpi_addr_fmt {
+ uint8_t addr_space; //0 is system memory, 1 is system io
+ uint8_t reg_bit_width;
+ uint8_t reg_bit_offset;
+ uint8_t resrved;
+ uint64_t addr;
+} __attribute__((packed));
+
+struct hpet_sdt {
+ sdt_head header;
+ uint8_t hw_rev_id;
+ unsigned int comparator_cnt:5;
+ unsigned int counter_size_64bit:1;
+ unsigned int reserved:1;
+ unsigned int legacy_capable:1;
+ uint16_t vendor_id;
+ struct acpi_addr_fmt acpi_addr;
+ uint8_t hpet_number;
+ uint16_t min_tick;
+ unsigned int protection:4; //0 = no protection, 1 = 4kb, 2 = 64kb
+ unsigned int oem_attribute:4;
+} __attribute__((packed));
+
+struct hpet_info_struct {
+ uint64_t *hpet_reg;
+ unsigned int hpet_period;
+ double hpet_freq_mhz; //improves speed with us quantum
+ unsigned int timer_cnt;
+ unsigned int irqs;
+ bool long_mode;
+} hpet_info;
+
+
+struct lapic_lvt {
+ uint8_t vector;
+ unsigned int reserved:4;
+ unsigned int delivery_status:1;
+ unsigned int reserved_1:3;
+ unsigned int mask:1;
+ unsigned int timer_mode:2;
+ unsigned int reserved_2:13;
+} __attribute__((packed));
+
+extern lapic_t lapic;
+
+#define TSC_TIME_TSC_EVENT 0
+#define TSC_TIME_LAPIC_EVENT 1
+#define LAPIC_TIME_HPET_EVENT 2
+
+static int clock_mode;
+
+//time quantum is 1us
+static double tsc_freq;
+static double apic_freq;
+
+static unsigned int early_event_vector;
+
+static struct lapic_lvt lapic_timer_lvt;
+
+uint64_t timestamp() {
+ if((clock_mode == TSC_TIME_TSC_EVENT) || (clock_mode == TSC_TIME_LAPIC_EVENT)) {
+ return read_tsc() / tsc_freq;
+ }
+ else {
+ return UINT32_MAX - (lapic[LAPIC_TIMER_CURRENT_COUNT] / apic_freq);
+ }
+ return 0;
+}
+
+//timer test code
+//there is a race condition here.
+//I'm leaving it unattended, as I'm only expecting this to be used for SMP booting.
+void usleep(unsigned int us) {
+ if(clock_mode == TSC_TIME_TSC_EVENT) {
+ write_msr(IA32_TSC_DEADLINE, ((uint64_t)((us * (double)tsc_freq) + 0.5)) + read_tsc());
+ }
+ else if(clock_mode == TSC_TIME_LAPIC_EVENT) {
+ lapic[LAPIC_TIMER_INIT_COUNT] = (uint32_t)((us * (double)apic_freq) + 0.5);
+ }
+ else {
+ hpet_info.hpet_reg[33] = hpet_info.hpet_reg[30] +
+ (uint32_t)((us * hpet_info.hpet_freq_mhz) + 0.5);
+ }
+ asm("hlt\n");
+}
+
+/**
+we either use:
+1: tsc
+2: tsc
+
+1: tsc
+2: lapic (no tsc deadline)
+
+1: lapic
+2: hpet
+
+PIT not implimented, I've yet to find a computer that doesn't have HPET
+**/
+
+void calibrate_lapic() {
+ unsigned int timer_idt = alloc_idt(&KERNEL_IDT_GATE(lapic_timer_racefixer));
+ uint32_t lapic_ticks;
+ uint64_t hpet_ticks = (100000000000000 * (1 / (double)hpet_info.hpet_period)) + 0.5;
+ uint64_t timer_loops = 0;
+ struct lapic_lvt timer_lvt = {
+ .vector = timer_idt,
+ .delivery_status = 0,
+ .mask = 0,
+ .timer_mode = LAPIC_TIMER_MODE_PERIODIC
+ };
+ printf("Starting LAPIC timer calibration...\n");
+
+ lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&timer_lvt;
+ lapic[LAPIC_TIMER_DIVIDE] = 0b1011;
+ asm(".global calibrate_lapic_waiting\n"
+ "xor rbx, rbx\n"
+ "mov rax, %2\n"
+ "add rax, %3\n"
+ "mov [%4], rax\n" //hpet timer
+ "mov [%5], 0xffffffff\n" //lapic timer
+ "calibrate_lapic_waiting:\n"
+ "hlt\n"
+ "mov %0, %6\n" //save lapic time
+ "mov [%5], 0\n"
+ "mov %1, rbx\n"
+ :"=r"(lapic_ticks), "=r"(timer_loops)
+ :"r"(hpet_ticks), "m"(hpet_info.hpet_reg[30]), "m"(hpet_info.hpet_reg[33]),
+ "m"(lapic[LAPIC_TIMER_INIT_COUNT]), "m"(lapic[LAPIC_TIMER_CURRENT_COUNT])
+ :"rax","rbx" );
+ apic_freq = ((UINT32_MAX * timer_loops) + (UINT32_MAX - lapic_ticks)) / (double)100000;
+
+ printf("LAPIC timer frequency: %f MHz\n", apic_freq);
+ free_idt(timer_idt);
+}
+
+
+void init_timer() {
+ struct hpet_sdt *hpet_desc = find_sdt(SDT_HPET);
+ early_event_vector = alloc_idt(&KERNEL_IDT_GATE(kernel_block));
+ if(!hpet_desc) PANIC(KERNEL_PANIC_HPET_REQUIRED);
+
+ unsigned int first_irq;
+
+ struct apic_vt hpet_redirect;
+ bzero(&hpet_redirect, sizeof(hpet_redirect));
+ hpet_redirect.vector = early_event_vector;
+ hpet_redirect.polarity = 1;
+
+
+ hpet_info.hpet_reg = PHYS_TO_VIRT(hpet_desc->acpi_addr.addr);
+ hpet_info.hpet_period = (hpet_info.hpet_reg[0] >> 32) & UINT32_MAX;
+ hpet_info.long_mode = (hpet_info.hpet_reg[0] >> 13) & 1;
+ hpet_info.irqs = (hpet_info.hpet_reg[32] >> 32) & UINT32_MAX;
+ hpet_info.hpet_freq_mhz = (1 / (double)hpet_info.hpet_period) * 1000000000;
+ //get first irq available
+ first_irq = __builtin_ctzl(hpet_info.irqs) + 1;
+
+ printf("hpet frequency: %f MHz\n", hpet_info.hpet_freq_mhz);
+
+ //do we need to worry about bypassing irq remappings?
+ create_fixed_interrupt(first_irq, &hpet_redirect);
+
+ //set irq, enable triggering of interrupts
+ hpet_info.hpet_reg[32] = (first_irq << 9) | (1 << 2) | 1;
+
+ //enable main counter
+ hpet_info.hpet_reg[2] = 1;
+
+ asm("sti\n");
+
+ //detect consistent TSC
+ uint32_t unused, cpuid_reg;
+ __get_cpuid(0x80000007, &unused, &unused, &unused, &cpuid_reg);
+
+ //goto debug_tsc;
+ if((cpuid_reg >> 8) & 1) {
+ printf("Detected invariant TSC\n");
+ //.1 second to calibrate, TODO do we need to check if the register is big enough?
+ uint64_t hpet_ticks = (100000000000000 * (1 / (double)hpet_info.hpet_period)) + 0.5;
+ printf("Starting TSC calibration...\n");
+ uint64_t volatile start_tsc, end_tsc;
+ //this may not be the fastest, but I'll improve if needed further into development
+ asm volatile(
+ "xor rax, rax\n"
+ "rdtsc\n"
+ "shl rdx, 32\n"
+ "or rax, rdx\n"
+ "mov %0, rax\n"
+ "mov rbx, %4\n"
+ "add rbx, [%3]\n"
+ "mov [%2], rbx\n"
+ //if you're worried about a single instruction being a race condition, it's time for an upgrade
+ "xor rax, rax\n"
+ "hlt\n"
+ "rdtsc\n"
+ "shl rdx, 32\n"
+ "or rax, rdx\n"
+ "mov %1, rax\n"
+ :"=&r"(start_tsc), "=&r"(end_tsc)
+ :"m"(hpet_info.hpet_reg[33]), "m"(hpet_info.hpet_reg[30]),"r"(hpet_ticks)
+ :"rax","rbx","rdx");
+ tsc_freq = (end_tsc - start_tsc) / (double)100000;
+ printf("TSC: Detected frequency is %f MHz\n", tsc_freq);
+ __get_cpuid(0x1, &unused, &unused, &cpuid_reg, &unused);
+ if((cpuid_reg >> 24) & 1) {
+ clock_mode = TSC_TIME_TSC_EVENT;
+
+ lapic_timer_lvt.vector = early_event_vector;
+ lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_TSC_DEADLINE;
+ lapic_timer_lvt.delivery_status = 0;
+ lapic_timer_lvt.mask = 0;
+ }
+ else {
+ clock_mode = TSC_TIME_LAPIC_EVENT;
+ calibrate_lapic();
+
+ lapic_timer_lvt.vector = early_event_vector;
+ lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_ONESHOT;
+ lapic_timer_lvt.delivery_status = 0;
+ lapic_timer_lvt.mask = 0;
+ }
+ lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&lapic_timer_lvt;
+ }
+ else {
+ uint32_t apic_div;
+ clock_mode = LAPIC_TIME_HPET_EVENT;
+ calibrate_lapic();
+
+ //because lapic is used as scheduler, we want to cause as little interrupts as possible
+ //while retaining 1 mhz accuracy
+
+ apic_div = __builtin_clz((uint32_t)apic_freq);
+ if(!apic_div) {
+ apic_div = 0b1011;
+ }
+ else if(apic_div >= 7) {
+ apic_div = 0b1010;
+ apic_freq /= 128;
+ }
+ else {
+ apic_freq /= (1 << --apic_div);
+ apic_div = (((apic_div & 0b100) << 1) | (apic_div * 0b1011));
+ }
+
+ lapic_timer_lvt.vector = SPURRIOUS_VECTOR; //TODO CHANGE ME
+ lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_PERIODIC;
+ lapic_timer_lvt.delivery_status = 0;
+ lapic_timer_lvt.mask = 1;
+ lapic[LAPIC_TIMER_DIVIDE] = apic_div;
+ lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&lapic_timer_lvt;
+ lapic[LAPIC_TIMER_INIT_COUNT] = UINT32_MAX;
+ }
+ switch(clock_mode) {
+ case TSC_TIME_TSC_EVENT:
+ printf("Clock source: tsc\nEvent source: tsc-deadline\n");
+ break;
+ case TSC_TIME_LAPIC_EVENT:
+ printf("Clock source: tsc\nEvent source: lapic\n");
+ break;
+ case LAPIC_TIME_HPET_EVENT:
+ printf("Clock source: lapic\nEvent source: hpet\n");
+ break;
+ }
+}
diff --git a/src/kernel/drivers/video.c b/src/kernel/video.c
index ab73bb0..0433ce2 100644
--- a/src/kernel/drivers/video.c
+++ b/src/kernel/video.c
@@ -5,5 +5,6 @@
void dump_video() {
struct mode_info *video = (struct mode_info *)0x600;
- printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n", video->width, video->height, video->bpp, video->framebuffer);
+ printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n",
+ video->width, video->height, video->bpp, video->framebuffer);
}