Add kernel documentation
This commit is contained in:
parent
794dd702b0
commit
ee7ce4dabe
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ sysroot/boot/initrd.tar
|
||||
serout
|
||||
vga_drv/vga_drv
|
||||
.vagrant
|
||||
.vscode
|
||||
.vscode
|
||||
kerneldoc
|
||||
|
2582
Doxyfile.bak
Normal file
2582
Doxyfile.bak
Normal file
File diff suppressed because it is too large
Load Diff
4
Makefile
4
Makefile
@ -1,5 +1,6 @@
|
||||
PLAT=i386
|
||||
C_SOURCES = $(wildcard kernel/*.c kernel/cpu/$(PLAT)/*.c kernel/cpu/*.c)
|
||||
C_HEADERS = $(wildcard kernel/*.h kernel/cpu/$(PLAT)/*.h kernel/cpu/*.h)
|
||||
ASM = $(wildcard kernel/cpu/$(PLAT)/*.asm)
|
||||
S_ASM = $(wildcard kernel/cpu/$(PLAT)/*.s)
|
||||
LIBC_SOURCES = $(wildcard libc/*.c libc/*/*.c)
|
||||
@ -86,3 +87,6 @@ kernel/cpu/isr.h: kernel/cpu/$(PLAT)/isr.h
|
||||
|
||||
clean:
|
||||
@rm -rf initrd/* kernel/*.o drivers/*/*.o drivers/*/*/*.o cpu/*/*.o fs/*.o libc/libc.a kernel/cstart.o cpu/memory.h os.iso */*.elf sysroot/boot/initrd.tar
|
||||
|
||||
doc: $(C_SOURCES) $(C_HEADERS)
|
||||
@doxygen > /dev/null
|
||||
|
@ -1,6 +1,25 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef ADDRESS_SPACES_H
|
||||
#define ADDRESS_SPACES_H
|
||||
|
||||
/**
|
||||
* Copy data into an address space at a specified virtual address
|
||||
* \param cr3 The adress space to copy data to.
|
||||
* \param data The data to copy
|
||||
* \param size The size of the data
|
||||
* \param virt_addr The address to copy the data to in the address space
|
||||
*/
|
||||
void address_spaces_copy_data(void* cr3, void* data,uint32_t size,void* virt_addr);
|
||||
|
||||
/**
|
||||
* Put data into an address space at an unknown virtual address
|
||||
* \param cr3 The adress space to copy data to.
|
||||
* \param data The data to copy
|
||||
* \param size The size of the data
|
||||
* \return The address that the data was copied to.
|
||||
*/
|
||||
void* address_spaces_put_data(void* cr3, void* data,uint32_t size);
|
||||
#endif
|
||||
|
@ -1,6 +1,13 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef CPU_INIT_H
|
||||
#define CPU_INIT_H
|
||||
|
||||
/**
|
||||
* Initialize any architecture-specific CPU things.
|
||||
*/
|
||||
void cpu_init();
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,13 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef HALT_H
|
||||
#define HALT_H
|
||||
|
||||
/**
|
||||
* Clear interrupts and halt the CPU,
|
||||
*/
|
||||
void halt() __attribute__((noreturn));
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "gdt.h"
|
||||
|
||||
void cpu_init() {
|
||||
|
@ -1,63 +1,95 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NUM_ENTRIES 6
|
||||
|
||||
extern uint32_t int_stack_top;
|
||||
#define NUM_ENTRIES 6 //!< Number of entries in the GDT
|
||||
|
||||
extern uint32_t int_stack_top; //!< Initial kernel stack before the kernel's first yield
|
||||
/**
|
||||
* Represents an entry in the GDT.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t limit_low16;
|
||||
uint16_t base_low16;
|
||||
uint8_t base_mid8;
|
||||
uint8_t access;
|
||||
uint8_t limit_flags;
|
||||
uint8_t base_high8;
|
||||
uint16_t limit_low16;//!< Low 16 bits of the limit
|
||||
uint16_t base_low16; //!< Low 16 bits of the base
|
||||
uint8_t base_mid8; //!< Middle 8 bits of the base
|
||||
uint8_t access; /**<
|
||||
Access byte. Gives info about the descriptor. <br>
|
||||
Format: <br>
|
||||
Bit 7: Present. Must be 1 for all valid selectors. <br>
|
||||
Bits 6-5. Privilege. Contains the ring level for the selector. 0 for kernel mode, 3 for user mode. <br>
|
||||
Bit 4. Descriptor type. Must be set for code/data segments and cleared for system segments like the TSS. <br>
|
||||
Bit 3. Executable. If this bit is set, it is a code selector, otherwise a data selector. <br>
|
||||
Bit 2. Direction/Conforming. Too complex to explain, should be set to 0. <br>
|
||||
Bit 1. Readable/Writable. For code sels, this bit sets whther you can use it like a read-only data segment. For data sels, it sets whether the selector is writable. <br>
|
||||
Bit 0. Acessed bit. Set to 0. <br>
|
||||
*/
|
||||
uint8_t limit_flags; /**<
|
||||
High nibble of this contains two flags, and the lower niblle contains the high 4 bits of the limit. <br>
|
||||
The flags are: <br>
|
||||
Bit 3. Granularity. 0 for byte granularity, 1 for 4 KB granularity. <br>
|
||||
Bit 2. Size. 0 for 16 bit protected mode, 1 for 32 bit protected mode. <br>
|
||||
Bits 1-0. Unused. Set to 0. <br>
|
||||
*/
|
||||
uint8_t base_high8; //!< High 8 bits of the base
|
||||
} __attribute__((packed)) gdt_entry;
|
||||
|
||||
/**
|
||||
* Pointed to by the GDTR to tell the processor the GDT's size and address.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t size;
|
||||
gdt_entry* address;
|
||||
uint16_t size; //!< Size of the GDT.
|
||||
gdt_entry* address; //!< Address of the GDT.
|
||||
} __attribute__((packed)) gdt_description;
|
||||
|
||||
/**
|
||||
* Represents a TSS.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
|
||||
uint32_t esp0; // The stack pointer to load when we change to kernel mode.
|
||||
uint32_t ss0; // The stack segment to load when we change to kernel mode.
|
||||
uint32_t esp1; // Unused...
|
||||
uint32_t ss1;
|
||||
uint32_t esp2;
|
||||
uint32_t ss2;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t es; // The value to load into ES when we change to kernel mode.
|
||||
uint32_t cs; // The value to load into CS when we change to kernel mode.
|
||||
uint32_t ss; // The value to load into SS when we change to kernel mode.
|
||||
uint32_t ds; // The value to load into DS when we change to kernel mode.
|
||||
uint32_t fs; // The value to load into FS when we change to kernel mode.
|
||||
uint32_t gs; // The value to load into GS when we change to kernel mode.
|
||||
uint32_t ldt; // Unused...
|
||||
uint16_t trap;
|
||||
uint16_t iomap_base;
|
||||
char iopb[8192]; // IO port bitmap
|
||||
uint8_t set_ff;
|
||||
uint32_t prev_tss; //!< The previous TSS - if we used hardware task switching this would form a linked list.
|
||||
uint32_t esp0; //!< The stack pointer to load when we change to kernel mode.
|
||||
uint32_t ss0; //!< The stack segment to load when we change to kernel mode.
|
||||
uint32_t esp1; //!< Unused
|
||||
uint32_t ss1; //!< Unused
|
||||
uint32_t ss2; //!< Unused
|
||||
uint32_t esp2; //!< Unused
|
||||
uint32_t cr3; //!< Unused
|
||||
uint32_t eip; //!< Unused
|
||||
uint32_t eflags; //!< Unused
|
||||
uint32_t eax; //!< Unused
|
||||
uint32_t ecx; //!< Unused
|
||||
uint32_t edx; //!< Unused
|
||||
uint32_t ebx; //!< Unused
|
||||
uint32_t esp; //!< Unused
|
||||
uint32_t ebp; //!< Unused
|
||||
uint32_t esi; //!< Unused
|
||||
uint32_t edi; //!< Unused
|
||||
uint32_t es; //!< The value to load into ES when we change to kernel mode.
|
||||
uint32_t cs; //!< The value to load into CS when we change to kernel mode.
|
||||
uint32_t ss; //!< The value to load into SS when we change to kernel mode.
|
||||
uint32_t ds; //!< The value to load into DS when we change to kernel mode.
|
||||
uint32_t fs; //!< The value to load into FS when we change to kernel mode.
|
||||
uint32_t gs; //!< The value to load into GS when we change to kernel mode.
|
||||
uint32_t ldt; //!< Unused
|
||||
uint16_t trap; //!< Unused
|
||||
uint16_t iomap_base; //!< Offset of the IOPB in the TSS.
|
||||
char iopb[8192]; //!< IO port bitmap
|
||||
uint8_t set_ff; //!< Must be set to 0xFF to mark the end of the IOPB
|
||||
} __attribute__((packed)) tss_entry;
|
||||
|
||||
static gdt_entry gdt[NUM_ENTRIES];
|
||||
static gdt_description gdt_desc;
|
||||
tss_entry tss;
|
||||
static gdt_entry gdt[NUM_ENTRIES]; //!< The GDT
|
||||
static gdt_description gdt_desc; //!< The value to load into the GDTR
|
||||
tss_entry tss; //!< The TSS
|
||||
|
||||
void tss_stack_reset() {
|
||||
tss.esp0=int_stack_top+0xC0000000;
|
||||
}
|
||||
/**
|
||||
* Set a GDT entry.
|
||||
* \param i The GDT entry to set.
|
||||
* \param base The base of the GDT entry.
|
||||
* \param limit The limit of the GDT entry.
|
||||
* \param access The access byte of the GDT entry.
|
||||
*/
|
||||
|
||||
static void set_entry(int i,uint32_t base,uint32_t limit,uint8_t access) {
|
||||
gdt[i].limit_low16=limit&0xFFFF;
|
||||
@ -69,6 +101,13 @@ static void set_entry(int i,uint32_t base,uint32_t limit,uint8_t access) {
|
||||
gdt[i].base_high8=(base&0xFF000000)>>24;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a GDT entry.
|
||||
* \param num The GDT entry to set.
|
||||
* \param ss0 The kernel stack selector.
|
||||
* \param esp0 The kernel stack pointer.
|
||||
*/
|
||||
|
||||
static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0) {
|
||||
// Firstly, let's compute the base and limit of our entry into the GDT.
|
||||
uint32_t base = (uint32_t) &tss;
|
||||
@ -111,20 +150,18 @@ void allow_all_ports() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void block_all_ports() {
|
||||
for (int i=0;i<8192;i++) {
|
||||
tss.iopb[i]=0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gdt_init() {
|
||||
set_entry(0,0,0,0);
|
||||
set_entry(1,0,0xFFFFF,0x9A);
|
||||
set_entry(2,0,0xFFFFF,0x92);
|
||||
set_entry(3,0,0xFFFFF,0xFA);
|
||||
set_entry(4,0,0xFFFFF,0xF2);
|
||||
set_entry(1,0,0xFFFFF,0b10011010);
|
||||
set_entry(2,0,0xFFFFF,0b10010010);
|
||||
set_entry(3,0,0xFFFFF,0b11111010);
|
||||
set_entry(4,0,0xFFFFF,0b11110010);
|
||||
write_tss(5,0x10,int_stack_top+0xC0000000);
|
||||
gdt_desc.size=(sizeof(gdt_entry)*NUM_ENTRIES)-1;
|
||||
gdt_desc.address=gdt;
|
||||
|
@ -1,8 +1,26 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef GDT_H
|
||||
#define GDT_H
|
||||
|
||||
/**
|
||||
* Initializes the GDT & TSS.
|
||||
*/
|
||||
|
||||
void gdt_init();
|
||||
void tss_stack_reset();
|
||||
|
||||
/**
|
||||
* Allows all ports in the IOPB.
|
||||
*/
|
||||
|
||||
|
||||
void allow_all_ports();
|
||||
|
||||
/**
|
||||
* Blocks all ports in the IOPB.
|
||||
*/
|
||||
|
||||
void block_all_ports();
|
||||
#endif
|
||||
|
@ -1,51 +1,57 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "idt.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Segment selectors */
|
||||
#define KERNEL_CS 0x08
|
||||
#define KERNEL_CS 0x08 //!< Kernel code segemnt selector
|
||||
|
||||
/* How every interrupt gate (handler) is defined */
|
||||
/**
|
||||
* Defines an interrupt gate
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t low_offset; /* Lower 16 bits of handler function address */
|
||||
uint16_t sel; /* Kernel segment selector */
|
||||
uint8_t always0;
|
||||
/* First byte
|
||||
* Bit 7: "Interrupt is present"
|
||||
* Bits 6-5: Privilege level of caller (0=kernel..3=user)
|
||||
* Bit 4: Set to 0 for interrupt gates
|
||||
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
|
||||
uint8_t flags;
|
||||
uint16_t high_offset; /* Higher 16 bits of handler function address */
|
||||
} __attribute__((packed)) idt_gate_t ;
|
||||
uint16_t low_offset; //!< Lower 16 bits of handler function address
|
||||
uint16_t sel; //!< Kernel segment selector
|
||||
uint8_t always0; //!< Must be 0.
|
||||
uint8_t flags; /**<
|
||||
Flags byte. Gives info about the descriptor
|
||||
* Bit 7: Present. Must be 1 for all valid selectors.
|
||||
* Bits 6-5: Privilege. Contains the minimum ring level for the caller. 0 for kernel mode, 3 for user mode.
|
||||
* Bit 4: Set to 0 for interrupt gates.
|
||||
* Bits 3-0: 1110 = "32 bit interrupt gate".
|
||||
*/
|
||||
uint16_t high_offset; //!< Higher 16 bits of handler function address
|
||||
} __attribute__((packed)) idt_gate_t;
|
||||
|
||||
/* A pointer to the array of interrupt handlers.
|
||||
* Assembly instruction 'lidt' will read it */
|
||||
/**
|
||||
* Pointed to by the IDTR to tell the processor the IDT's size and address.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
uint16_t limit; //!< Size of the IDT.
|
||||
idt_gate_t* base; //!< Address of the IDT.
|
||||
} __attribute__((packed)) idt_register_t;
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
#define IDT_ENTRIES 256 //!< Number of entries in the IDT
|
||||
|
||||
static idt_gate_t idt[IDT_ENTRIES];
|
||||
static idt_register_t idt_reg;
|
||||
|
||||
#define low_16(address) (uint16_t)((address) & 0xFFFF)
|
||||
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
|
||||
static idt_gate_t idt[IDT_ENTRIES]; //!< The IDT
|
||||
static idt_register_t idt_reg; //!< The value to load into the IDTR
|
||||
|
||||
#define low_16(address) (uint16_t)((address) & 0xFFFF) //!< Macro to get the low 16 bits of an address
|
||||
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF) //!< Macro to get the high 16 bits of an address
|
||||
|
||||
|
||||
void idt_set_gate(int n,uint32_t handler) {
|
||||
idt[n].low_offset=low_16(handler);
|
||||
idt[n].sel=0x08;
|
||||
idt[n].always0=0;
|
||||
idt[n].flags=0xEE;
|
||||
idt[n].high_offset=high_16(handler);
|
||||
idt[n].low_offset=low_16(handler);
|
||||
idt[n].sel=0x08;
|
||||
idt[n].always0=0;
|
||||
idt[n].flags=0xEE;
|
||||
idt[n].high_offset=high_16(handler);
|
||||
}
|
||||
|
||||
void load_idt() {
|
||||
idt_reg.base=(uint32_t) &idt;
|
||||
idt_reg.limit=IDT_ENTRIES * sizeof(idt_gate_t) - 1;
|
||||
/* Don't make the mistake of loading &idt -- always load &idt_reg */
|
||||
asm volatile("lidtl (%0)":: "r" (&idt_reg));
|
||||
idt_reg.base=&idt[0];
|
||||
idt_reg.limit=IDT_ENTRIES * sizeof(idt_gate_t) - 1;
|
||||
/* Don't make the mistake of loading &idt -- always load &idt_reg */
|
||||
asm volatile("lidtl (%0)":: "r" (&idt_reg));
|
||||
}
|
||||
|
@ -1,10 +1,22 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Functions implemented in idt.c */
|
||||
/**
|
||||
* Sets an IDT gate.
|
||||
* \param n the IDT gate to set
|
||||
* \param handler the handler for the gate.
|
||||
*/
|
||||
void idt_set_gate(int n,uint32_t handler);
|
||||
/**
|
||||
* Loads the IDT
|
||||
*/
|
||||
void load_idt();
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
#include "../../kernel.h"
|
||||
#include "../../tasking.h"
|
||||
#include "../../vga_err.h"
|
||||
@ -8,6 +11,7 @@
|
||||
#include "../serial.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "isr.h"
|
||||
#include "interrupt.h"
|
||||
#include <cpu/ports.h>
|
||||
#include <stdint.h>
|
||||
@ -16,10 +20,8 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
void irq_handler(registers_t* r);
|
||||
static isr_t irq_handlers[16];
|
||||
static isr_t irq_handlers[16]; //!< Handlers for the PIC interrupts
|
||||
|
||||
/* Can't do this with a loop because we need the address
|
||||
* of the function names */
|
||||
void isr_install() {
|
||||
idt_set_gate(0,(uint32_t)isr0);
|
||||
idt_set_gate(1,(uint32_t)isr1);
|
||||
@ -90,8 +92,8 @@ void isr_install() {
|
||||
}
|
||||
|
||||
|
||||
/* To print the message which defines every exception */
|
||||
|
||||
//! List of messages for each exception
|
||||
__attribute__((unused)) static char *exception_messages[] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
@ -130,6 +132,11 @@ __attribute__((unused)) static char *exception_messages[] = {
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for non-PIC interrupts
|
||||
* \param r The saved state of the CPU
|
||||
*/
|
||||
void isr_handler(registers_t* r) {
|
||||
if (r->int_no!=80 && r->int_no!=14) {
|
||||
serial_write_string(exception_messages[r->int_no]);
|
||||
@ -276,6 +283,10 @@ void isr_register_handler(int n,isr_t handler) {
|
||||
irq_handlers[n] = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for PIC interrupts
|
||||
* \param r The saved state of the CPU
|
||||
*/
|
||||
void irq_handler(registers_t* r) {
|
||||
/* After every interrupt we need to send an EOI to the PICs
|
||||
* or they will not send another interrupt again */
|
||||
|
@ -1,19 +1,46 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Struct which aggregates many registers */
|
||||
/**
|
||||
* Saved state of the CPU when an interrupt occurs
|
||||
*/
|
||||
typedef struct {
|
||||
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 */
|
||||
uint32_t ds; //!< Data segment selector
|
||||
uint32_t edi; //!< Pushed by pusha.
|
||||
uint32_t esi; //!< Pushed by pusha.
|
||||
uint32_t ebp; //!< Pushed by pusha.
|
||||
uint32_t esp; //!< Pushed by pusha.
|
||||
uint32_t ebx; //!< Pushed by pusha.
|
||||
uint32_t edx; //!< Pushed by pusha.
|
||||
uint32_t ecx; //!< Pushed by pusha.
|
||||
uint32_t eax; //!< Pushed by pusha.
|
||||
uint32_t int_no; //!< Interrupt number
|
||||
uint32_t err_code; //!< Error code (if applicable)
|
||||
uint32_t eip; //!< Pushed by the processor automatically
|
||||
uint32_t cs; //!< Pushed by the processor automatically
|
||||
uint32_t eflags; //!< Pushed by the processor automatically
|
||||
uint32_t useresp; //!< Pushed by the processor automatically
|
||||
uint32_t ss; //!< Pushed by the processor automatically
|
||||
} registers_t;
|
||||
|
||||
typedef void (*isr_t)(registers_t*);
|
||||
typedef void (*isr_t)(registers_t*); //!< Type of an ISR handler function pointer
|
||||
|
||||
/**
|
||||
* Install the interrupt handlers into the IDT.
|
||||
*/
|
||||
void isr_install();
|
||||
|
||||
/**
|
||||
* Register an IRQ handler
|
||||
* \param n the IRQ to register a handler for
|
||||
* \param handler the handler to register
|
||||
*/
|
||||
void isr_register_handler(int n,isr_t handler);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "../../pmem.h"
|
||||
#include "../../vga_err.h"
|
||||
#include "../halt.h"
|
||||
@ -7,12 +11,34 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||
static uint32_t kern_page_tables[NUM_KERN_FRAMES] __attribute__((aligned(4096)));
|
||||
static uint32_t kstack_page_tables[218*1024] __attribute__((aligned(4096)));
|
||||
static uint32_t kmalloc_page_tables[4*1024] __attribute__((aligned(4096)));
|
||||
static uint32_t* pagdirmap=(uint32_t*)0xFFFFF000;
|
||||
static uint32_t* pagtblmap=(uint32_t*)0xFFC00000;
|
||||
/**
|
||||
* \page pg_struct_entry Format of a paging structure entry
|
||||
* The format of a page table/directiry entry is as following: <br>
|
||||
* Bits 31-11 is the physical frame number the entry points to. <br>
|
||||
* Bits 11-9 are availible for use by the OS. <br>
|
||||
* Bit 8 is ignored. <br>
|
||||
* Bit 7 is the page size in page directories, and must be 0 in page tables. If set to 1 in a page directory, it indicates 4MB pages. <br>
|
||||
* Bit 6 is the dirty bit in page tables, and must be 0 in page directories. In page tabes, it is set to 1 by the CPU when the page is written to. <br>
|
||||
* Bit 5 will be set to 1 by the CPU when the page is accessed. <br>
|
||||
* Bit 4 indicates whether the page has it's cache disabled. <br>
|
||||
* Bit 3 indictates whether write-through caching (when it is 1), or write-back caching, (when it is 0) is enabled. <br>
|
||||
* Bit 2 indictaes whether user mode code can access the page. <br>
|
||||
* Bit 1 indicates whether the page is writable. <br>
|
||||
* Bit 0 indicates whether the entry is present. If it is 0, the CU ignores the other 31 bits of the entry. <br>
|
||||
* Privlege bits in the entries are ANDed together, so the most restrictive privlege between the page directory and the page table wins.
|
||||
*/
|
||||
|
||||
static uint32_t page_directory[1024] __attribute__((aligned(4096))); //!< The kernel process's page directory
|
||||
static uint32_t kern_page_tables[NUM_KERN_FRAMES] __attribute__((aligned(4096))); //!< The page tables where the kernel binary is mapped in
|
||||
static uint32_t kstack_page_tables[218*1024] __attribute__((aligned(4096))); //!< Page tables for thread kernel stacks
|
||||
static uint32_t kmalloc_page_tables[4*1024] __attribute__((aligned(4096))); //!< Page tables for the kmalloc heap
|
||||
static uint32_t* pagdirmap=(uint32_t*)0xFFFFF000; //!< Pointer to the page directory entries in the recursive mapping
|
||||
static uint32_t* pagtblmap=(uint32_t*)0xFFC00000; //!< Pointer to the page table entries in the recursive mapping
|
||||
/**
|
||||
* Checks whether a page is present
|
||||
* \param page The page number to check
|
||||
* \return Whether the page is present
|
||||
*/
|
||||
static char is_page_present(size_t page) {
|
||||
int table=page>>10;
|
||||
page=page&0x3FF;
|
||||
@ -118,7 +144,11 @@ void alloc_pages_virt(int num_pages,void* addr) {
|
||||
map_pages(addr,phys_addr,num_pages,1,1);
|
||||
}
|
||||
|
||||
void invl_page(void* addr) {
|
||||
/**
|
||||
* Invalidates a page in the TLB,
|
||||
* \param addr The address of the page to invalidate.
|
||||
*/
|
||||
static void invl_page(void* addr) {
|
||||
asm volatile("invlpg (%0)"::"r"(addr):"memory");
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,26 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include <cpu/ports.h>
|
||||
|
||||
static char configured[]={0,0,0,0};
|
||||
static int data_ports[4]={0x3f8,0x2f8,0x3e8,0x2e8};
|
||||
static char configured[]={0,0,0,0}; //!< What serial ports have been detected and configured
|
||||
static int data_ports[4]={0x3f8,0x2f8,0x3e8,0x2e8}; //!< List of the data ports for all the potential serial ports
|
||||
|
||||
#define data_port(com) (data_ports[com])
|
||||
#define int_port(com) (data_port(com)+1)
|
||||
#define fifo_port(com) (data_port(com)+2)
|
||||
#define line_cmd_port(com) (data_port(com)+3)
|
||||
#define modem_cmd_port(com) (data_port(com)+4)
|
||||
#define line_stat_port(com) (data_port(com)+5)
|
||||
#define scratch_port(com) (data_port(com)+7)
|
||||
#define is_transmit_fifo_empty(com) (port_byte_in(line_stat_port(com))&0x20)
|
||||
#define data_port(com) (data_ports[com]) //!< Returns the data port of a serial port
|
||||
#define int_port(com) (data_port(com)+1) //!< Returns the interrupt config port of a serial port
|
||||
#define fifo_port(com) (data_port(com)+2) //!< Returns the fifo config port of a serial port
|
||||
#define line_cmd_port(com) (data_port(com)+3) //!< Returns the line cmd port of a serial port
|
||||
#define modem_cmd_port(com) (data_port(com)+4) //!< Returns the modem cmd port of a serial port
|
||||
#define line_stat_port(com) (data_port(com)+5) //!< Returns the line status port of a serial port
|
||||
#define scratch_port(com) (data_port(com)+7) //!< Returns the scratch port of a serial port
|
||||
#define is_transmit_fifo_empty(com) (port_byte_in(line_stat_port(com))&0x20) //!< Returns whether the trasmit FIFO is empty.
|
||||
|
||||
/**
|
||||
* Configure a serial port with a specified baud rate.
|
||||
* \param com The number of the serial port to configure
|
||||
* \param rate The baud rate to set the serial port to.
|
||||
*/
|
||||
static void configure(int com, int rate) {
|
||||
configured[com]=1;
|
||||
port_byte_out(line_cmd_port(com),0x80); // Enable DLAB
|
||||
|
@ -1,29 +1,46 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "../../tasking.h"
|
||||
#include "../paging.h"
|
||||
#include "../tasking_helpers.h"
|
||||
#include "../../pmem.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static void** kstacks=(void*)0xC8000000;
|
||||
static char kstack_bmap[(218*1024)/8]={0};
|
||||
static void** kstacks=(void*)0xC8000000; //!< Pointer to all the thread kernel stacks
|
||||
static char kstack_bmap[(218*1024)/8]={0}; //!< Bitmap of what kernel stacks have been allocated
|
||||
|
||||
static char get_bmap_bit(size_t index) {
|
||||
/**
|
||||
* Check whether a kernel stack is allocated
|
||||
* \param index The kernel stack to check
|
||||
* \return whether the kernel stack is allocated
|
||||
*/
|
||||
static char is_kstack_allocated(size_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
char entry=kstack_bmap[byte];
|
||||
return (entry&(1<<bit))>0;
|
||||
}
|
||||
|
||||
static void set_bmap_bit(size_t index) {
|
||||
/**
|
||||
* Mark that a kernel stack is allocated
|
||||
* \param index The kernel stack to mark
|
||||
*/
|
||||
static void mark_kstack_allocated(size_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
kstack_bmap[byte]=kstack_bmap[byte]|(1<<bit);
|
||||
}
|
||||
|
||||
int new_kstack() {
|
||||
/**
|
||||
* Allocate a kernel stack for a thread
|
||||
* \return The number of the new kernel stack, or -1 if none are unallocated.
|
||||
*/
|
||||
static int new_kstack() {
|
||||
int num=-1;
|
||||
for (int i=0;i<(218*1024);i++) {
|
||||
if (get_bmap_bit(i)==0) {
|
||||
if (is_kstack_allocated(i)==0) {
|
||||
num=i;
|
||||
break;
|
||||
}
|
||||
@ -31,7 +48,7 @@ int new_kstack() {
|
||||
if (num==-1) {
|
||||
return -1;
|
||||
}
|
||||
set_bmap_bit(num);
|
||||
mark_kstack_allocated(num);
|
||||
map_pages(((char*)kstacks+num*0x1000),pmem_alloc(1),1,1,1);
|
||||
return num;
|
||||
}
|
||||
|
@ -1,19 +1,46 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Struct which aggregates many registers */
|
||||
/**
|
||||
* Saved state of the CPU when an interrupt occurs
|
||||
*/
|
||||
typedef struct {
|
||||
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 */
|
||||
uint32_t ds; //!< Data segment selector
|
||||
uint32_t edi; //!< Pushed by pusha.
|
||||
uint32_t esi; //!< Pushed by pusha.
|
||||
uint32_t ebp; //!< Pushed by pusha.
|
||||
uint32_t esp; //!< Pushed by pusha.
|
||||
uint32_t ebx; //!< Pushed by pusha.
|
||||
uint32_t edx; //!< Pushed by pusha.
|
||||
uint32_t ecx; //!< Pushed by pusha.
|
||||
uint32_t eax; //!< Pushed by pusha.
|
||||
uint32_t int_no; //!< Interrupt number
|
||||
uint32_t err_code; //!< Error code (if applicable)
|
||||
uint32_t eip; //!< Pushed by the processor automatically
|
||||
uint32_t cs; //!< Pushed by the processor automatically
|
||||
uint32_t eflags; //!< Pushed by the processor automatically
|
||||
uint32_t useresp; //!< Pushed by the processor automatically
|
||||
uint32_t ss; //!< Pushed by the processor automatically
|
||||
} registers_t;
|
||||
|
||||
typedef void (*isr_t)(registers_t*);
|
||||
typedef void (*isr_t)(registers_t*); //!< Type of an ISR handler function pointer
|
||||
|
||||
/**
|
||||
* Install the interrupt handlers into the IDT.
|
||||
*/
|
||||
void isr_install();
|
||||
|
||||
/**
|
||||
* Register an IRQ handler
|
||||
* \param n the IRQ to register a handler for
|
||||
* \param handler the handler to register
|
||||
*/
|
||||
void isr_register_handler(int n,isr_t handler);
|
||||
|
||||
#endif
|
||||
|
@ -1,15 +1,68 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef PAGING_H
|
||||
#define PAGING_H
|
||||
|
||||
/**
|
||||
* Map virtual pages to physical frames.
|
||||
* \param virt_addr_ptr The start of the virtual range to map.
|
||||
* \param phys_addr_ptr The start of the physical range to map.
|
||||
* \param num_pages The number of pages to map.
|
||||
* \param usr Are the pages acessible by user mode code
|
||||
* \param wr Are the pages writable by user mode code (kernel always has write permissions)
|
||||
*/
|
||||
void map_pages(void* virt_addr_ptr,void* phys_addr_ptr,int num_pages,char usr,char wr);
|
||||
/**
|
||||
* Unmap virtual pages,
|
||||
* \param start_virt The start of the virtual range to unmap.
|
||||
* \param num_pages The number of pages to map.
|
||||
*/
|
||||
void unmap_pages(void* start_virt,int num_pages);
|
||||
/**
|
||||
* Allocate virtual pages & map them to physical memory.
|
||||
* \param num_pages The number of pages to allocate.
|
||||
* \return a pointer to the allocated pages.
|
||||
*/
|
||||
void* alloc_pages(int num_pages);
|
||||
/**
|
||||
* Allocate virtual pages at a specific address & map them to physical memory.
|
||||
* \param num_pages The number of pages to allocate.
|
||||
* \param addr The adress to start allocation at.
|
||||
*/
|
||||
void alloc_pages_virt(int num_pages,void* addr);
|
||||
/**
|
||||
* Initialize paging
|
||||
*/
|
||||
void paging_init();
|
||||
/**
|
||||
* Create a new address space
|
||||
* \return a pointer to the new address space in physical memory.
|
||||
*/
|
||||
void* paging_new_address_space();
|
||||
/**
|
||||
* Load an address space
|
||||
* \param cr3 The address space to load
|
||||
*/
|
||||
void load_address_space(void* cr3);
|
||||
/**
|
||||
* Convert a virtual address to a physical one.
|
||||
* \param virt_addr The virtual address to convert
|
||||
* \return the physical adress it maps to, or NULL if it is not mapped.
|
||||
*/
|
||||
void* virt_to_phys(void* virt_addr);
|
||||
/**
|
||||
* Finds free virtual pages and returns the start address
|
||||
* \param num_pages The minimum size of the free area
|
||||
* \return the start of the free area
|
||||
*/
|
||||
void* find_free_pages(int num_pages);
|
||||
|
||||
/**
|
||||
* Get the current address space
|
||||
* \return a pointer to the current address space in physical memory.
|
||||
*/
|
||||
void* get_cr3();
|
||||
|
||||
#endif
|
||||
|
@ -1,9 +1,34 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
/**
|
||||
* Initialize the serial driver
|
||||
*/
|
||||
void serial_init();
|
||||
|
||||
/**
|
||||
* Write a character to the serial port
|
||||
* \param c The character to write
|
||||
*/
|
||||
void serial_putc(char c);
|
||||
void serial_write_string(const char* s); //Provided by platform-independent code
|
||||
void serial_printf(const char* format,...); //Provided by platform-independent code
|
||||
|
||||
/**
|
||||
* Write a string to the serial port
|
||||
* \param s The string to write
|
||||
* \note This function is provided by platform-independent code, a serial driver does not need to implement this.
|
||||
*/
|
||||
void serial_write_string(const char* s);
|
||||
|
||||
/**
|
||||
* Printf, but to the serial port
|
||||
* \param format The format string
|
||||
* \param ... Arguments for the format string
|
||||
* \note This function is provided by platform-independent code, a serial driver does not need to implement this.
|
||||
*/
|
||||
void serial_printf(const char* format,...);
|
||||
|
||||
#endif
|
||||
|
@ -1,11 +1,37 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef TASKING_HELPERS_H
|
||||
#define TASKING_HELPERS_H
|
||||
|
||||
#include "../tasking.h"
|
||||
|
||||
/**
|
||||
* The assembly part of switching to a thread. Performs the actual context switch.
|
||||
* \param thread The thread to switch to.
|
||||
*/
|
||||
void switch_to_thread_asm(Thread* thread);
|
||||
|
||||
/**
|
||||
* Initializes a usermode task
|
||||
*/
|
||||
void task_init();
|
||||
|
||||
/**
|
||||
* An assembly helper for waiting for an unblocked thread
|
||||
* Starts interrupts, halts, then clears interrupts.
|
||||
*/
|
||||
void wait_for_unblocked_thread_asm();
|
||||
|
||||
/**
|
||||
* Setup a kernel stack for a thread
|
||||
* \param thread The thread to setup a stack for
|
||||
* \param param1 The thread's start function first parameter
|
||||
* \param param2 The thread's start function second parameter
|
||||
* \param kmode Whether the thread is a kernel mode thread
|
||||
* \param eip The start address of the thread
|
||||
*/
|
||||
void setup_kstack(Thread* thread,void* param1,void* param2,char kmode,void* eip);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,5 @@
|
||||
// #include "../tasking.h"
|
||||
// #include "paging.h"
|
||||
#include "../../drivers/vga.h"
|
||||
#include "../halt.h"
|
||||
#include "../isr.h"
|
||||
#include "idt.h"
|
||||
@ -170,7 +169,6 @@ void isr_handler(registers_t* r) {
|
||||
break;
|
||||
case 80:
|
||||
// if (r->eax==1) {
|
||||
// tss_stack_reset();
|
||||
// tasking_yield();
|
||||
// } else if (r->eax==2) {
|
||||
// tasking_createTask((void*)r->ebx);
|
||||
|
@ -12,15 +12,18 @@
|
||||
#include <string.h>
|
||||
#include <tasking.h>
|
||||
|
||||
/**
|
||||
* REspresents a TAR file header
|
||||
*/
|
||||
typedef struct {
|
||||
char filename[100];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char chksum[8];
|
||||
char typeflag[1];
|
||||
char filename[100]; //!< Filename of file descried by the tar header
|
||||
char mode[8]; //!< Mode as an octal string
|
||||
char uid[8]; //!< UID of owner as an octal string
|
||||
char gid[8]; //!< GID of owner as an octal string
|
||||
char size[12]; //!< Size of file as an octal string
|
||||
char mtime[12]; //!< Modification time as an octal string
|
||||
char chksum[8]; //!< Checksum as octal string
|
||||
char typeflag[1]; //!< File type. (0 for normal file)
|
||||
} tar_header;
|
||||
|
||||
long initrd_sz;
|
||||
|
@ -1,14 +1,22 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "cpu/arch_consts.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define KMALLOC_BMAP_SZ (((KMALLOC_SZ*1024)/4)/8)
|
||||
|
||||
static char bitmap[KMALLOC_BMAP_SZ];
|
||||
static void* data=(void*)KMALLOC_START;
|
||||
#define KMALLOC_BMAP_SZ (((KMALLOC_SZ*1024)/4)/8) //!< The size of the kmalloc bitmap
|
||||
|
||||
static char bitmap[KMALLOC_BMAP_SZ]; //!< Bitmap of used areas of the heap
|
||||
static void* data=(void*)KMALLOC_START; //!< Start of the kmalloc heap
|
||||
|
||||
/**
|
||||
* Get a bit in the heap bitmap
|
||||
* \param index The bit to get
|
||||
* \return the bit
|
||||
*/
|
||||
static char get_bmap_bit(size_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
@ -16,12 +24,20 @@ static char get_bmap_bit(size_t index) {
|
||||
return (entry&(1<<bit))>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bit in the heap bitmap
|
||||
* \param index The bit to set
|
||||
*/
|
||||
static void set_bmap_bit(size_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
bitmap[byte]=bitmap[byte]|(1<<bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a bit in the heap bitmap
|
||||
* \param index The bit to clear
|
||||
*/
|
||||
static void clear_bmap_bit(size_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
|
@ -1,9 +1,24 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef KMALLOC_H
|
||||
#define KMALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a block in the kernel heap
|
||||
* \param size The size of the block
|
||||
* \return the address of the block in the heap.
|
||||
*/
|
||||
void* kmalloc(size_t size);
|
||||
|
||||
/**
|
||||
* Free a block in the kernel heap
|
||||
* \param mem The address of the block
|
||||
*/
|
||||
void kfree(void* mem);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "cpu/arch_consts.h"
|
||||
#include "cpu/halt.h"
|
||||
#include "vga_err.h"
|
||||
@ -6,10 +10,15 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BMAP_LEN (NUM_FRAMES/8)
|
||||
#define BMAP_LEN (NUM_FRAMES/8) //!< The size of the physical memory manager's bitmap
|
||||
|
||||
static char bmap[BMAP_LEN];
|
||||
static char bmap[BMAP_LEN]; //!< Bitmap of allocated/non-present page frames
|
||||
|
||||
/**
|
||||
* Get a bit in the bitmap
|
||||
* \param index The bit to get
|
||||
* \return the bit
|
||||
*/
|
||||
static char get_bmap_bit(int index) {
|
||||
int byte=index/8;
|
||||
int bit=index%8;
|
||||
@ -17,12 +26,20 @@ static char get_bmap_bit(int index) {
|
||||
return (entry&(1<<bit))>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bit in the heap bitmap
|
||||
* \param index The bit to set
|
||||
*/
|
||||
static void set_bmap_bit(int index) {
|
||||
int byte=index/8;
|
||||
int bit=index%8;
|
||||
bmap[byte]=bmap[byte]|(1<<bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a bit in the heap bitmap
|
||||
* \param index The bit to clear
|
||||
*/
|
||||
static void clear_bmap_bit(int index) {
|
||||
int byte=index/8;
|
||||
int bit=index%8;
|
||||
|
@ -1,10 +1,29 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef PMEM_H
|
||||
#define PMEM_H
|
||||
|
||||
#include <grub/multiboot2.h>
|
||||
|
||||
/**
|
||||
* Initialize the physical memory manager
|
||||
* \param tags The multiboot header
|
||||
*/
|
||||
void pmem_init(struct multiboot_boot_header_tag* tags);
|
||||
/**
|
||||
* Allocate physical frames
|
||||
* \param num_pages The number of frames to allocate
|
||||
* \return the physical address of the allocated frames
|
||||
*/
|
||||
void* pmem_alloc(int num_pages);
|
||||
|
||||
/**
|
||||
* Free allocated physical frames
|
||||
* \param start_page The frame to start freeing at.
|
||||
* \param num_pages The number of frames to free
|
||||
*/
|
||||
void pmem_free(int start_page,int num_pages);
|
||||
|
||||
#endif
|
||||
|
20
kernel/rpc.h
20
kernel/rpc.h
@ -1,18 +1,16 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef RPC_H
|
||||
#define RPC_H
|
||||
|
||||
/**
|
||||
* Represents an RPC fumctiom
|
||||
*/
|
||||
typedef struct RPCFuncInfo {
|
||||
char name[32];
|
||||
void* (*code)(void*);
|
||||
char name[32]; //!< THe name of the function
|
||||
void* (*code)(void*); //!< A pointer to the code that implements the funtcion
|
||||
} RPCFuncInfo;
|
||||
|
||||
typedef struct ThreadRPCStruct {
|
||||
RPCFuncInfo funcs[32];
|
||||
int num_funcs;
|
||||
void* rpc_response;
|
||||
} ThreadRPCStruct;
|
||||
|
||||
|
||||
void rpc_init_struct(ThreadRPCStruct* info);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include "cpu/halt.h"
|
||||
#include "cpu/paging.h"
|
||||
#include "cpu/serial.h"
|
||||
@ -6,19 +10,24 @@
|
||||
#include "tasking.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#define MAX_PROCS 32768
|
||||
#define HAS_UNBLOCKED_THREADS(proc) (proc->numThreads!=proc->numThreadsBlocked)
|
||||
#define NUM_UNBLOCKED_THREADS(proc) (proc->numThreads-proc->numThreadsBlocked)
|
||||
#define SAME_PROC(thread1,thread2) (thread1->process->pid==thread2->process->pid)
|
||||
#define SAME_THREAD(thread1,thread2) (thread1->process->pid==thread2->process->pid&&thread1->tid==thread2->tid)
|
||||
pid_t next_pid=0;
|
||||
size_t num_procs=0;
|
||||
Process* processes[MAX_PROCS];
|
||||
char proc_schedule_bmap[MAX_PROCS/8];
|
||||
Thread* currentThread;
|
||||
static Thread* readyToRunHead=NULL;
|
||||
static Thread* readyToRunTail=NULL;
|
||||
#define MAX_PROCS 32768 //!< Maximum number of processes that can be running at a time
|
||||
#define HAS_UNBLOCKED_THREADS(proc) (proc->numThreads!=proc->numThreadsBlocked) //!< Macro to check whethe a process has unblocked threads
|
||||
#define NUM_UNBLOCKED_THREADS(proc) (proc->numThreads-proc->numThreadsBlocked) //!< Macro to get the number of unblocked threads for a process
|
||||
#define SAME_PROC(thread1,thread2) (thread1->process->pid==thread2->process->pid) //!< Macro to check whether two threads have the same PID
|
||||
#define SAME_THREAD(thread1,thread2) (thread1->process->pid==thread2->process->pid&&thread1->tid==thread2->tid) //!< Macro to check whether two threads have the same PID and TID
|
||||
pid_t next_pid=0; //!< PID to use for the next created process
|
||||
size_t num_procs=0; //!< Number of non-exited processes
|
||||
Process* processes[MAX_PROCS]; //!< Array pf processes by PID
|
||||
char proc_schedule_bmap[MAX_PROCS/8]; //!< Bitmap of what processes are scheduled
|
||||
Thread* currentThread; //!< Currently running thread
|
||||
static Thread* readyToRunHead=NULL; //!< Head of the linked list of ready to run threads
|
||||
static Thread* readyToRunTail=NULL; //!< Tail of the linked list of ready to run threads
|
||||
|
||||
/**
|
||||
* Check whether a process is scheduled
|
||||
* \param index The PID to check
|
||||
* \return whether the process is scheduled
|
||||
*/
|
||||
static char is_proc_scheduled(pid_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
@ -26,6 +35,10 @@ static char is_proc_scheduled(pid_t index) {
|
||||
return (entry&(1<<bit))>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a process as scheduled
|
||||
* \param index The PID to mark
|
||||
*/
|
||||
static void mark_proc_scheduled(pid_t index) {
|
||||
if (is_proc_scheduled(index)) {
|
||||
serial_printf("Attempt to schedule a thread in a process with a scheduled thread! (PID %d)\n",index);
|
||||
@ -36,6 +49,10 @@ static void mark_proc_scheduled(pid_t index) {
|
||||
proc_schedule_bmap[byte]=proc_schedule_bmap[byte]|(1<<bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmark a process as scheduled
|
||||
* \param index The PID to unmark
|
||||
*/
|
||||
static void unmark_proc_scheduled(pid_t index) {
|
||||
size_t byte=index/8;
|
||||
size_t bit=index%8;
|
||||
@ -146,6 +163,10 @@ pid_t tasking_new_thread(void* start,pid_t pid,char param_exists,void* param_arg
|
||||
return processes[pid]->firstThread->tid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a thread and schedule the next ready thread in the current process, if there is one.
|
||||
* \param thread The thread to switch to
|
||||
*/
|
||||
void switch_to_thread(Thread* thread) {
|
||||
// Unlink the thread from the list of ready-to-run threads
|
||||
if (thread!=readyToRunHead) {
|
||||
|
103
kernel/tasking.h
103
kernel/tasking.h
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef KERN_TASKING_H
|
||||
#define KERN_TASKING_H
|
||||
|
||||
@ -6,52 +10,109 @@
|
||||
|
||||
#ifndef TASKING_H
|
||||
|
||||
/**
|
||||
* Represents the state of a thread
|
||||
*/
|
||||
typedef enum ThreadState {
|
||||
THREAD_RUNNING,
|
||||
THREAD_READY,
|
||||
THREAD_EXITED,
|
||||
THREAD_BLOCKED
|
||||
THREAD_RUNNING, //!< The state of a running thread
|
||||
THREAD_READY, //!< The state of a ready to run thread
|
||||
THREAD_EXITED, //!< The state of an exited thread
|
||||
THREAD_BLOCKED //!< The state of a generically blocked thread
|
||||
} ThreadState;
|
||||
|
||||
#endif
|
||||
|
||||
struct Thread;
|
||||
|
||||
/**
|
||||
* Represents a process
|
||||
*/
|
||||
typedef struct Process {
|
||||
char priv;
|
||||
pid_t pid;
|
||||
pid_t next_tid;
|
||||
int numThreads;
|
||||
int numThreadsBlocked;
|
||||
struct Thread* firstThread;
|
||||
char priv; //!< Whether the process is privileged (can execute syscalls to acesss all of memory/has acess to IO ports).
|
||||
pid_t pid; //!< The PID of this process
|
||||
pid_t next_tid; //!< The TID that the next created thread will use.
|
||||
int numThreads; //!< The number of threads in this process
|
||||
int numThreadsBlocked; //!< The number of blocked threads in this process
|
||||
struct Thread* firstThread; //!< A pointer to the head of the linked list of threads for this process.
|
||||
} Process;
|
||||
|
||||
/**
|
||||
* Represents a thread of a process
|
||||
*/
|
||||
typedef struct Thread {
|
||||
void* kernel_esp;
|
||||
void* kernel_esp_top;
|
||||
void* cr3; //In thread to make the task switch asm easier
|
||||
pid_t tid;
|
||||
ThreadState state;
|
||||
int errno;
|
||||
struct Thread* nextThreadInProcess;
|
||||
struct Thread* prevThreadInProcess;
|
||||
struct Thread* nextReadyToRun;
|
||||
struct Thread* prevReadyToRun;
|
||||
Process* process;
|
||||
void* kernel_esp; //!< The thread's kernel stack.
|
||||
void* kernel_esp_top; //!< The top of the thread's kernel stack.
|
||||
void* cr3; //!< The address space of this thread. (it is in here and not in the process to simplify the task switch asembly)
|
||||
pid_t tid; //!< The TID of this thread.
|
||||
ThreadState state; //!< The state of this thread. (running,ready to run,blocked,etc.)
|
||||
int errno; //!< The errno value for this thread.
|
||||
struct Thread* nextThreadInProcess; //!< The next thread in the process.
|
||||
struct Thread* prevThreadInProcess; //!< The previous thread in the process.
|
||||
struct Thread* nextReadyToRun; //!< If the thread is in the ready to run list, this is the next ready to run thread. (potentially in a different process)
|
||||
struct Thread* prevReadyToRun; //!< If the thread is in the ready to run list, this is the previous ready to run thread. (potentially in a different process)
|
||||
Process* process; //!< The thread's process.
|
||||
} Thread;
|
||||
|
||||
extern Thread* currentThread;
|
||||
|
||||
/**
|
||||
* Create a task
|
||||
* \param eip The start address of the task
|
||||
* \param cr3 The address space of the task
|
||||
* \param kmode Whether the task is a kernel mode task
|
||||
* \param param1_exists Whether param1_arg is a valid value
|
||||
* \param param1_arg The thread's start function first parameter
|
||||
* \param param2_exists Whether param2_arg is a valid value
|
||||
* \param param2_arg The thread's start function second parameter/
|
||||
* \param isThread Whether we are creating a new process or a thread in a process. If we are creating a theead, param2_arg becomes the PID for the newly created thread, and param2_exists must be 0.
|
||||
*/
|
||||
void tasking_createTask(void* eip,void* cr3,char kmode,char param1_exists,void* param1_arg,char param2_exists,void* param2_arg,char isThread);
|
||||
/**
|
||||
* Initialize tasking
|
||||
*/
|
||||
void tasking_init();
|
||||
/**
|
||||
* Check whether the current process is privleged
|
||||
*/
|
||||
char tasking_isPrivleged();
|
||||
/**
|
||||
* Get the PID of the current thread.
|
||||
*/
|
||||
pid_t tasking_getPID();
|
||||
/**
|
||||
* Get the adddress of errno for the current thread
|
||||
*/
|
||||
int* tasking_get_errno_address();
|
||||
/**
|
||||
* Create a new thread
|
||||
* \param start The start address of the task
|
||||
* \param pid The PID that gets the new thread
|
||||
* \param param_exists Whether param_arg is a valid value
|
||||
* \param param_arg The thread's start function parameter
|
||||
* \return the TID of the thread
|
||||
*/
|
||||
pid_t tasking_new_thread(void* start,pid_t pid,char param_exists,void* param_arg);
|
||||
|
||||
/**
|
||||
* Terminate the current thread
|
||||
* If the main thread terminates, the whole process terminates.
|
||||
* \note Currently, calling tasking_exit from any thread terminates the whole process.
|
||||
*/
|
||||
void tasking_exit(int code);
|
||||
/**
|
||||
* Block the current thread & yield
|
||||
* \param newstate The state to block it in
|
||||
*/
|
||||
void tasking_block(ThreadState newstate);
|
||||
/**
|
||||
* Unblock a thread
|
||||
* \param pid The PID that contains the thread to unblock
|
||||
* \param tid The TID in the process to unblock.
|
||||
*/
|
||||
void tasking_unblock(pid_t pid,pid_t tid);
|
||||
/**
|
||||
* Yield to the next ready thread in any process
|
||||
*/
|
||||
void tasking_yield();
|
||||
|
||||
#endif
|
||||
|
@ -1,11 +1,20 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#include <cpu/ports.h>
|
||||
#include <string.h>
|
||||
|
||||
#define VGA_BLACK 0
|
||||
#define VGA_WHITE 15
|
||||
static char* screen;
|
||||
static int x=0;
|
||||
#define VGA_BLACK 0 //!< The color black
|
||||
#define VGA_WHITE 15 //!< The color white
|
||||
static char* screen; //!< Pointer to VGA screen memory
|
||||
static int x=0; //!< Next character offset in VGA sreen memory
|
||||
|
||||
/**
|
||||
* Set a character on the screen
|
||||
* \param x The character index to set
|
||||
* \param c The character to write
|
||||
*/
|
||||
static void set_char(int x,char c) {
|
||||
screen[x*2]=c;
|
||||
screen[x*2+1]=(VGA_BLACK<<4)|VGA_WHITE;
|
||||
|
@ -1,7 +1,18 @@
|
||||
/**
|
||||
* \file
|
||||
*/
|
||||
|
||||
#ifndef VGA_ERR_H
|
||||
#define VGA_ERR_H
|
||||
|
||||
/**
|
||||
* Initilaze the VGA error writing driver
|
||||
*/
|
||||
void vga_init(char* screen);
|
||||
|
||||
/**
|
||||
* Write a string starting at the top line of the VGA display
|
||||
*/
|
||||
void vga_write_string(const char *string);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user