/* Should be called by main. This will setup the special GDT * pointer, set up the first 3 entries in our GDT, and then * finally call gdt_flush() in our assembler file in order * to tell the processor where the new GDT is and update the * new segment registers */ void gdt_install() { kprintc(":: Installing ", BLACK, LIGHT_RED); kprintc("GDT\n", BLACK, LIGHT_CYAN); /* Setup the GDT pointer and limit */ gp.limit = (sizeof(struct gdt_entry) * 3) - 1; gp.base = (int)&gdt; /* Our NULL descriptor */ gdt_set_gate(0, 0, 0, 0, 0); /* The second entry is our Code Segment. The base address * is 0, the limit is 4GBytes, it uses 4KByte granularity, * uses 32-bit opcodes, and is a Code Segment descriptor. * Please check the table above in the tutorial in order * to see exactly what each value means */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* The third entry is our Data Segment. It's EXACTLY the * same as our code segment, but the descriptor type in * this entry's access byte says it's a Data Segment */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Flush out the old GDT and install the new changes! */ gdt_flush(); }
/* This installs a custom IRQ handler for the given IRQ */ void irq_install_handler(int irq, void (*handler)(struct regs *r), char *handler_name) { kprintc(":: Installing ", BLACK, LIGHT_RED); kprintc("IRQ Handler -> ", BLACK, GREEN); kprintc("[ ", BLACK, LIGHT_MAGENTA); kprintc(handler_name, BLACK, LIGHT_CYAN); kprintc(" ]\n", BLACK, LIGHT_MAGENTA); irq_routines[irq] = handler; }
// Prints a log message to the terminal void klog(const char text[]) { int i; for(i = 0; text[i] != '\0'; i++) { if(column >= 80) { row++; column = 0; if(row > TERM_ROWS) row = 0; } if(text[i] == '\n') { row++; column = 0; if(row > TERM_ROWS) row = 0; } else { kprintc(text[i], 0x07, column, row); column++; } } row++; column = 0; if(row > TERM_ROWS) scroll(); }
/* This is a very repetitive function... it's not hard, it's * just annoying. As you can see, we set the first 32 entries * in the IDT to the first 32 ISRs. We can't use a for loop * for this, because there is no way to get the function names * that correspond to that given entry. We set the access * flags to 0x8E. This means that the entry is present, is * running in ring 0 (kernel level), and has the lower 5 bits * set to the required '14', which is represented by 'E' in * hex. */ void isrs_install() { kprintc(":: Installing ", BLACK, LIGHT_RED); kprintc("ISRs\n", BLACK, LIGHT_CYAN); idt_set_gate(0, (unsigned)_isr0, 0x08, 0x8E); idt_set_gate(1, (unsigned)_isr1, 0x08, 0x8E); idt_set_gate(2, (unsigned)_isr2, 0x08, 0x8E); idt_set_gate(3, (unsigned)_isr3, 0x08, 0x8E); idt_set_gate(4, (unsigned)_isr4, 0x08, 0x8E); idt_set_gate(5, (unsigned)_isr5, 0x08, 0x8E); idt_set_gate(6, (unsigned)_isr6, 0x08, 0x8E); idt_set_gate(7, (unsigned)_isr7, 0x08, 0x8E); idt_set_gate(8, (unsigned)_isr8, 0x08, 0x8E); idt_set_gate(9, (unsigned)_isr9, 0x08, 0x8E); idt_set_gate(10, (unsigned)_isr10, 0x08, 0x8E); idt_set_gate(11, (unsigned)_isr11, 0x08, 0x8E); idt_set_gate(12, (unsigned)_isr12, 0x08, 0x8E); idt_set_gate(13, (unsigned)_isr13, 0x08, 0x8E); idt_set_gate(14, (unsigned)_isr14, 0x08, 0x8E); idt_set_gate(15, (unsigned)_isr15, 0x08, 0x8E); idt_set_gate(16, (unsigned)_isr16, 0x08, 0x8E); idt_set_gate(17, (unsigned)_isr17, 0x08, 0x8E); idt_set_gate(18, (unsigned)_isr18, 0x08, 0x8E); idt_set_gate(19, (unsigned)_isr19, 0x08, 0x8E); idt_set_gate(20, (unsigned)_isr20, 0x08, 0x8E); idt_set_gate(21, (unsigned)_isr21, 0x08, 0x8E); idt_set_gate(22, (unsigned)_isr22, 0x08, 0x8E); idt_set_gate(23, (unsigned)_isr23, 0x08, 0x8E); idt_set_gate(24, (unsigned)_isr24, 0x08, 0x8E); idt_set_gate(25, (unsigned)_isr25, 0x08, 0x8E); idt_set_gate(26, (unsigned)_isr26, 0x08, 0x8E); idt_set_gate(27, (unsigned)_isr27, 0x08, 0x8E); idt_set_gate(28, (unsigned)_isr28, 0x08, 0x8E); idt_set_gate(29, (unsigned)_isr29, 0x08, 0x8E); idt_set_gate(30, (unsigned)_isr30, 0x08, 0x8E); idt_set_gate(31, (unsigned)_isr31, 0x08, 0x8E); }
// Scrolls one line down void scroll() { for (int i = 0; i < TERM_ROWS * 80; i++) { uint16_t* base = (uint16_t*)0xB8000; base += i; uint16_t* nchar = base + 80; *base = *nchar; } for (int i = 0 ; i < 80; i++) kprintc(' ', 0x07, i, 24); row = 24; }
/* We first remap the interrupt controllers, and then we install * the appropriate ISRs to the correct entries in the IDT. This * is just like installing the exception handlers */ void irq_install() { kprintc(":: Installing ", BLACK, LIGHT_RED); kprintc("IRQs\n", BLACK, LIGHT_CYAN); irq_remap(); idt_set_gate(32, (unsigned)_irq0, 0x08, 0x8E); idt_set_gate(33, (unsigned)_irq1, 0x08, 0x8E); idt_set_gate(34, (unsigned)_irq2, 0x08, 0x8E); idt_set_gate(35, (unsigned)_irq3, 0x08, 0x8E); idt_set_gate(36, (unsigned)_irq4, 0x08, 0x8E); idt_set_gate(37, (unsigned)_irq5, 0x08, 0x8E); idt_set_gate(38, (unsigned)_irq6, 0x08, 0x8E); idt_set_gate(39, (unsigned)_irq7, 0x08, 0x8E); idt_set_gate(40, (unsigned)_irq8, 0x08, 0x8E); idt_set_gate(41, (unsigned)_irq9, 0x08, 0x8E); idt_set_gate(42, (unsigned)_irq10, 0x08, 0x8E); idt_set_gate(43, (unsigned)_irq11, 0x08, 0x8E); idt_set_gate(44, (unsigned)_irq12, 0x08, 0x8E); idt_set_gate(45, (unsigned)_irq13, 0x08, 0x8E); idt_set_gate(46, (unsigned)_irq14, 0x08, 0x8E); idt_set_gate(47, (unsigned)_irq15, 0x08, 0x8E); }
void mmngr_init(uint32_t lomem, uint32_t himem) { kprintc("mem: ", 0x0A); kprintf("Initialising Memory Manager with %dkb of Memory\n", himem); //How much memory is actually available memavail = himem - KERNEND; uint32_t head_addr = &head; //Put the head block on a 4kb boundary, after the end of the kernel! head = ((uint32_t)KERNEND & 0xFFFFF000) + 0x1000; //How many blocks do we have available?? blocks_avail = himem / BLOCK_SIZE; kprintc("mem: ", 0x0A); kprintf("We have %d blocks of memory available\n", blocks_avail); head->prev = (block_t*)NULL; //We can't go before the head... head->next = (block_t*)NULL; //This should be NULL on boot head->size = BLOCK_SIZE; //One 4kb block head->flags = 0x03; //Used, RESERVED block! }
void gdt_init() { kprintc("kern: ", 0x0D); kprint("Initialising GDT...\n"); gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (uint32_t)&gdt_entries; gdt_create_desc(0, 0, 0, 0, 0); //Our NULL descriptor gdt_create_desc(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_create_desc(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_create_desc(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); gdt_create_desc(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); gdt_flush((uint32_t)&gdt_ptr); }
void sys_write(char c) { kprintc(current->tty_user, c); }