Compare commits
2 commits
0d81f79a96
...
887429636c
Author | SHA1 | Date | |
---|---|---|---|
vanten-s | 887429636c | ||
vanten-s | bb441eaeb6 |
6
Makefile
6
Makefile
|
@ -25,16 +25,18 @@ kernel/elf.o \
|
||||||
kernel/syscall.o \
|
kernel/syscall.o \
|
||||||
kernel/io/keyboard.o \
|
kernel/io/keyboard.o \
|
||||||
kernel/heap.o \
|
kernel/heap.o \
|
||||||
|
kernel/task.o \
|
||||||
|
|
||||||
LIB_OBJS=\
|
LIB_OBJS=\
|
||||||
$(ARCHDIR)/bootstrap.o \
|
$(ARCHDIR)/bootstrap.o \
|
||||||
$(ARCHDIR)/tty.o \
|
$(ARCHDIR)/tty.o \
|
||||||
$(ARCHDIR)/strlib.o \
|
$(ARCHDIR)/strlib.o \
|
||||||
|
$(ARCHDIR)/paging.o \
|
||||||
|
$(ARCHDIR)/gdt.o \
|
||||||
$(ARCHDIR)/interrupts/idt.o \
|
$(ARCHDIR)/interrupts/idt.o \
|
||||||
$(ARCHDIR)/interrupts/interrupt.o \
|
$(ARCHDIR)/interrupts/interrupt.o \
|
||||||
|
$(ARCHDIR)/interrupts/irq0.o \
|
||||||
$(ARCHDIR)/interrupts/syscall.o \
|
$(ARCHDIR)/interrupts/syscall.o \
|
||||||
$(ARCHDIR)/gdt.o \
|
|
||||||
$(ARCHDIR)/userland.o \
|
|
||||||
$(ARCHDIR)/interrupts/pic.o \
|
$(ARCHDIR)/interrupts/pic.o \
|
||||||
|
|
||||||
OBJS=$(KERNEL_OBJS) $(LIB_OBJS)
|
OBJS=$(KERNEL_OBJS) $(LIB_OBJS)
|
||||||
|
|
0
arch/i686/ata.c
Normal file
0
arch/i686/ata.c
Normal file
|
@ -1,18 +1,12 @@
|
||||||
/* Declare constants for the multiboot header. */
|
# Declare constants for the multiboot header.
|
||||||
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
.set ALIGN, 1<<0 # align loaded modules on page boundaries
|
||||||
.set MEMINFO, 1<<1 /* provide memory map */
|
.set MEMINFO, 1<<1 # provide memory map
|
||||||
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
|
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
|
||||||
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
|
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
|
||||||
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
|
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
|
||||||
|
|
||||||
/*
|
# Declare a multiboot header that marks the program as a kernel.
|
||||||
Declare a multiboot header that marks the program as a kernel. These are magic
|
.section .multiboot.data, "aw"
|
||||||
values that are documented in the multiboot standard. The bootloader will
|
|
||||||
search for this signature in the first 8 KiB of the kernel file, aligned at a
|
|
||||||
32-bit boundary. The signature is in its own section so the header can be
|
|
||||||
forced to be within the first 8 KiB of the kernel file.
|
|
||||||
*/
|
|
||||||
.section .multiboot
|
|
||||||
.align 4
|
.align 4
|
||||||
.long MAGIC
|
.long MAGIC
|
||||||
.long FLAGS
|
.long FLAGS
|
||||||
|
@ -31,100 +25,109 @@ stack is properly aligned and failure to align the stack will result in
|
||||||
undefined behavior.
|
undefined behavior.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.section .bss
|
.section .bss, "aw", @nobits
|
||||||
.align 16
|
.align 16
|
||||||
stack_bottom:
|
stack_bottom:
|
||||||
.skip 16384 # 16 KiB
|
.skip 16384 # 16 KiB
|
||||||
stack_top:
|
stack_top:
|
||||||
|
|
||||||
|
.global boot_page_directory
|
||||||
|
.align 4096
|
||||||
|
boot_page_directory:
|
||||||
|
.skip 4096
|
||||||
|
boot_page_table1:
|
||||||
|
.skip 4096
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The linker script specifies _start as the entry point to the kernel and the
|
The linker script specifies _start as the entry point to the kernel and the
|
||||||
bootloader will jump to this position once the kernel has been loaded. It
|
bootloader will jump to this position once the kernel has been loaded. It
|
||||||
doesn't make sense to return from this function as the bootloader is gone.
|
doesn't make sense to return from this function as the bootloader is gone.
|
||||||
*/
|
*/
|
||||||
.section .text
|
.section .multiboot.text, "a"
|
||||||
.global _start
|
.global _start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
_start:
|
_start:
|
||||||
/*
|
# Physical address of boot_page_table1.
|
||||||
The bootloader has loaded us into 32-bit protected mode on a x86
|
# TODO: I recall seeing some assembly that used a macro to do the
|
||||||
machine. Interrupts are disabled. Paging is disabled. The processor
|
# conversions to and from physical. Maybe this should be done in this
|
||||||
state is as defined in the multiboot standard. The kernel has full
|
# code as well?
|
||||||
control of the CPU. The kernel can only make use of hardware features
|
movl $(boot_page_table1 - 0xC0000000), %edi
|
||||||
and any code it provides as part of itself. There's no printf
|
# First address to map is address 0.
|
||||||
function, unless the kernel provides its own <stdio.h> header and a
|
# TODO: Start at the first kernel page instead. Alternatively map the first
|
||||||
printf implementation. There are no security restrictions, no
|
# 1 MiB as it can be generally useful, and there's no need to
|
||||||
safeguards, no debugging mechanisms, only what the kernel provides
|
# specially map the VGA buffer.
|
||||||
itself. It has absolute and complete power over the
|
movl $0, %esi
|
||||||
machine.
|
# Map 1023 pages. The 1024th will be the VGA text buffer.
|
||||||
*/
|
movl $1023, %ecx
|
||||||
|
|
||||||
/*
|
1:
|
||||||
To set up a stack, we set the esp register to point to the top of the
|
# Only map the kernel.
|
||||||
stack (as it grows downwards on x86 systems). This is necessarily done
|
cmpl $_kernel_start, %esi
|
||||||
in assembly as languages such as C cannot function without a stack.
|
jl 2f
|
||||||
*/
|
cmpl $(_kernel_end - 0xC0000000), %esi
|
||||||
|
jge 3f
|
||||||
|
|
||||||
|
# Map physical address as "present, writable". Note that this maps
|
||||||
|
# .text and .rodata as writable. Mind security and map them as non-writable.
|
||||||
|
movl %esi, %edx
|
||||||
|
orl $0x003, %edx
|
||||||
|
movl %edx, (%edi)
|
||||||
|
|
||||||
|
2:
|
||||||
|
# Size of page is 4096 bytes.
|
||||||
|
addl $4096, %esi
|
||||||
|
# Size of entries in boot_page_table1 is 4 bytes.
|
||||||
|
addl $4, %edi
|
||||||
|
# Loop to the next entry if we haven't finished.
|
||||||
|
loop 1b
|
||||||
|
|
||||||
|
3:
|
||||||
|
# Map VGA video memory to 0xC03FF000 as "present, writable".
|
||||||
|
movl $(0x000B8000 | 0x003), boot_page_table1 - 0xC0000000 + 1023 * 4
|
||||||
|
|
||||||
|
# The page table is used at both page directory entry 0 (virtually from 0x0
|
||||||
|
# to 0x3FFFFF) (thus identity mapping the kernel) and page directory entry
|
||||||
|
# 768 (virtually from 0xC0000000 to 0xC03FFFFF) (thus mapping it in the
|
||||||
|
# higher half). The kernel is identity mapped because enabling paging does
|
||||||
|
# not change the next instruction, which continues to be physical. The CPU
|
||||||
|
# would instead page fault if there was no identity mapping.
|
||||||
|
|
||||||
|
# Map the page table to both virtual addresses 0x00000000 and 0xC0000000.
|
||||||
|
movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0
|
||||||
|
movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4
|
||||||
|
|
||||||
|
# Set cr3 to the address of the boot_page_directory.
|
||||||
|
movl $(boot_page_directory - 0xC0000000), %ecx
|
||||||
|
movl %ecx, %cr3
|
||||||
|
|
||||||
|
# Enable paging and the write-protect bit.
|
||||||
|
movl %cr0, %ecx
|
||||||
|
orl $0x80010000, %ecx
|
||||||
|
movl %ecx, %cr0
|
||||||
|
|
||||||
|
# Jump to higher half with an absolute jump.
|
||||||
|
lea 4f, %ecx
|
||||||
|
jmp *%ecx
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
4:
|
||||||
|
# At this point, paging is fully set up and enabled.
|
||||||
|
|
||||||
|
# Unmap the identity mapping as it is now unnecessary.
|
||||||
|
movl $0, boot_page_directory + 0
|
||||||
|
|
||||||
|
# Reload crc3 to force a TLB flush so the changes to take effect.
|
||||||
|
movl %cr3, %ecx
|
||||||
|
movl %ecx, %cr3
|
||||||
|
|
||||||
|
# Set up the stack.
|
||||||
mov $stack_top, %esp
|
mov $stack_top, %esp
|
||||||
|
|
||||||
cli
|
# Enter the high-level kernel.
|
||||||
|
|
||||||
call gdt_init
|
|
||||||
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
movw %ax, %gs
|
|
||||||
movw %ax, %ss
|
|
||||||
# jmp kernel
|
|
||||||
ljmp $0x08, $kernel
|
|
||||||
|
|
||||||
kernel:
|
|
||||||
/*
|
|
||||||
This is a good place to initialize crucial processor state before the
|
|
||||||
high-level kernel is entered. It's best to minimize the early
|
|
||||||
environment where crucial features are offline. Note that the
|
|
||||||
processor is not fully initialized yet: Features such as floating
|
|
||||||
point instructions and instruction set extensions are not initialized
|
|
||||||
yet. The GDT should be loaded here. Paging should be enabled here.
|
|
||||||
C++ features such as global constructors and exceptions will require
|
|
||||||
runtime support to work as well.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Enter the high-level kernel. The ABI requires the stack is 16-byte
|
|
||||||
aligned at the time of the call instruction (which afterwards pushes
|
|
||||||
the return pointer of size 4 bytes). The stack was originally 16-byte
|
|
||||||
aligned above and we've pushed a multiple of 16 bytes to the
|
|
||||||
stack since (pushed 0 bytes so far), so the alignment has thus been
|
|
||||||
preserved and the call is well defined.
|
|
||||||
*/
|
|
||||||
|
|
||||||
call kernel_main
|
call kernel_main
|
||||||
|
|
||||||
.global keyboard_test
|
# Infinite loop if the system has nothing more to do.
|
||||||
keyboard_test:
|
|
||||||
hlt
|
|
||||||
|
|
||||||
/*
|
|
||||||
If the system has nothing more to do, put the computer into an
|
|
||||||
infinite loop. To do that:
|
|
||||||
1) Disable interrupts with cli (clear interrupt enable in eflags).
|
|
||||||
They are already disabled by the bootloader, so this is not needed.
|
|
||||||
Mind that you might later enable interrupts and return from
|
|
||||||
kernel_main (which is sort of nonsensical to do).
|
|
||||||
2) Wait for the next interrupt to arrive with hlt (halt instruction).
|
|
||||||
Since they are disabled, this will lock up the computer.
|
|
||||||
3) Jump to the hlt instruction if it ever wakes up due to a
|
|
||||||
non-maskable interrupt occurring or due to system management mode.
|
|
||||||
*/
|
|
||||||
cli
|
cli
|
||||||
1: hlt
|
1: hlt
|
||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
/*
|
|
||||||
Set the size of the _start symbol to the current location '.' minus its start.
|
|
||||||
This is useful when debugging or when you implement call tracing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.size _start, . - _start
|
|
||||||
|
|
|
@ -15,6 +15,15 @@
|
||||||
#define IRQ6 (IRQ0 + 6)
|
#define IRQ6 (IRQ0 + 6)
|
||||||
#define IRQ7 (IRQ0 + 7)
|
#define IRQ7 (IRQ0 + 7)
|
||||||
|
|
||||||
|
#define IRQ8 0x28
|
||||||
|
#define IRQ9 (IRQ8 + 1)
|
||||||
|
#define IRQ10 (IRQ8 + 2)
|
||||||
|
#define IRQ11 (IRQ8 + 3)
|
||||||
|
#define IRQ12 (IRQ8 + 4)
|
||||||
|
#define IRQ13 (IRQ8 + 5)
|
||||||
|
#define IRQ14 (IRQ8 + 6)
|
||||||
|
#define IRQ15 (IRQ8 + 7)
|
||||||
|
|
||||||
#define NUM_ENTRIES 0x100
|
#define NUM_ENTRIES 0x100
|
||||||
|
|
||||||
struct InterruptDescriptor {
|
struct InterruptDescriptor {
|
||||||
|
@ -97,21 +106,20 @@ static void load_idt()
|
||||||
idt.base = entries;
|
idt.base = entries;
|
||||||
|
|
||||||
asm ( "lidt %0" : : "m"(idt) );
|
asm ( "lidt %0" : : "m"(idt) );
|
||||||
asm ( "sti" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InterruptDescriptor generate_entry(bool present, void isr(struct interrupt_frame*), uint8_t gate_type, uint8_t ring, uint8_t selector)
|
static struct InterruptDescriptor generate_entry(bool present, void isr(struct interrupt_frame*), uint8_t gate_type, uint8_t ring, uint8_t selector)
|
||||||
{
|
{
|
||||||
struct InterruptDescriptor entry;
|
struct InterruptDescriptor entry;
|
||||||
entry.present = present;
|
entry.present = present;
|
||||||
entry.offset = (uint32_t)isr;
|
entry.offset = (size_t)isr;
|
||||||
entry.gate_type = gate_type;
|
entry.gate_type = gate_type;
|
||||||
entry.ring = ring;
|
entry.ring = ring;
|
||||||
entry.selector = selector;
|
entry.selector = selector;
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_init()
|
static void add_exceptions()
|
||||||
{
|
{
|
||||||
struct InterruptDescriptor entry;
|
struct InterruptDescriptor entry;
|
||||||
|
|
||||||
|
@ -130,23 +138,47 @@ void idt_init()
|
||||||
entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
|
entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
|
||||||
add_entry(entry, DoubleFault);
|
add_entry(entry, DoubleFault);
|
||||||
|
|
||||||
entry = generate_entry(true, irq, 0xE, 0, 0x8);
|
}
|
||||||
|
|
||||||
|
static void add_irqs()
|
||||||
|
{
|
||||||
|
struct InterruptDescriptor entry;
|
||||||
|
entry = generate_entry(true, irq_1, 0xE, 0, 0x8);
|
||||||
for (int i = IRQ0; i <= IRQ7; i++)
|
for (int i = IRQ0; i <= IRQ7; i++)
|
||||||
{
|
{
|
||||||
add_entry(entry, i);
|
add_entry(entry, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry = generate_entry(true, irq_2, 0xE, 0, 0x8);
|
||||||
|
for (int i = IRQ8; i <= IRQ15; i++)
|
||||||
|
{
|
||||||
|
add_entry(entry, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = generate_entry(true, irq0, 0xE, 0, 0x8);
|
||||||
|
add_entry(entry, IRQ0);
|
||||||
|
|
||||||
entry = generate_entry(true, keyboard_interrupt, 0xE, 0, 0x8);
|
entry = generate_entry(true, keyboard_interrupt, 0xE, 0, 0x8);
|
||||||
add_entry(entry, IRQ1);
|
add_entry(entry, IRQ1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_syscall()
|
||||||
|
{
|
||||||
struct InterruptDescriptor syscall_entry;
|
struct InterruptDescriptor syscall_entry;
|
||||||
syscall_entry.present = true;
|
syscall_entry.present = true;
|
||||||
syscall_entry.offset = (uint32_t)syscall;
|
syscall_entry.offset = (size_t)syscall;
|
||||||
syscall_entry.gate_type = 0xE;
|
syscall_entry.gate_type = 0xE;
|
||||||
syscall_entry.ring = 3;
|
syscall_entry.ring = 3;
|
||||||
syscall_entry.selector = 0x8;
|
syscall_entry.selector = 0x8;
|
||||||
|
|
||||||
add_entry(syscall_entry, 0x80);
|
add_entry(syscall_entry, 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_init()
|
||||||
|
{
|
||||||
|
add_exceptions();
|
||||||
|
add_irqs();
|
||||||
|
add_syscall();
|
||||||
|
|
||||||
load_idt();
|
load_idt();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
|
#include <kernel/task.h>
|
||||||
|
#include "interrupt.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <debugging.h>
|
#include <debugging.h>
|
||||||
#include <kernel/io/keyboard.h>
|
#include <kernel/io/keyboard.h>
|
||||||
#include "../io.h"
|
#include "../io.h"
|
||||||
|
|
||||||
struct interrupt_frame {
|
|
||||||
uint32_t eflags;
|
|
||||||
uint32_t cs;
|
|
||||||
uint32_t eip;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t test = 'a';
|
uint8_t test = 'a';
|
||||||
|
|
||||||
static void stack_trace()
|
static void stack_trace()
|
||||||
|
@ -25,40 +21,54 @@ static void stack_trace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void divide_by_zero(void*)
|
__attribute__((interrupt)) void divide_by_zero(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
terminal_writestring("Yo dude u cant divide by zero yao\n");
|
terminal_writestring("Yo dude u cant divide by zero yao\n");
|
||||||
while (1) { }
|
while (1) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void general_protection_fault(void*)
|
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
terminal_writestring("GPF handler called\n");
|
terminal_writestring("GPF handler called\n");
|
||||||
while (1) { }
|
while (1) {
|
||||||
|
asm("cli");
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void double_fault(void*)
|
__attribute__((interrupt)) void double_fault(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
stack_trace();
|
stack_trace();
|
||||||
terminal_writestring("2 Errors in a row, u better behave naughty naughty\n");
|
terminal_writestring("2 Errors in a row, u better behave naughty naughty\n");
|
||||||
while (1) { }
|
while (1) {
|
||||||
|
asm("cli");
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void exception(void*)
|
__attribute__((interrupt)) void exception(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
terminal_writestring("Some weird error code stuff\n");
|
terminal_writestring("Some weird error code stuff\n");
|
||||||
while (1) { }
|
while (1) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void keyboard_interrupt(void*)
|
__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
|
terminal_writestring("Keyboard Interrupt\n");
|
||||||
uint8_t scancode = inb(0x60);
|
uint8_t scancode = inb(0x60);
|
||||||
handle_keyboard(scancode);
|
handle_keyboard(scancode);
|
||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt)) void irq(void*)
|
__attribute__((interrupt)) void irq_1(struct interrupt_frame*)
|
||||||
{
|
{
|
||||||
|
terminal_writestring("PIC 1\n");
|
||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((interrupt)) void irq_2(struct interrupt_frame*)
|
||||||
|
{
|
||||||
|
terminal_writestring("PIC 2\n");
|
||||||
|
outb(0xA0, 0x20);
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
struct interrupt_frame;
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct interrupt_frame {
|
||||||
|
size_t eip;
|
||||||
|
size_t cs;
|
||||||
|
size_t eflags;
|
||||||
|
size_t ss;
|
||||||
|
size_t esp;
|
||||||
|
};
|
||||||
|
|
||||||
__attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame);
|
__attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame);
|
||||||
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame);
|
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame);
|
||||||
|
@ -6,7 +14,10 @@ __attribute__((interrupt)) void double_fault(struct interrupt_frame* frame);
|
||||||
|
|
||||||
__attribute__((interrupt)) void exception(struct interrupt_frame* frame);
|
__attribute__((interrupt)) void exception(struct interrupt_frame* frame);
|
||||||
|
|
||||||
__attribute__((interrupt)) void syscall(void*);
|
__attribute__((interrupt)) void syscall(struct interrupt_frame* frame);
|
||||||
|
|
||||||
__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame);
|
__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame* frame);
|
||||||
__attribute__((interrupt)) void irq(struct interrupt_frame* frame);
|
__attribute__((interrupt)) void irq_1(struct interrupt_frame* frame);
|
||||||
|
__attribute__((interrupt)) void irq_2(struct interrupt_frame* frame);
|
||||||
|
|
||||||
|
__attribute__((interrupt)) void irq0(struct interrupt_frame* frame);
|
||||||
|
|
68
arch/i686/interrupts/irq0.s
Normal file
68
arch/i686/interrupts/irq0.s
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
.global irq0
|
||||||
|
.extern _switch_task
|
||||||
|
|
||||||
|
.global jump_kernel
|
||||||
|
.global jump_user
|
||||||
|
|
||||||
|
.extern ss
|
||||||
|
.extern esp
|
||||||
|
.extern eflags
|
||||||
|
.extern cs
|
||||||
|
.extern eip
|
||||||
|
|
||||||
|
irq0:
|
||||||
|
pusha
|
||||||
|
|
||||||
|
mov $0x10, %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
call _switch_task
|
||||||
|
|
||||||
|
iret
|
||||||
|
|
||||||
|
jump_kernel:
|
||||||
|
mov $0x20, %eax
|
||||||
|
outb %al, $0x20
|
||||||
|
|
||||||
|
mov (ss), %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
popa
|
||||||
|
|
||||||
|
mov (esp), %esp
|
||||||
|
|
||||||
|
push (ss)
|
||||||
|
push (esp)
|
||||||
|
push (eflags)
|
||||||
|
push (cs)
|
||||||
|
push (eip)
|
||||||
|
|
||||||
|
iret
|
||||||
|
|
||||||
|
jump_user:
|
||||||
|
mov $0x20, %eax
|
||||||
|
outb %al, $0x20
|
||||||
|
|
||||||
|
mov (ss), %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
popa
|
||||||
|
|
||||||
|
push (ss)
|
||||||
|
push (esp)
|
||||||
|
push (eflags)
|
||||||
|
push (cs)
|
||||||
|
push (eip)
|
||||||
|
|
||||||
|
iret
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,18 @@
|
||||||
|
|
||||||
void init_pic() {
|
void init_pic() {
|
||||||
uint8_t a1;
|
uint8_t a1;
|
||||||
|
uint8_t a2;
|
||||||
|
|
||||||
a1 = inb(PIC1_DATA); // save masks
|
a1 = inb(PIC1_DATA); // save masks
|
||||||
inb(PIC2_DATA);
|
a2 = inb(PIC2_DATA);
|
||||||
|
|
||||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset
|
outb(PIC1_DATA, 0x20); // ICW2: Master PIC vector offset
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC2_DATA, 0xFF); // ICW2: Slave PIC vector offset
|
outb(PIC2_DATA, 0x28); // ICW2: Slave PIC vector offset
|
||||||
io_wait();
|
io_wait();
|
||||||
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||||
io_wait();
|
io_wait();
|
||||||
|
@ -45,5 +46,5 @@ void init_pic() {
|
||||||
|
|
||||||
outb(PIC1_DATA, a1); // restore saved masks.
|
outb(PIC1_DATA, a1); // restore saved masks.
|
||||||
// outb(PIC2_DATA, a2);
|
// outb(PIC2_DATA, a2);
|
||||||
outb(PIC2_DATA, 0xFF);
|
outb(PIC2_DATA, a2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
.extern _syscall
|
.extern _syscall
|
||||||
.global syscall
|
.global syscall
|
||||||
syscall:
|
syscall:
|
||||||
sti
|
mov $0x10, %edx
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
mov %esp, %edx
|
||||||
|
mov $0x00f00000, %esp
|
||||||
|
push 0x10(%edx)
|
||||||
|
push 0x0C(%edx)
|
||||||
|
push 0x08(%edx)
|
||||||
|
push 0x04(%edx)
|
||||||
|
push 0x00(%edx)
|
||||||
|
|
||||||
push %edx
|
|
||||||
push %ecx
|
push %ecx
|
||||||
push %ebx
|
push %ebx
|
||||||
push %eax
|
push %eax
|
||||||
|
@ -13,6 +24,5 @@ call _syscall
|
||||||
pop %eax
|
pop %eax
|
||||||
pop %ebx
|
pop %ebx
|
||||||
pop %ecx
|
pop %ecx
|
||||||
pop %edx
|
|
||||||
iret
|
iret
|
||||||
|
|
||||||
|
|
|
@ -6,47 +6,43 @@ ENTRY(_start)
|
||||||
kernel image. */
|
kernel image. */
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
/* It used to be universally recommended to use 1M as a start offset,
|
. = 1M;
|
||||||
as it was effectively guaranteed to be available under BIOS systems.
|
|
||||||
However, UEFI has made things more complicated, and experimental data
|
_kernel_start = .;
|
||||||
strongly suggests that 2M is a safer place to load. In 2016, a new
|
.multiboot.data :
|
||||||
feature was introduced to the multiboot2 spec to inform bootloaders
|
{
|
||||||
that a kernel can be loaded anywhere within a range of addresses and
|
*(.multiboot.data)
|
||||||
will be able to relocate itself to run from such a loader-selected
|
}
|
||||||
address, in order to give the loader freedom in selecting a span of
|
|
||||||
memory which is verified to be available by the firmware, in order to
|
|
||||||
work around this issue. This does not use that feature, so 2M was
|
|
||||||
chosen as a safer option than the traditional 1M. */
|
|
||||||
. = 2M;
|
|
||||||
|
|
||||||
/* First put the multiboot header, as it is required to be put very early
|
.multiboot.text :
|
||||||
in the image or the bootloader won't recognize the file format.
|
{
|
||||||
Next we'll put the .text section. */
|
*(.multiboot.text)
|
||||||
.text BLOCK (4K) : ALIGN(4K)
|
}
|
||||||
|
|
||||||
|
. += 0xC0000000;
|
||||||
|
|
||||||
|
.text BLOCK (4K) : AT (ADDR (.text) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.multiboot)
|
|
||||||
*(.text)
|
*(.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read-only data. */
|
/* Read-only data. */
|
||||||
.rodata BLOCK(4K) : ALIGN(4M)
|
.rodata BLOCK(4K) : AT (ADDR (.rodata) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read-write data (initialized) */
|
/* Read-write data (initialized) */
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data BLOCK(4K) : AT (ADDR (.data) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read-write data (uninitialized) and stack */
|
/* Read-write data (uninitialized) and stack */
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
.bss BLOCK(4K) : AT (ADDR (.bss) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
}
|
}
|
||||||
|
_kernel_end = .;
|
||||||
/* The compiler may produce other sections, by default it will put them in
|
|
||||||
a segment with the same name. Simply add stuff here as needed. */
|
|
||||||
}
|
}
|
||||||
|
|
26
arch/i686/paging.c
Normal file
26
arch/i686/paging.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <kernel/paging.h>
|
||||||
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
|
struct x86_Page_Directory {
|
||||||
|
uint32_t address : 20;
|
||||||
|
uint8_t available_1 : 4;
|
||||||
|
bool page_Size: 1;
|
||||||
|
bool available_2: 1;
|
||||||
|
bool accesed: 1;
|
||||||
|
bool cache_disable: 1;
|
||||||
|
bool write_through: 1;
|
||||||
|
bool user_supervisor: 1;
|
||||||
|
bool read_write: 1;
|
||||||
|
bool present: 1;
|
||||||
|
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct x86_Page_Directory page_directory[1024] __attribute__((aligned(4096)));
|
||||||
|
|
||||||
|
void setup_paging() {
|
||||||
|
size_t size = sizeof(page_directory[0]);
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ void terminal_initialize(void)
|
||||||
terminal_row = 0;
|
terminal_row = 0;
|
||||||
terminal_column = 0;
|
terminal_column = 0;
|
||||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||||
terminal_buffer = (uint16_t*) 0xB8000;
|
terminal_buffer = (uint16_t*) 0xC03FF000;
|
||||||
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
||||||
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
const size_t index = y * VGA_WIDTH + x;
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
|
@ -117,11 +117,13 @@ void terminal_putchar(char c)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
|
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
|
||||||
if (++terminal_column == VGA_WIDTH) {
|
if (++terminal_column >= VGA_WIDTH) {
|
||||||
terminal_column = 0;
|
terminal_column = 0;
|
||||||
if (++terminal_row == VGA_HEIGHT)
|
terminal_row++;
|
||||||
terminal_scroll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (terminal_row >= VGA_HEIGHT)
|
||||||
|
terminal_scroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void terminal_write(const char* data, size_t size)
|
static void terminal_write(const char* data, size_t size)
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
.global jump_to_userspace
|
|
||||||
jump_to_userspace:
|
|
||||||
mov $0x20 | 0x3, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
movw %ax, %gs
|
|
||||||
pushl $0x20 | 0x3 /* SS*/
|
|
||||||
pushl $0x00c00100 /* ESP */
|
|
||||||
pushf /* EFLAGS */
|
|
||||||
popl %eax
|
|
||||||
orl $0x200, %eax
|
|
||||||
pushl %eax /* Set interrupts */
|
|
||||||
pushl $0x18 | 0x3 /* CS */
|
|
||||||
pushl $0x00800000 /* EIP */
|
|
||||||
iret
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void run_program(uint8_t* program, size_t length);
|
void run_program(uint8_t* code, size_t code_length, uint8_t* data, size_t data_length);
|
||||||
|
|
||||||
|
|
0
include/kernel/io/ata.h
Normal file
0
include/kernel/io/ata.h
Normal file
11
include/kernel/paging.h
Normal file
11
include/kernel/paging.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct PageDirectory {
|
||||||
|
size_t page_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PageTable {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup_paging();
|
40
include/kernel/task.h
Normal file
40
include/kernel/task.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct CPUState {
|
||||||
|
size_t eax;
|
||||||
|
size_t ebx;
|
||||||
|
size_t ecx;
|
||||||
|
size_t edx;
|
||||||
|
size_t eip;
|
||||||
|
size_t esp;
|
||||||
|
size_t ebp;
|
||||||
|
size_t edi;
|
||||||
|
size_t esi;
|
||||||
|
size_t cs;
|
||||||
|
size_t ds;
|
||||||
|
size_t eflags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
struct CPUState state;
|
||||||
|
};
|
||||||
|
|
||||||
|
void switch_task(
|
||||||
|
size_t eax,
|
||||||
|
size_t ebx,
|
||||||
|
size_t ecx,
|
||||||
|
size_t edx,
|
||||||
|
|
||||||
|
size_t ebp,
|
||||||
|
|
||||||
|
size_t esp_real,
|
||||||
|
|
||||||
|
size_t eip,
|
||||||
|
size_t cs,
|
||||||
|
size_t eflags,
|
||||||
|
size_t esp_fake,
|
||||||
|
size_t ds
|
||||||
|
);
|
||||||
|
void setup_tasks();
|
||||||
|
void add_task(struct Task task);
|
29
kernel/elf.c
29
kernel/elf.c
|
@ -3,6 +3,7 @@
|
||||||
#include <debugging.h>
|
#include <debugging.h>
|
||||||
#include <kernel/tty.h>
|
#include <kernel/tty.h>
|
||||||
#include <kernel/gdt.h>
|
#include <kernel/gdt.h>
|
||||||
|
#include <kernel/task.h>
|
||||||
#include <debugging.h>
|
#include <debugging.h>
|
||||||
|
|
||||||
static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
|
static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
|
||||||
|
@ -15,10 +16,30 @@ static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t s
|
||||||
|
|
||||||
extern void jump_to_userspace();
|
extern void jump_to_userspace();
|
||||||
|
|
||||||
void run_program(uint8_t* program, size_t length)
|
void run_program(uint8_t* code, size_t code_length, uint8_t* data, size_t data_length)
|
||||||
{
|
{
|
||||||
uint8_t* userland_code = (uint8_t*) 0x00800000;
|
uint8_t* userland_code = (uint8_t*) 0x00000000;
|
||||||
memcpy(userland_code, program, length);
|
uint8_t* userland_data = (uint8_t*) 0x00800000;
|
||||||
|
|
||||||
jump_to_userspace();
|
memcpy(userland_code, code, code_length);
|
||||||
|
memcpy(userland_data, data, data_length);
|
||||||
|
|
||||||
|
struct CPUState target = {
|
||||||
|
.eip = (size_t) userland_code,
|
||||||
|
.esp = 0x00000000,
|
||||||
|
.eax = 0,
|
||||||
|
.ebx = 0,
|
||||||
|
.ecx = 0,
|
||||||
|
.edx = 0,
|
||||||
|
.cs = 0x18 | 0x3,
|
||||||
|
.ds = 0x20 | 0x3,
|
||||||
|
.eflags = 0x0200,
|
||||||
|
.ebp = 0x00c00f00,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Task task = {
|
||||||
|
.state = target,
|
||||||
|
};
|
||||||
|
|
||||||
|
add_task(task);
|
||||||
}
|
}
|
||||||
|
|
0
kernel/io/fat.c
Normal file
0
kernel/io/fat.c
Normal file
|
@ -3,6 +3,8 @@
|
||||||
#include <kernel/elf.h>
|
#include <kernel/elf.h>
|
||||||
#include <kernel/pic.h>
|
#include <kernel/pic.h>
|
||||||
#include <kernel/heap.h>
|
#include <kernel/heap.h>
|
||||||
|
#include <kernel/task.h>
|
||||||
|
#include <kernel/paging.h>
|
||||||
|
|
||||||
#include <debugging.h>
|
#include <debugging.h>
|
||||||
|
|
||||||
|
@ -12,23 +14,36 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t program[] = {
|
uint8_t program[] = {
|
||||||
0xba, 0x01, 0x00, 0x00, 0x00, // mov 1, %edx
|
// 0xba, 0x01, 0x00, 0x00, 0x00, // mov 1, %edx
|
||||||
0xb8, 0xff, 0x00, 0x80, 0x00, // mov $buffer, %eax
|
0xb8, 0x00, 0x00, 0xC0, 0x00, // mov $buffer, %eax
|
||||||
0xcd, 0x80, // int 0x80
|
// 0xcd, 0x80, // int 0x80
|
||||||
0xba, 0x00, 0x00, 0x00, 0x00, // mov 0, %edx
|
0xb9, 0x00, 0x00, 0x00, 0x00, // mov 0, %ecx
|
||||||
0xcd, 0x80, // int 0x80
|
0xcd, 0x80, // int 0x80
|
||||||
0xb9, 0x00, 0x00, 0x80, 0x00, // mov $start, %ecx
|
0xb9, 0x00, 0x00, 0x80, 0x00, // mov $start, %ecx
|
||||||
0xff, 0xe1, // jmp *%ecx
|
0xff, 0xe1, // jmp *%ecx
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t data[] = "Hello From Userspace\n";
|
||||||
|
|
||||||
|
|
||||||
void kernel_main(void)
|
void kernel_main(void)
|
||||||
{
|
{
|
||||||
/* Initialize terminal interface */
|
/* Initialize terminal interface */
|
||||||
terminal_initialize();
|
terminal_initialize();
|
||||||
|
terminal_writestring("Hello from Kernelspace\n");
|
||||||
|
|
||||||
init_pic();
|
|
||||||
idt_init();
|
idt_init();
|
||||||
|
init_pic();
|
||||||
heap_init();
|
heap_init();
|
||||||
|
|
||||||
run_program(program, sizeof(program));
|
setup_tasks();
|
||||||
|
setup_paging();
|
||||||
|
|
||||||
|
asm("sti");
|
||||||
|
|
||||||
|
run_program(program, sizeof(program), data, sizeof(data));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
terminal_writestring("Hello from Kernelspace\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ static void print(char* buffer)
|
||||||
|
|
||||||
static void input(char* buffer)
|
static void input(char* buffer)
|
||||||
{
|
{
|
||||||
|
terminal_writestring("Input: ");
|
||||||
while (true) {
|
while (true) {
|
||||||
for (size_t i = 0; i < keyboard_buffer_top; i++) {
|
for (size_t i = 0; i < keyboard_buffer_top; i++) {
|
||||||
buffer[i] = keyboard_buffer[i];
|
buffer[i] = keyboard_buffer[i];
|
||||||
|
@ -22,9 +23,9 @@ static void input(char* buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _syscall(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
void _syscall(uint32_t a, uint32_t b, uint32_t c)
|
||||||
{
|
{
|
||||||
switch (d) {
|
switch (c) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
print((char*) a);
|
print((char*) a);
|
||||||
break;
|
break;
|
||||||
|
|
181
kernel/task.c
Normal file
181
kernel/task.c
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
#include <kernel/task.h>
|
||||||
|
#include <kernel/heap.h>
|
||||||
|
#include <kernel/tty.h>
|
||||||
|
|
||||||
|
struct Task* tasks;
|
||||||
|
size_t tasks_capacity;
|
||||||
|
size_t num_tasks;
|
||||||
|
|
||||||
|
size_t current_task = 0;
|
||||||
|
|
||||||
|
void setup_tasks()
|
||||||
|
{
|
||||||
|
tasks = malloc(sizeof(*tasks));
|
||||||
|
tasks_capacity = 1;
|
||||||
|
num_tasks = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_task(struct Task task)
|
||||||
|
{
|
||||||
|
asm("cli");
|
||||||
|
if (num_tasks == tasks_capacity) {
|
||||||
|
struct Task* temp = malloc(sizeof(*tasks) * tasks_capacity * 2);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_tasks; i++) {
|
||||||
|
temp[i] = tasks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks_capacity *= 2;
|
||||||
|
|
||||||
|
free(tasks);
|
||||||
|
tasks = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks[num_tasks] = task;
|
||||||
|
num_tasks++;
|
||||||
|
asm("sti");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ss;
|
||||||
|
size_t esp;
|
||||||
|
size_t eflags;
|
||||||
|
size_t cs;
|
||||||
|
size_t eip;
|
||||||
|
|
||||||
|
void jump_kernel(
|
||||||
|
size_t edi,
|
||||||
|
size_t esi,
|
||||||
|
size_t ebp,
|
||||||
|
size_t esp,
|
||||||
|
size_t ebx,
|
||||||
|
size_t edx,
|
||||||
|
size_t ecx,
|
||||||
|
size_t eax
|
||||||
|
);
|
||||||
|
void jump_user(
|
||||||
|
size_t edi,
|
||||||
|
size_t esi,
|
||||||
|
size_t ebp,
|
||||||
|
size_t esp,
|
||||||
|
size_t ebx,
|
||||||
|
size_t edx,
|
||||||
|
size_t ecx,
|
||||||
|
size_t eax
|
||||||
|
);
|
||||||
|
|
||||||
|
static void save_state(
|
||||||
|
size_t eax,
|
||||||
|
size_t ebx,
|
||||||
|
size_t ecx,
|
||||||
|
size_t edx,
|
||||||
|
|
||||||
|
size_t esp,
|
||||||
|
size_t ebp,
|
||||||
|
|
||||||
|
size_t esi,
|
||||||
|
size_t edi,
|
||||||
|
|
||||||
|
size_t eip,
|
||||||
|
|
||||||
|
size_t cs,
|
||||||
|
size_t ds,
|
||||||
|
|
||||||
|
size_t eflags
|
||||||
|
) {
|
||||||
|
struct CPUState state = {
|
||||||
|
.eax = eax,
|
||||||
|
.ebx = ebx,
|
||||||
|
.ecx = ecx,
|
||||||
|
.edx = edx,
|
||||||
|
|
||||||
|
.esp = esp,
|
||||||
|
.ebp = ebp,
|
||||||
|
|
||||||
|
.eip = eip,
|
||||||
|
|
||||||
|
.esi = esi,
|
||||||
|
.edi = edi,
|
||||||
|
|
||||||
|
.cs = cs,
|
||||||
|
.ds = ds,
|
||||||
|
|
||||||
|
.eflags = eflags,
|
||||||
|
};
|
||||||
|
|
||||||
|
tasks[current_task].state = state;
|
||||||
|
|
||||||
|
current_task++;
|
||||||
|
current_task %= num_tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_task() {
|
||||||
|
struct CPUState s = tasks[current_task].state;
|
||||||
|
|
||||||
|
ss = s.ds;
|
||||||
|
esp = s.esp;
|
||||||
|
eflags = s.eflags;
|
||||||
|
cs = s.cs;
|
||||||
|
eip = s.eip;
|
||||||
|
|
||||||
|
if ((cs & 3) == 0) {
|
||||||
|
jump_kernel(
|
||||||
|
s.edi,
|
||||||
|
s.esi,
|
||||||
|
s.ebp,
|
||||||
|
s.esp,
|
||||||
|
s.ebx,
|
||||||
|
s.edx,
|
||||||
|
s.ecx,
|
||||||
|
s.eax
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
jump_user(
|
||||||
|
s.edi,
|
||||||
|
s.esi,
|
||||||
|
s.ebp,
|
||||||
|
s.esp,
|
||||||
|
s.ebx,
|
||||||
|
s.edx,
|
||||||
|
s.ecx,
|
||||||
|
s.eax
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _switch_task(
|
||||||
|
size_t edi,
|
||||||
|
size_t esi,
|
||||||
|
size_t ebp,
|
||||||
|
size_t esp_current,
|
||||||
|
size_t ebx,
|
||||||
|
size_t edx,
|
||||||
|
size_t ecx,
|
||||||
|
size_t eax,
|
||||||
|
|
||||||
|
size_t eip_passed,
|
||||||
|
size_t cs_passed,
|
||||||
|
size_t eflags_passed,
|
||||||
|
size_t esp_passed,
|
||||||
|
size_t ds_passed
|
||||||
|
)
|
||||||
|
{
|
||||||
|
terminal_writestring("Switching task\n");
|
||||||
|
if (num_tasks == 0) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t ds;
|
||||||
|
if ((cs & 3) == 0) {
|
||||||
|
ds = 0x10;
|
||||||
|
esp_current = esp_current + sizeof(size_t) * 3;
|
||||||
|
} else {
|
||||||
|
ds = ds_passed;
|
||||||
|
esp_current = esp_passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_state(eax, ebx, ecx, edx, esp_current, ebp, esi, edi, eip_passed, cs_passed, ds, eflags_passed);
|
||||||
|
|
||||||
|
next_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue