Kernel: add timer, paging, irqs but that not works well
This commit is contained in:
parent
791679dcd0
commit
094213a1e5
|
@ -82,6 +82,17 @@ isr\num:
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
.endm
|
.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 0 // Divide by sero
|
||||||
ISR_NOERRCODE 1 // Debug
|
ISR_NOERRCODE 1 // Debug
|
||||||
ISR_NOERRCODE 2 // Non-maskable Interrupt
|
ISR_NOERRCODE 2 // Non-maskable Interrupt
|
||||||
|
@ -114,27 +125,69 @@ ISR_NOERRCODE 28
|
||||||
ISR_NOERRCODE 29
|
ISR_NOERRCODE 29
|
||||||
ISR_ERRCODE 30
|
ISR_ERRCODE 30
|
||||||
ISR_NOERRCODE 31
|
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:
|
isr_common_stub:
|
||||||
pusha
|
pusha
|
||||||
mov %ds,%ax
|
mov %ds,%ax
|
||||||
push %eax
|
push %eax
|
||||||
mov $0x10,%ax
|
mov $0x10,%ax
|
||||||
mov %eax,%ds
|
mov %ax,%ds
|
||||||
mov %eax,%es
|
mov %ax,%es
|
||||||
mov %eax,%fs
|
mov %ax,%fs
|
||||||
mov %eax,%gs
|
mov %ax,%gs
|
||||||
|
|
||||||
call isr_handler
|
call isr_handler
|
||||||
|
|
||||||
pop %eax
|
pop %eax
|
||||||
mov %eax,%ds
|
mov %ax,%ds
|
||||||
mov %eax,%es
|
mov %ax,%es
|
||||||
mov %eax,%fs
|
mov %ax,%fs
|
||||||
mov %eax,%gs
|
mov %ax,%gs
|
||||||
popa
|
popa
|
||||||
add $0x8,%esp
|
add $0x8,%esp
|
||||||
sti
|
sti
|
||||||
iret
|
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
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "gdt.c"
|
#include "gdt.c"
|
||||||
#include "interrupts.c"
|
#include "interrupts.c"
|
||||||
|
#include "timer.c"
|
||||||
|
#include "paging.h"
|
||||||
|
|
||||||
void kernel_early_main(void) {
|
void kernel_early_main(void) {
|
||||||
gdt_init();
|
gdt_init();
|
||||||
|
@ -11,7 +14,9 @@ void kernel_early_main(void) {
|
||||||
serial_printf("gdt initialized!\n");
|
serial_printf("gdt initialized!\n");
|
||||||
idt_init();
|
idt_init();
|
||||||
serial_printf("idt initialized!\n");
|
serial_printf("idt initialized!\n");
|
||||||
//asm volatile("int $0x3");
|
init_timer(50); // Initialise timer to 50Hz
|
||||||
//asm volatile("int $0x4");
|
serial_printf("timer initialized!\n");
|
||||||
|
init_paging();
|
||||||
|
serial_printf("paging initialized!\n");
|
||||||
terminal_initialize();
|
terminal_initialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ typedef struct gdt_ptr_struct gdt_ptr_t;
|
||||||
gdt_entry_t gdt_entries[5];
|
gdt_entry_t gdt_entries[5];
|
||||||
gdt_ptr_t gdt_ptr;
|
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)
|
static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
struct idt_entry_struct
|
||||||
{
|
{
|
||||||
uint16_t base_lo; // The lower 16 bits of the ISR's address
|
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(void);
|
||||||
void idt_init() {
|
void idt_init() {
|
||||||
idt_ptr.base = (uintptr_t)&idt_entries;
|
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
|
||||||
idt_ptr.limit = (uint16_t)sizeof(idt_entry_t) * 256 - 1;
|
idt_ptr.base = (uint32_t)&idt_entries;
|
||||||
|
|
||||||
memset(&idt_entries, 0, sizeof(idt_entry_t)*256);
|
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)isr0, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr1, 0x08, 0x8E);
|
idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr2, 0x08, 0x8E);
|
idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr3, 0x08, 0x8E);
|
idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr4, 0x08, 0x8E);
|
idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr5, 0x08, 0x8E);
|
idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr6, 0x08, 0x8E);
|
idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr7, 0x08, 0x8E);
|
idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr8, 0x08, 0x8E);
|
idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr9, 0x08, 0x8E);
|
idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr10, 0x08, 0x8E);
|
idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr11, 0x08, 0x8E);
|
idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr12, 0x08, 0x8E);
|
idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr13, 0x08, 0x8E);
|
idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr14, 0x08, 0x8E);
|
idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr15, 0x08, 0x8E);
|
idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr16, 0x08, 0x8E);
|
idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr17, 0x08, 0x8E);
|
idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr18, 0x08, 0x8E);
|
idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr19, 0x08, 0x8E);
|
idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr20, 0x08, 0x8E);
|
idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr21, 0x08, 0x8E);
|
idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr22, 0x08, 0x8E);
|
idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr23, 0x08, 0x8E);
|
idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr24, 0x08, 0x8E);
|
idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr25, 0x08, 0x8E);
|
idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr26, 0x08, 0x8E);
|
idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr27, 0x08, 0x8E);
|
idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr28, 0x08, 0x8E);
|
idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr29, 0x08, 0x8E);
|
idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr30, 0x08, 0x8E);
|
idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
|
||||||
idt_set_gate(0, (uint32_t)isr31, 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);
|
||||||
|
|
||||||
|
extern void idt_flush(uint32_t);
|
||||||
//__asm__ volatile ("lidt %0" : : "memory"(idt_ptr)); // load the new IDT
|
|
||||||
//__asm__ volatile ("sti"); // set the interrupt flag
|
|
||||||
|
|
||||||
extern void idt_flush(uint32);
|
|
||||||
idt_flush((uint32_t)&idt_ptr);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void kernel_main(void) {
|
void kernel_main(void) {
|
||||||
printf("Hello from OrionOS!\n");
|
printf("Hello from OrionOS!\n");
|
||||||
|
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue