Kernel: add timer, paging, irqs but that not works well

This commit is contained in:
g1n 2021-08-12 14:07:07 +03:00
parent 791679dcd0
commit 094213a1e5
7 changed files with 558 additions and 86 deletions

View File

@ -82,6 +82,17 @@ isr\num:
jmp isr_common_stub
.endm
// This macro creates a stub for an IRQ - the first parameter is
// the IRQ number, the second is the ISR number it is remapped to.
.macro IRQ num to
.global irq\num
irq\num:
cli
push $0x0
push $0x\to
jmp irq_common_stub
.endm
ISR_NOERRCODE 0 // Divide by sero
ISR_NOERRCODE 1 // Debug
ISR_NOERRCODE 2 // Non-maskable Interrupt
@ -114,27 +125,69 @@ ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_ERRCODE 30
ISR_NOERRCODE 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
isr_common_stub:
pusha
mov %ds,%ax
push %eax
mov $0x10,%ax
mov %eax,%ds
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
call isr_handler
pop %eax
mov %eax,%ds
mov %eax,%es
mov %eax,%fs
mov %eax,%gs
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
popa
add $0x8,%esp
sti
iret
//This is our common IRQ stub. It saves the processor state, sets
//up for kernel mode segments, calls the C-level fault handler,
//and finally restores the stack frame.
irq_common_stub:
pusha //Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov %ds, %ax //Lower 16-bits of eax = ds.
push %eax //save the data segment descriptor
mov $0x10, %ax //load the kernel data segment descriptor
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
call irq_handler
pop %ebx //reload the original data segment descriptor
mov %bx, %ds
mov %bx, %es
mov %bx, %fs
mov %bx, %gs
popa //Pops edi,esi,ebp...
add $0x8, %esp //Cleans up the pushed error code and pushed ISR number
sti
iret

View File

@ -1,9 +1,12 @@
#include <stdint.h>
#include <kernel/tty.h>
#include <stdio.h>
#include "serial.h"
#include "gdt.c"
#include "interrupts.c"
#include "timer.c"
#include "paging.h"
void kernel_early_main(void) {
gdt_init();
@ -11,7 +14,9 @@ void kernel_early_main(void) {
serial_printf("gdt initialized!\n");
idt_init();
serial_printf("idt initialized!\n");
//asm volatile("int $0x3");
//asm volatile("int $0x4");
init_timer(50); // Initialise timer to 50Hz
serial_printf("timer initialized!\n");
init_paging();
serial_printf("paging initialized!\n");
terminal_initialize();
}

View File

@ -20,7 +20,7 @@ typedef struct gdt_ptr_struct gdt_ptr_t;
gdt_entry_t gdt_entries[5];
gdt_ptr_t gdt_ptr;
extern void gdt_flush(struct gdt_ptr* gdt_ptr_addr);
extern void gdt_flush(uint32_t);
static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
{

View File

@ -1,3 +1,22 @@
#define IRQ0 32
#define IRQ1 33
#define IRQ2 34
#define IRQ3 35
#define IRQ4 36
#define IRQ5 37
#define IRQ6 38
#define IRQ7 39
#define IRQ8 40
#define IRQ9 41
#define IRQ10 42
#define IRQ11 43
#define IRQ12 44
#define IRQ13 45
#define IRQ14 46
#define IRQ15 47
//#include "asm_helper.h"
struct idt_entry_struct
{
uint16_t base_lo; // The lower 16 bits of the ISR's address
@ -29,88 +48,170 @@ void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
void idt_init(void);
void idt_init() {
idt_ptr.base = (uintptr_t)&idt_entries;
idt_ptr.limit = (uint16_t)sizeof(idt_entry_t) * 256 - 1;
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
idt_ptr.base = (uint32_t)&idt_entries;
memset(&idt_entries, 0, sizeof(idt_entry_t)*256);
extern isr0;
extern isr1;
extern isr2;
extern isr3;
extern isr4;
extern isr5;
extern isr6;
extern isr7;
extern isr8;
extern isr9;
extern isr10;
extern isr11;
extern isr12;
extern isr13;
extern isr14;
extern isr15;
extern isr16;
extern isr17;
extern isr18;
extern isr19;
extern isr20;
extern isr21;
extern isr22;
extern isr23;
extern isr24;
extern isr25;
extern isr26;
extern isr27;
extern isr28;
extern isr29;
extern isr30;
extern isr31;
// Remap the irq table.
outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
extern int isr0;
extern int isr1;
extern int isr2;
extern int isr3;
extern int isr4;
extern int isr5;
extern int isr6;
extern int isr7;
extern int isr8;
extern int isr9;
extern int isr10;
extern int isr11;
extern int isr12;
extern int isr13;
extern int isr14;
extern int isr15;
extern int isr16;
extern int isr17;
extern int isr18;
extern int isr19;
extern int isr20;
extern int isr21;
extern int isr22;
extern int isr23;
extern int isr24;
extern int isr25;
extern int isr26;
extern int isr27;
extern int isr28;
extern int isr29;
extern int isr30;
extern int isr31;
extern int irq0;
extern int irq1;
extern int irq2;
extern int irq3;
extern int irq4;
extern int irq5;
extern int irq6;
extern int irq7;
extern int irq8;
extern int irq9;
extern int irq10;
extern int irq11;
extern int irq12;
extern int irq13;
extern int irq14;
extern int irq15;
idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr1, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr2, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr3, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr4, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr5, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr6, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr7, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr8, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr9, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr10, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr11, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr12, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr13, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr14, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr15, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr16, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr17, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr18, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr19, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr20, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr21, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr22, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr23, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr24, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr25, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr26, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr27, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr28, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr29, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr30, 0x08, 0x8E);
idt_set_gate(0, (uint32_t)isr31, 0x08, 0x8E);
idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E);
idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E);
idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E);
idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E);
idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E);
idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E);
idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E);
idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E);
idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);
idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E);
idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E);
idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E);
idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E);
idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E);
idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E);
idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E);
idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E);
idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E);
idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E);
idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E);
idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E);
idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E);
idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E);
idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E);
idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E);
//__asm__ volatile ("lidt %0" : : "memory"(idt_ptr)); // load the new IDT
//__asm__ volatile ("sti"); // set the interrupt flag
extern void idt_flush(uint32);
extern void idt_flush(uint32_t);
idt_flush((uint32_t)&idt_ptr);
}
void isr_handler()
typedef struct registers
{
serial_printf("Received interrupt\n");
uint32_t ds; // Data segment selector
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
} registers_t;
typedef void (*isr_t)(registers_t);
isr_t interrupt_handlers[256];
void isr_handler(registers_t regs)
{
printf("Received Interrupr\n");
serial_printf("Received interrupt: %s\n", regs.int_no);
if (interrupt_handlers[regs.int_no] != 0)
{
isr_t handler = interrupt_handlers[regs.int_no];
handler(regs);
}
}
void irq_handler(registers_t regs)
{
// Send an EOI (end of interrupt) signal to the PICs.
// If this interrupt involved the slave.
if (regs.int_no >= 40)
{
// Send reset signal to slave.
outb(0xA0, 0x20);
}
// Send reset signal to master. (As well as slave, if necessary).
outb(0x20, 0x20);
if (interrupt_handlers[regs.int_no] != 0)
{
isr_t handler = interrupt_handlers[regs.int_no];
handler(regs);
}
}
void register_interrupt_handler(uint8_t n, isr_t handler)
{
interrupt_handlers[n] = handler;
}

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <stdint.h>
void kernel_main(void) {
printf("Hello from OrionOS!\n");

285
kernel/kernel/paging.h Normal file
View File

@ -0,0 +1,285 @@
#ifndef PAGING_H
#define PAGING_H
// A bitset of frames - used or free.
uint32_t *frames;
uint32_t nframes;
/*extern */uint32_t placement_address;
// Macros used in the bitset algorithms.
#define INDEX_FROM_BIT(a) (a/(8*4))
#define OFFSET_FROM_BIT(a) (a%(8*4))
typedef struct page
{
uint32_t present : 1; // Page present in memory
uint32_t rw : 1; // Read-only if clear, readwrite if set
uint32_t user : 1; // Supervisor level only if clear
uint32_t accessed : 1; // Has the page been accessed since last refresh?
uint32_t dirty : 1; // Has the page been written to since last refresh?
uint32_t unused : 7; // Amalgamation of unused and reserved bits
uint32_t frame : 20; // Frame address (shifted right 12 bits)
} page_t;
typedef struct page_table
{
page_t pages[1024];
} page_table_t;
typedef struct page_directory
{
/*
Array of pointers to pagetables.
*/
page_table_t *tables[1024];
/*
Array of pointers to the pagetables above, but gives their *physical*
location, for loading into the CR3 register.
*/
uint32_t tablesPhysical[1024];
/*
The physical address of tablesPhysical.
*/
uint32_t physicalAddr;
} page_directory_t;
uint32_t kmalloc(uint32_t sz)
{
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
uint32_t kmalloc_a(uint32_t sz)
{
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
/*
uint32_t kmalloc_a(uint32_t sz, int align)
{
if (align == 1 && (placement_address & 0xFFFFF000)) // If the address is not already page-aligned
{
// Align it.
placement_address &= 0xFFFFF000;
placement_address += 0x1000;
}
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
*/
uint32_t kmalloc_ap(uint32_t sz, int align, uint32_t *phys)
{
if (align == 1 && (placement_address & 0xFFFFF000)) // If the address is not already page-aligned
{
// Align it.
placement_address &= 0xFFFFF000;
placement_address += 0x1000;
}
if (phys)
{
*phys = placement_address;
}
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
//uint32_t kmalloc_a(uint32_t sz); // page aligned.
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); // returns a physical address.
//uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); // page aligned and returns a physical address.
//uint32_t kmalloc(uint32_t sz); // vanilla (normal).
/*
Handler for page faults.
*/
void page_fault(registers_t regs){
// A page fault has occurred.
// The faulting address is stored in the CR2 register.
uint32_t faulting_address;
asm volatile("mov %%cr2, %0" : "=r" (faulting_address));
// The error code gives us details of what happened.
int present = !(regs.err_code & 0x1); // Page not present
int rw = regs.err_code & 0x2; // Write operation?
int us = regs.err_code & 0x4; // Processor was in user-mode?
int reserved = regs.err_code & 0x8; // Overwritten CPU-reserved bits of page entry?
int id = regs.err_code & 0x10; // Caused by an instruction fetch?
// Output an error message.
printf("Page fault: ( ");
if (present) {printf("present ");}
if (rw) {printf("read-only ");}
if (us) {printf("user-mode ");}
if (reserved) {printf("reserved ");}
printf(") at 0x%s\n", faulting_address);
panic("PAGE FAULT");
}
/*
Retrieves a pointer to the page required.
If make == 1, if the page-table in which this page should
reside isn't created, create it!
*/
page_t *get_page(uint32_t address, int make, page_directory_t *dir){
// Turn the address into an index.
address /= 0x1000;
// Find the page table containing this address.
uint32_t table_idx = address / 1024;
if (dir->tables[table_idx]) // If this table is already assigned
{
return &dir->tables[table_idx]->pages[address%1024];
}
else if(make)
{
uint32_t tmp;
dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), 1, &tmp);
memset(dir->tables[table_idx], 0, 0x1000);
dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
return &dir->tables[table_idx]->pages[address%1024];
}
else
{
return 0;
}
}
void init_paging() {
// The size of physical memory. For the moment we
// assume it is 16MB big.
uint32_t mem_end_page = 0x1000000;
nframes = mem_end_page / 0x1000;
frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes));
memset(frames, 0, INDEX_FROM_BIT(nframes));
// Let's make a page directory.
void* kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
void* current_directory = kernel_directory;
// We need to identity map (phys addr = virt addr) from
// 0x0 to the end of used memory, so we can access this
// transparently, as if paging wasn't enabled.
// NOTE that we use a while loop here deliberately.
// inside the loop body we actually change placement_address
// by calling kmalloc(). A while loop causes this to be
// computed on-the-fly rather than once at the start.
int i = 0;
while (i < placement_address)
{
// Kernel code is readable but not writeable from userspace.
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += 0x1000;
}
// Before we enable paging, we must register our page fault handler.
register_interrupt_handler(14, page_fault);
// Now, enable paging!
switch_page_directory(kernel_directory);
}
/*
Causes the specified page directory to be loaded into the
CR3 register.
*/
void switch_page_directory(page_directory_t *dir) {
void* current_directory = dir;
asm volatile("mov %0, %%eax":: "r"(&dir->tablesPhysical));
asm("mov %eax, %cr3;");
asm("mov %cr0, %eax;");
asm("or 0x80000000, %eax;");
asm("mov %eax, %cr0;");
}
// Static function to set a bit in the frames bitset
static void set_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
frames[idx] |= (0x1 << off);
}
// Static function to clear a bit in the frames bitset
static void clear_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
frames[idx] &= ~(0x1 << off);
}
// Static function to test if a bit is set.
static uint32_t test_frame(uint32_t frame_addr)
{
uint32_t frame = frame_addr/0x1000;
uint32_t idx = INDEX_FROM_BIT(frame);
uint32_t off = OFFSET_FROM_BIT(frame);
return (frames[idx] & (0x1 << off));
}
// Static function to find the first free frame.
static uint32_t first_frame()
{
uint32_t i, j;
for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
{
if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
{
// at least one bit is free here.
for (j = 0; j < 32; j++)
{
uint32_t toTest = 0x1 << j;
if ( !(frames[i]&toTest) )
{
return i*4*8+j;
}
}
}
}
}
// Function to allocate a frame.
void alloc_frame(page_t *page, int is_kernel, int is_writeable)
{
if (page->frame != 0)
{
return; // Frame was already allocated, return straight away.
}
else
{
uint32_t idx = first_frame(); // idx is now the index of the first free frame.
if (idx == (uint32_t)-1)
{
panic("No free frames!");
}
set_frame(idx*0x1000); // this frame is now ours!
page->present = 1; // Mark it as present.
page->rw = (is_writeable)?1:0; // Should the page be writeable?
page->user = (is_kernel)?0:1; // Should the page be user-mode?
page->frame = idx;
}
}
// Function to deallocate a frame.
void free_frame(page_t *page)
{
uint32_t frame;
if (!(frame=page->frame))
{
return; // The given page didn't actually have an allocated frame!
}
else
{
clear_frame(frame); // Frame is now free again.
page->frame = 0x0; // Page now doesn't have a frame.
}
}
#endif

27
kernel/kernel/timer.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
//#include "asm_helper.h"
//#include "interrupts.c"
uint32_t tick = 0;
static void timer_callback(registers_t regs)
{
tick++;
printf("Tick: %s\n", tick);
serial_printf("Tick: %s\n", tick);
}
void init_timer(uint32_t frequency)
{
register_interrupt_handler(IRQ0, &timer_callback);
uint32_t divisor = 1193180 / frequency;
outb(0x43, 0x36);
uint8_t l = (uint8_t)(divisor & 0xFF);
uint8_t h = (uint8_t)( (divisor>>8) & 0xFF );
outb(0x40, l);
outb(0x40, h);
}