Changess
This commit is contained in:
parent
bb441eaeb6
commit
887429636c
4
Makefile
4
Makefile
|
@ -31,12 +31,12 @@ LIB_OBJS=\
|
|||
$(ARCHDIR)/bootstrap.o \
|
||||
$(ARCHDIR)/tty.o \
|
||||
$(ARCHDIR)/strlib.o \
|
||||
$(ARCHDIR)/paging.o \
|
||||
$(ARCHDIR)/gdt.o \
|
||||
$(ARCHDIR)/interrupts/idt.o \
|
||||
$(ARCHDIR)/interrupts/interrupt.o \
|
||||
$(ARCHDIR)/interrupts/irq0.o \
|
||||
$(ARCHDIR)/interrupts/syscall.o \
|
||||
$(ARCHDIR)/gdt.o \
|
||||
$(ARCHDIR)/userland.o \
|
||||
$(ARCHDIR)/interrupts/pic.o \
|
||||
|
||||
OBJS=$(KERNEL_OBJS) $(LIB_OBJS)
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
/* Declare constants for the multiboot header. */
|
||||
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
||||
.set MEMINFO, 1<<1 /* provide memory map */
|
||||
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
|
||||
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
|
||||
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
|
||||
# Declare constants for the multiboot header.
|
||||
.set ALIGN, 1<<0 # align loaded modules on page boundaries
|
||||
.set MEMINFO, 1<<1 # provide memory map
|
||||
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
|
||||
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
|
||||
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
|
||||
|
||||
/*
|
||||
Declare a multiboot header that marks the program as a kernel. These are magic
|
||||
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
|
||||
# Declare a multiboot header that marks the program as a kernel.
|
||||
.section .multiboot.data, "aw"
|
||||
.align 4
|
||||
.long MAGIC
|
||||
.long FLAGS
|
||||
|
@ -31,100 +25,109 @@ stack is properly aligned and failure to align the stack will result in
|
|||
undefined behavior.
|
||||
*/
|
||||
|
||||
.section .bss
|
||||
.section .bss, "aw", @nobits
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
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
|
||||
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.
|
||||
*/
|
||||
.section .text
|
||||
.section .multiboot.text, "a"
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
/*
|
||||
The bootloader has loaded us into 32-bit protected mode on a x86
|
||||
machine. Interrupts are disabled. Paging is disabled. The processor
|
||||
state is as defined in the multiboot standard. The kernel has full
|
||||
control of the CPU. The kernel can only make use of hardware features
|
||||
and any code it provides as part of itself. There's no printf
|
||||
function, unless the kernel provides its own <stdio.h> header and a
|
||||
printf implementation. There are no security restrictions, no
|
||||
safeguards, no debugging mechanisms, only what the kernel provides
|
||||
itself. It has absolute and complete power over the
|
||||
machine.
|
||||
*/
|
||||
# Physical address of boot_page_table1.
|
||||
# TODO: I recall seeing some assembly that used a macro to do the
|
||||
# conversions to and from physical. Maybe this should be done in this
|
||||
# code as well?
|
||||
movl $(boot_page_table1 - 0xC0000000), %edi
|
||||
# First address to map is address 0.
|
||||
# TODO: Start at the first kernel page instead. Alternatively map the first
|
||||
# 1 MiB as it can be generally useful, and there's no need to
|
||||
# specially map the VGA buffer.
|
||||
movl $0, %esi
|
||||
# Map 1023 pages. The 1024th will be the VGA text buffer.
|
||||
movl $1023, %ecx
|
||||
|
||||
/*
|
||||
To set up a stack, we set the esp register to point to the top of the
|
||||
stack (as it grows downwards on x86 systems). This is necessarily done
|
||||
in assembly as languages such as C cannot function without a stack.
|
||||
*/
|
||||
1:
|
||||
# Only map the kernel.
|
||||
cmpl $_kernel_start, %esi
|
||||
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
|
||||
|
||||
cli
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
# Enter the high-level kernel.
|
||||
call kernel_main
|
||||
|
||||
.global keyboard_test
|
||||
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.
|
||||
*/
|
||||
# Infinite loop if the system has nothing more to do.
|
||||
cli
|
||||
1: hlt
|
||||
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
|
||||
|
|
|
@ -30,14 +30,20 @@ __attribute__((interrupt)) void divide_by_zero(struct interrupt_frame*)
|
|||
__attribute__((interrupt)) void general_protection_fault(struct interrupt_frame*)
|
||||
{
|
||||
terminal_writestring("GPF handler called\n");
|
||||
while (1) { }
|
||||
while (1) {
|
||||
asm("cli");
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void double_fault(struct interrupt_frame*)
|
||||
{
|
||||
stack_trace();
|
||||
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(struct interrupt_frame*)
|
||||
|
@ -48,6 +54,7 @@ __attribute__((interrupt)) void exception(struct interrupt_frame*)
|
|||
|
||||
__attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame*)
|
||||
{
|
||||
terminal_writestring("Keyboard Interrupt\n");
|
||||
uint8_t scancode = inb(0x60);
|
||||
handle_keyboard(scancode);
|
||||
outb(0x20, 0x20);
|
||||
|
@ -55,11 +62,13 @@ __attribute__((interrupt)) void keyboard_interrupt(struct interrupt_frame*)
|
|||
|
||||
__attribute__((interrupt)) void irq_1(struct interrupt_frame*)
|
||||
{
|
||||
terminal_writestring("PIC 1\n");
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void irq_2(struct interrupt_frame*)
|
||||
{
|
||||
terminal_writestring("PIC 2\n");
|
||||
outb(0xA0, 0x20);
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
|
|
|
@ -11,30 +11,34 @@
|
|||
.extern eip
|
||||
|
||||
irq0:
|
||||
push %esp
|
||||
pusha
|
||||
|
||||
push %ebp
|
||||
|
||||
push %edx
|
||||
push %ecx
|
||||
push %ebx
|
||||
push %eax
|
||||
mov $0x10, %eax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
call _switch_task
|
||||
|
||||
iret
|
||||
|
||||
jump_kernel:
|
||||
pop %eax /* pop return instruction */
|
||||
mov $0x20, %eax
|
||||
outb %al, $0x20
|
||||
|
||||
pop %eax
|
||||
pop %ebx
|
||||
pop %ecx
|
||||
pop %edx
|
||||
mov (ss), %eax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
pop %ebp
|
||||
pop %esp
|
||||
popa
|
||||
|
||||
mov (esp), %esp
|
||||
|
||||
push (ss)
|
||||
push (esp)
|
||||
push (eflags)
|
||||
push (cs)
|
||||
push (eip)
|
||||
|
@ -42,14 +46,16 @@ push (eip)
|
|||
iret
|
||||
|
||||
jump_user:
|
||||
pop %eax /* pop return instruction */
|
||||
mov $0x20, %eax
|
||||
outb %al, $0x20
|
||||
|
||||
pop %eax
|
||||
pop %ebx
|
||||
pop %ecx
|
||||
pop %edx
|
||||
mov (ss), %eax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
pop %ebp
|
||||
popa
|
||||
|
||||
push (ss)
|
||||
push (esp)
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
.extern _syscall
|
||||
.global 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 %ebx
|
||||
push %eax
|
||||
|
@ -13,6 +24,5 @@ call _syscall
|
|||
pop %eax
|
||||
pop %ebx
|
||||
pop %ecx
|
||||
pop %edx
|
||||
iret
|
||||
|
||||
|
|
|
@ -6,47 +6,43 @@ ENTRY(_start)
|
|||
kernel image. */
|
||||
SECTIONS
|
||||
{
|
||||
/* It used to be universally recommended to use 1M as a start offset,
|
||||
as it was effectively guaranteed to be available under BIOS systems.
|
||||
However, UEFI has made things more complicated, and experimental data
|
||||
strongly suggests that 2M is a safer place to load. In 2016, a new
|
||||
feature was introduced to the multiboot2 spec to inform bootloaders
|
||||
that a kernel can be loaded anywhere within a range of addresses and
|
||||
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;
|
||||
. = 1M;
|
||||
|
||||
/* First put the multiboot header, as it is required to be put very early
|
||||
in the image or the bootloader won't recognize the file format.
|
||||
Next we'll put the .text section. */
|
||||
.text BLOCK (4K) : ALIGN(4K)
|
||||
_kernel_start = .;
|
||||
.multiboot.data :
|
||||
{
|
||||
*(.multiboot.data)
|
||||
}
|
||||
|
||||
.multiboot.text :
|
||||
{
|
||||
*(.multiboot.text)
|
||||
}
|
||||
|
||||
. += 0xC0000000;
|
||||
|
||||
.text BLOCK (4K) : AT (ADDR (.text) - 0xC0000000)
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
/* Read-only data. */
|
||||
.rodata BLOCK(4K) : ALIGN(4M)
|
||||
.rodata BLOCK(4K) : AT (ADDR (.rodata) - 0xC0000000)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
.data BLOCK(4K) : AT (ADDR (.data) - 0xC0000000)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
/* Read-write data (uninitialized) and stack */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
.bss BLOCK(4K) : AT (ADDR (.bss) - 0xC0000000)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
_kernel_end = .;
|
||||
}
|
||||
|
|
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_column = 0;
|
||||
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 x = 0; x < VGA_WIDTH; x++) {
|
||||
const size_t index = y * VGA_WIDTH + x;
|
||||
|
@ -117,11 +117,13 @@ void terminal_putchar(char c)
|
|||
return;
|
||||
}
|
||||
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
|
||||
if (++terminal_column == VGA_WIDTH) {
|
||||
if (++terminal_column >= VGA_WIDTH) {
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
terminal_scroll();
|
||||
terminal_row++;
|
||||
}
|
||||
|
||||
if (terminal_row >= VGA_HEIGHT)
|
||||
terminal_scroll();
|
||||
}
|
||||
|
||||
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 <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);
|
||||
|
||||
|
|
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();
|
|
@ -9,6 +9,8 @@ struct CPUState {
|
|||
size_t eip;
|
||||
size_t esp;
|
||||
size_t ebp;
|
||||
size_t edi;
|
||||
size_t esi;
|
||||
size_t cs;
|
||||
size_t ds;
|
||||
size_t eflags;
|
||||
|
|
13
kernel/elf.c
13
kernel/elf.c
|
@ -16,14 +16,17 @@ static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t s
|
|||
|
||||
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;
|
||||
memcpy(userland_code, program, length);
|
||||
uint8_t* userland_code = (uint8_t*) 0x00000000;
|
||||
uint8_t* userland_data = (uint8_t*) 0x00800000;
|
||||
|
||||
memcpy(userland_code, code, code_length);
|
||||
memcpy(userland_data, data, data_length);
|
||||
|
||||
struct CPUState target = {
|
||||
.eip = (size_t) userland_code,
|
||||
.esp = 0x00c00100,
|
||||
.esp = 0x00000000,
|
||||
.eax = 0,
|
||||
.ebx = 0,
|
||||
.ecx = 0,
|
||||
|
@ -31,7 +34,7 @@ void run_program(uint8_t* program, size_t length)
|
|||
.cs = 0x18 | 0x3,
|
||||
.ds = 0x20 | 0x3,
|
||||
.eflags = 0x0200,
|
||||
.ebp = 0x00c00100,
|
||||
.ebp = 0x00c00f00,
|
||||
};
|
||||
|
||||
struct Task task = {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <kernel/pic.h>
|
||||
#include <kernel/heap.h>
|
||||
#include <kernel/task.h>
|
||||
#include <kernel/paging.h>
|
||||
|
||||
#include <debugging.h>
|
||||
|
||||
|
@ -13,33 +14,36 @@
|
|||
#endif
|
||||
|
||||
uint8_t program[] = {
|
||||
0xba, 0x01, 0x00, 0x00, 0x00, // mov 1, %edx
|
||||
0xb8, 0xff, 0x00, 0x80, 0x00, // mov $buffer, %eax
|
||||
// 0xba, 0x01, 0x00, 0x00, 0x00, // mov 1, %edx
|
||||
0xb8, 0x00, 0x00, 0xC0, 0x00, // mov $buffer, %eax
|
||||
// 0xcd, 0x80, // int 0x80
|
||||
0xb9, 0x00, 0x00, 0x00, 0x00, // mov 0, %ecx
|
||||
0xcd, 0x80, // int 0x80
|
||||
0xba, 0x00, 0x00, 0x00, 0x00, // mov 0, %edx
|
||||
0xcd, 0x80, // int 0x80
|
||||
0xcd, 0x20, // int 0x20
|
||||
0xb9, 0x00, 0x00, 0x80, 0x00, // mov $start, %ecx
|
||||
0xff, 0xe1, // jmp *%ecx
|
||||
};
|
||||
|
||||
uint8_t data[] = "Hello From Userspace\n";
|
||||
|
||||
|
||||
void kernel_main(void)
|
||||
{
|
||||
/* Initialize terminal interface */
|
||||
terminal_initialize();
|
||||
terminal_writestring("Hello from Kernelspace\n");
|
||||
|
||||
idt_init();
|
||||
init_pic();
|
||||
heap_init();
|
||||
|
||||
setup_tasks();
|
||||
setup_paging();
|
||||
|
||||
asm("sti");
|
||||
|
||||
run_program(program, sizeof(program));
|
||||
run_program(program, sizeof(program), data, sizeof(data));
|
||||
|
||||
while (true) {
|
||||
asm("hlt");
|
||||
terminal_writestring("Hello from Kernelspace\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ static void print(char* buffer)
|
|||
|
||||
static void input(char* buffer)
|
||||
{
|
||||
terminal_writestring("Input: ");
|
||||
while (true) {
|
||||
for (size_t i = 0; i < keyboard_buffer_top; 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:
|
||||
print((char*) a);
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <kernel/task.h>
|
||||
#include <kernel/heap.h>
|
||||
#include <kernel/tty.h>
|
||||
|
||||
struct Task* tasks;
|
||||
size_t tasks_capacity;
|
||||
|
@ -16,6 +17,7 @@ void setup_tasks()
|
|||
|
||||
void add_task(struct Task task)
|
||||
{
|
||||
asm("cli");
|
||||
if (num_tasks == tasks_capacity) {
|
||||
struct Task* temp = malloc(sizeof(*tasks) * tasks_capacity * 2);
|
||||
|
||||
|
@ -31,6 +33,7 @@ void add_task(struct Task task)
|
|||
|
||||
tasks[num_tasks] = task;
|
||||
num_tasks++;
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
size_t ss;
|
||||
|
@ -39,8 +42,26 @@ size_t eflags;
|
|||
size_t cs;
|
||||
size_t eip;
|
||||
|
||||
void jump_kernel(size_t eax, size_t ebx, size_t ecx, size_t edx, size_t ebp, size_t esp);
|
||||
void jump_user(size_t eax, size_t ebx, size_t ecx, size_t edx, size_t ebp);
|
||||
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,
|
||||
|
@ -51,6 +72,9 @@ static void save_state(
|
|||
size_t esp,
|
||||
size_t ebp,
|
||||
|
||||
size_t esi,
|
||||
size_t edi,
|
||||
|
||||
size_t eip,
|
||||
|
||||
size_t cs,
|
||||
|
@ -69,6 +93,9 @@ static void save_state(
|
|||
|
||||
.eip = eip,
|
||||
|
||||
.esi = esi,
|
||||
.edi = edi,
|
||||
|
||||
.cs = cs,
|
||||
.ds = ds,
|
||||
|
||||
|
@ -91,21 +118,39 @@ void next_task() {
|
|||
eip = s.eip;
|
||||
|
||||
if ((cs & 3) == 0) {
|
||||
jump_kernel(s.eax, s.ebx, s.ecx, s.edx, s.ebp, s.esp);
|
||||
jump_kernel(
|
||||
s.edi,
|
||||
s.esi,
|
||||
s.ebp,
|
||||
s.esp,
|
||||
s.ebx,
|
||||
s.edx,
|
||||
s.ecx,
|
||||
s.eax
|
||||
);
|
||||
} else {
|
||||
jump_user(s.eax, s.ebx, s.ecx, s.edx, s.ebp);
|
||||
jump_user(
|
||||
s.edi,
|
||||
s.esi,
|
||||
s.ebp,
|
||||
s.esp,
|
||||
s.ebx,
|
||||
s.edx,
|
||||
s.ecx,
|
||||
s.eax
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _switch_task(
|
||||
size_t eax,
|
||||
size_t ebx,
|
||||
size_t ecx,
|
||||
size_t edx,
|
||||
|
||||
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,
|
||||
|
@ -114,6 +159,7 @@ void _switch_task(
|
|||
size_t ds_passed
|
||||
)
|
||||
{
|
||||
terminal_writestring("Switching task\n");
|
||||
if (num_tasks == 0) {
|
||||
return;
|
||||
};
|
||||
|
@ -127,13 +173,7 @@ void _switch_task(
|
|||
esp_current = esp_passed;
|
||||
}
|
||||
|
||||
ss = ds_passed;
|
||||
esp = esp_passed;
|
||||
eflags = eflags_passed;
|
||||
cs = cs_passed;
|
||||
eip = eip_passed;
|
||||
|
||||
save_state(eax, ebx, ecx, edx, esp, ebp, eip_passed, cs_passed, ds, eflags_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