initial release.
This commit is contained in:
commit
ad1a74fb85
27 changed files with 2058 additions and 0 deletions
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Gitignore
|
||||||
|
|
||||||
|
obj/*
|
||||||
|
kernel
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
22
LICENSE
Normal file
22
LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Felix Queißner
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
29
Makefile
Normal file
29
Makefile
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
SRCS = $(shell find -name '*.[cS]')
|
||||||
|
OBJS = $(addsuffix .o,$(basename $(SRCS)))
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
LD = ld
|
||||||
|
|
||||||
|
# define nullptr, but not NULL.
|
||||||
|
CFLAGS = -m32 -Dnullptr=0
|
||||||
|
ASFLAGS =
|
||||||
|
CCFLAGS = -g -std=c11 -Wall -g -fno-stack-protector -ffreestanding
|
||||||
|
LDFLAGS = -g -melf_i386 -Tkernel.ld
|
||||||
|
|
||||||
|
kernel: $(OBJS)
|
||||||
|
$(LD) $(LDFLAGS) -o $@ $(addprefix obj/, $(notdir $^))
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) $(CCFLAGS) -c -o $(addprefix obj/, $(notdir $@)) $^
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(CC) $(CFLAGS) $(ASFLAGS) -c -o $(addprefix obj/, $(notdir $@)) $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(addprefix obj/, $(notdir $(OBJS)))
|
||||||
|
|
||||||
|
run:
|
||||||
|
qemu-system-i386 -kernel kernel
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
.PHONY: run
|
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# KernelTemplate
|
||||||
|
A pretty primitive kernel base with physical and virtual memory management and a console.
|
88
asm/intr_common_handler.S
Normal file
88
asm/intr_common_handler.S
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
.macro intr_stub nr
|
||||||
|
.global intr_stub_\nr
|
||||||
|
intr_stub_\nr:
|
||||||
|
pushl $0
|
||||||
|
pushl $\nr
|
||||||
|
jmp intr_common_handler
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro intr_stub_error_code nr
|
||||||
|
.global intr_stub_\nr
|
||||||
|
intr_stub_\nr:
|
||||||
|
pushl $\nr
|
||||||
|
jmp intr_common_handler
|
||||||
|
.endm
|
||||||
|
|
||||||
|
// Exceptions
|
||||||
|
intr_stub 0
|
||||||
|
intr_stub 1
|
||||||
|
intr_stub 2
|
||||||
|
intr_stub 3
|
||||||
|
intr_stub 4
|
||||||
|
intr_stub 5
|
||||||
|
intr_stub 6
|
||||||
|
intr_stub 7
|
||||||
|
intr_stub_error_code 8
|
||||||
|
intr_stub 9
|
||||||
|
intr_stub_error_code 10
|
||||||
|
intr_stub_error_code 11
|
||||||
|
intr_stub_error_code 12
|
||||||
|
intr_stub_error_code 13
|
||||||
|
intr_stub_error_code 14
|
||||||
|
intr_stub 15
|
||||||
|
intr_stub 16
|
||||||
|
intr_stub_error_code 17
|
||||||
|
intr_stub 18
|
||||||
|
|
||||||
|
// IRQs
|
||||||
|
intr_stub 32
|
||||||
|
intr_stub 33
|
||||||
|
intr_stub 34
|
||||||
|
intr_stub 35
|
||||||
|
intr_stub 36
|
||||||
|
intr_stub 37
|
||||||
|
intr_stub 38
|
||||||
|
intr_stub 39
|
||||||
|
intr_stub 40
|
||||||
|
intr_stub 41
|
||||||
|
intr_stub 42
|
||||||
|
intr_stub 43
|
||||||
|
intr_stub 44
|
||||||
|
intr_stub 45
|
||||||
|
intr_stub 46
|
||||||
|
intr_stub 47
|
||||||
|
|
||||||
|
// System call
|
||||||
|
intr_stub 48
|
||||||
|
|
||||||
|
intr_stub 80
|
||||||
|
|
||||||
|
.extern intr_routine
|
||||||
|
intr_common_handler:
|
||||||
|
// Save additional cpu state
|
||||||
|
push %ebp
|
||||||
|
push %edi
|
||||||
|
push %esi
|
||||||
|
push %edx
|
||||||
|
push %ecx
|
||||||
|
push %ebx
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
// Call interrupt handler
|
||||||
|
push %esp
|
||||||
|
call intr_routine
|
||||||
|
add $4, %esp
|
||||||
|
|
||||||
|
// Restore cpu state
|
||||||
|
pop %eax
|
||||||
|
pop %ebx
|
||||||
|
pop %ecx
|
||||||
|
pop %edx
|
||||||
|
pop %esi
|
||||||
|
pop %edi
|
||||||
|
pop %ebp
|
||||||
|
|
||||||
|
// Fehlercode und Interruptnummer vom Stack nehmen
|
||||||
|
add $8, %esp
|
||||||
|
|
||||||
|
iret
|
9
asm/multiboot.S
Normal file
9
asm/multiboot.S
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.section multiboot
|
||||||
|
#define MB_MAGIC 0x1badb002
|
||||||
|
#define MB_FLAGS 0x0
|
||||||
|
#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS)
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.int MB_MAGIC
|
||||||
|
.int MB_FLAGS
|
||||||
|
.int MB_CHECKSUM
|
25
asm/start.S
Normal file
25
asm/start.S
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
// C-Einstiegspunkt
|
||||||
|
.extern init
|
||||||
|
|
||||||
|
// .global für Sichtbarkeit im Linker (invers zu static aus C)
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
// Init stack
|
||||||
|
mov $kernel_stack, %esp
|
||||||
|
|
||||||
|
// Start Kernel
|
||||||
|
push %ebx
|
||||||
|
call init
|
||||||
|
|
||||||
|
// Halte an, no matter what
|
||||||
|
_stop:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp _stop
|
||||||
|
|
||||||
|
// 16 KB Stackspace
|
||||||
|
.section .bss
|
||||||
|
.space 16384
|
||||||
|
kernel_stack:
|
39
kernel.ld
Normal file
39
kernel.ld
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* Bei _start soll die Ausfuehrung losgehen */
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hier wird festgelegt, in welcher Reihenfolge welche Sektionen in die Binary
|
||||||
|
* geschrieben werden sollen
|
||||||
|
*/
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Startpunkt des Kernels
|
||||||
|
*/
|
||||||
|
. = 0x100000;
|
||||||
|
|
||||||
|
/* Kernel Start Punkt */
|
||||||
|
kernelStart = .;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two text sections: .text and .multiboot
|
||||||
|
* Multiboot must be at the start of the kernel
|
||||||
|
*/
|
||||||
|
.text : {
|
||||||
|
*(multiboot)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
.data ALIGN(4096) : {
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
.rodata ALIGN(4096) : {
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
.bss ALIGN(4096) : {
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the end of the kernel to the page size */
|
||||||
|
. = ALIGN(4096);
|
||||||
|
kernelEnd = .;
|
||||||
|
}
|
222
src/console.c
Normal file
222
src/console.c
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#include "console.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
csDefault = 0,
|
||||||
|
csSetColor,
|
||||||
|
csSetForeground,
|
||||||
|
csSetBackground,
|
||||||
|
} ConsoleState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int foreground:4;
|
||||||
|
int background:4;
|
||||||
|
} ConsoleColor;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
uint8_t color;
|
||||||
|
} ConsoleChar;
|
||||||
|
|
||||||
|
static int cursorX = 0;
|
||||||
|
static int cursorY = 0;
|
||||||
|
static ConsoleColor color = { COLOR_LIGHTGRAY, COLOR_BLACK };
|
||||||
|
static ConsoleState state = csDefault;
|
||||||
|
|
||||||
|
static ConsoleChar *screen = (ConsoleChar*)0xB8000;
|
||||||
|
|
||||||
|
void ksetpos(int x, int y)
|
||||||
|
{
|
||||||
|
if((x >= 0) && (x < CONSOLE_WIDTH))
|
||||||
|
{
|
||||||
|
cursorX = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((y >= 0) && (y < CONSOLE_HEIGHT))
|
||||||
|
{
|
||||||
|
cursorY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kgetpos(int *x, int *y)
|
||||||
|
{
|
||||||
|
if(x != nullptr) *x = cursorX;
|
||||||
|
if(y != nullptr) *y = cursorY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ksetcolor(int background, int foreground)
|
||||||
|
{
|
||||||
|
if(background >= 0)
|
||||||
|
{
|
||||||
|
background &= 0xF;
|
||||||
|
color.background = background;
|
||||||
|
}
|
||||||
|
if(foreground >= 0)
|
||||||
|
{
|
||||||
|
foreground &= 0xF;
|
||||||
|
color.foreground = foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kgetcolor(int *background, int *foreground)
|
||||||
|
{
|
||||||
|
if(background != nullptr) *background = color.background;
|
||||||
|
if(foreground != nullptr) *foreground = color.foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kclear(void)
|
||||||
|
{
|
||||||
|
cursorX = 0;
|
||||||
|
cursorY = 0;
|
||||||
|
for(size_t i = 0; i < (CONSOLE_WIDTH * CONSOLE_HEIGHT); i++)
|
||||||
|
{
|
||||||
|
screen[i].c = ' '; // Fill screen with spaces
|
||||||
|
screen[i].color = *((uint8_t*)&color); // Set screen to current color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void newline()
|
||||||
|
{
|
||||||
|
cursorX = 0;
|
||||||
|
cursorY += 1;
|
||||||
|
if(cursorY == (CONSOLE_HEIGHT))
|
||||||
|
{
|
||||||
|
// We need to scroll here:
|
||||||
|
|
||||||
|
// Copy everything line on the screen to the previous line
|
||||||
|
for(int line = 1; line < CONSOLE_HEIGHT; line++)
|
||||||
|
{
|
||||||
|
memcpy(&screen[CONSOLE_WIDTH * (line-1)], &screen[CONSOLE_WIDTH * line], CONSOLE_WIDTH * sizeof(ConsoleChar));
|
||||||
|
}
|
||||||
|
// Fill the last line with blanks
|
||||||
|
for(int i = 0; i < CONSOLE_WIDTH; i++)
|
||||||
|
{
|
||||||
|
screen[CONSOLE_WIDTH * (CONSOLE_HEIGHT-1)+i].c = ' ';
|
||||||
|
screen[CONSOLE_WIDTH * (CONSOLE_HEIGHT-1)+i].color = *((uint8_t*)&color);
|
||||||
|
}
|
||||||
|
// Reset y cursor position to previous line (we don't want to write out of bounds)
|
||||||
|
cursorY -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kputc(char c)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case csSetColor:
|
||||||
|
{
|
||||||
|
color = *((ConsoleColor*)&c);
|
||||||
|
state = csDefault;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case csSetForeground:
|
||||||
|
{
|
||||||
|
color.foreground = c & 0xF;
|
||||||
|
state = csDefault;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case csSetBackground:
|
||||||
|
{
|
||||||
|
color.background = c & 0xF;
|
||||||
|
state = csDefault;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case csDefault:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int idx = CONSOLE_WIDTH * cursorY + cursorX;
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '\x11':
|
||||||
|
state = csSetColor;
|
||||||
|
return;
|
||||||
|
case '\x12':
|
||||||
|
state = csSetForeground;
|
||||||
|
return;
|
||||||
|
case '\x13':
|
||||||
|
state = csSetBackground;
|
||||||
|
return;
|
||||||
|
case '\r':
|
||||||
|
// Ignore carriage return
|
||||||
|
return;
|
||||||
|
case '\n':
|
||||||
|
newline();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
screen[idx].color = *((uint8_t*)&color); // Set screen to current color
|
||||||
|
screen[idx].c = c;
|
||||||
|
|
||||||
|
cursorX += 1;
|
||||||
|
if(cursorX >= CONSOLE_WIDTH)
|
||||||
|
{
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kputs(const char *str)
|
||||||
|
{
|
||||||
|
while(*str)
|
||||||
|
{
|
||||||
|
kputc(*str);
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kprintf(const char *format, ...)
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
while(*format != 0)
|
||||||
|
{
|
||||||
|
char c = *(format++);
|
||||||
|
if(c == '%')
|
||||||
|
{
|
||||||
|
c = *(format++);
|
||||||
|
int i;
|
||||||
|
char *str;
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
i = va_arg(vl, int);
|
||||||
|
kputs(itoa(i, buffer, 10));
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
i = va_arg(vl, int);
|
||||||
|
kputs(itoa(i, buffer, 2));
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
i = va_arg(vl, int);
|
||||||
|
kputs(itoa(i, buffer, 16));
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
c = va_arg(vl, int);
|
||||||
|
kputc(c);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
str = va_arg(vl, char*);
|
||||||
|
kputs(str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
kputc(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kputc(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(vl);
|
||||||
|
}
|
74
src/console.h
Normal file
74
src/console.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CONSOLE_WIDTH 80
|
||||||
|
#define CONSOLE_HEIGHT 25
|
||||||
|
|
||||||
|
#define COLOR_BLACK 0x0
|
||||||
|
#define COLOR_BLUE 0x1
|
||||||
|
#define COLOR_GREEN 0x2
|
||||||
|
#define COLOR_CYAN 0x3
|
||||||
|
#define COLOR_RED 0x4
|
||||||
|
#define COLOR_MAGENTA 0x5
|
||||||
|
#define COLOR_BROWN 0x6
|
||||||
|
#define COLOR_LIGHTGRAY 0x7
|
||||||
|
#define COLOR_GRAY 0x8
|
||||||
|
#define COLOR_LIGHTBLUE 0x9
|
||||||
|
#define COLOR_LIGHTGREEN 0xA
|
||||||
|
#define COLOR_LIGHTRED 0xC
|
||||||
|
#define COLOR_LIGHTMAGENTA 0xD
|
||||||
|
#define COLOR_YELLOW 0xE
|
||||||
|
#define COLOR_WHITE 0xF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the cursor position.
|
||||||
|
* @param x Distance of the cursor from the left border.
|
||||||
|
* @param y Distance of the cursor from the top border.
|
||||||
|
*/
|
||||||
|
void ksetpos(int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the cursor position.
|
||||||
|
* @param x Pointer to an integer that should store the distance of the cursor from the left border.
|
||||||
|
* @param y Pointer to an integer that should store the distance of the cursor from the top border.
|
||||||
|
*/
|
||||||
|
void kgetpos(int *x, int *y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the color of the console.
|
||||||
|
* @param foreground The foreground color.
|
||||||
|
* @param background The background color.
|
||||||
|
*/
|
||||||
|
void ksetcolor(int background, int foreground);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the color of the console.
|
||||||
|
* @param foreground A pointer to the foreground color.
|
||||||
|
* @param background A pointer to the background color.
|
||||||
|
*/
|
||||||
|
void kgetcolor(int *background, int *foreground);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the screen and sets the cursor to the top left corner.
|
||||||
|
*/
|
||||||
|
void kclear(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Puts a character onto the screen.
|
||||||
|
* @param c The character that should be printed.
|
||||||
|
*/
|
||||||
|
void kputc(char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints a string onto the screen.
|
||||||
|
* @param A null-terminated string that should be printed.
|
||||||
|
*/
|
||||||
|
void kputs(const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints a formatted string onto the screen.
|
||||||
|
* @param format The format string that will be printed in formatted version.
|
||||||
|
* @param ... The format parameters that will be used to print the string.
|
||||||
|
*/
|
||||||
|
void kprintf(const char *format, ...);
|
24
src/cpustate.h
Normal file
24
src/cpustate.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
#include "inttypes.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// Saved by interrupt routine
|
||||||
|
uint32_t eax;
|
||||||
|
uint32_t ebx;
|
||||||
|
uint32_t ecx;
|
||||||
|
uint32_t edx;
|
||||||
|
uint32_t esi;
|
||||||
|
uint32_t edi;
|
||||||
|
uint32_t ebp;
|
||||||
|
|
||||||
|
uint32_t intr;
|
||||||
|
uint32_t error;
|
||||||
|
|
||||||
|
// Saved by CPU
|
||||||
|
uint32_t eip;
|
||||||
|
uint32_t cs;
|
||||||
|
uint32_t eflags;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t ss;
|
||||||
|
} CpuState;
|
149
src/init.c
Normal file
149
src/init.c
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "pmm.h"
|
||||||
|
#include "vmm.h"
|
||||||
|
|
||||||
|
void die(const char *msg)
|
||||||
|
{
|
||||||
|
kputs("\n");
|
||||||
|
ksetcolor(COLOR_RED, COLOR_WHITE);
|
||||||
|
kputs(msg);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("cli; hlt;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksleep(uint32_t time)
|
||||||
|
{
|
||||||
|
for(uint32_t i = 0; i < time; i++)
|
||||||
|
{
|
||||||
|
// BURN, CPU, BURN!
|
||||||
|
for(volatile size_t i = 0; i < 40000000; i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_test()
|
||||||
|
{
|
||||||
|
char buffer[64];
|
||||||
|
kputs("itoa test:\n");
|
||||||
|
kputs("10 = "); kputs(itoa(10, buffer, 10)); kputc('\n');
|
||||||
|
kputs("10 = 0x"); kputs(itoa(10, buffer, 16)); kputc('\n');
|
||||||
|
kputs("10 = 0b"); kputs(itoa(10, buffer, 2)); kputc('\n');
|
||||||
|
kputs("10 = 0o"); kputs(itoa(10, buffer, 8)); kputc('\n');
|
||||||
|
|
||||||
|
kputs("printf test:\n");
|
||||||
|
kprintf("This %s %c test line.\n", "is", 'a');
|
||||||
|
kprintf("Numbers: %d %i %x %b\n", 15, 15, 15, 15);
|
||||||
|
|
||||||
|
/*
|
||||||
|
kputs("scroll-test:\n");
|
||||||
|
for(int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
kprintf("They see me scrolling, they hating! %i\n", i);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < 272; i++)
|
||||||
|
{
|
||||||
|
kprintf("x");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumpMB(const MultibootStructure *mbHeader)
|
||||||
|
{
|
||||||
|
kputs("Multiboot Information:\n");
|
||||||
|
if(mbHeader->flags & MB_MEMSIZE)
|
||||||
|
{
|
||||||
|
kprintf("Lower Memory: %d kB\n", mbHeader->memLower);
|
||||||
|
kprintf("Upper Memory: %d kB\n", mbHeader->memUpper);
|
||||||
|
}
|
||||||
|
// TODO: MB_BOOTDEVICE
|
||||||
|
if(mbHeader->flags & MB_COMMANDLINE)
|
||||||
|
{
|
||||||
|
kprintf("Commandline: %s\n", mbHeader->commandline);
|
||||||
|
}
|
||||||
|
if(mbHeader->flags & MB_MODULES)
|
||||||
|
{
|
||||||
|
const MultibootModule *mod = (const MultibootModule *)mbHeader->modules;
|
||||||
|
for(size_t i = 0; i < mbHeader->moduleCount; i++)
|
||||||
|
{
|
||||||
|
kprintf("Module %s [%d - %d]\n", mod[i].name, mod[i].start, mod[i].end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mbHeader->flags & MB_SYMS_AOUT)
|
||||||
|
{
|
||||||
|
kputs("Kernel File Format: a.out\n");
|
||||||
|
}
|
||||||
|
if(mbHeader->flags & MB_SYMS_ELF)
|
||||||
|
{
|
||||||
|
kputs("Kernel File Format: ELF\n");
|
||||||
|
}
|
||||||
|
if(mbHeader->flags & MB_MEMORYMAP)
|
||||||
|
{
|
||||||
|
uintptr_t it = mbHeader->memoryMap;
|
||||||
|
kprintf("Memory Map: %d entries\n", mbHeader->memoryMapLength);
|
||||||
|
for(size_t i = 0; i < mbHeader->memoryMapLength; i++)
|
||||||
|
{
|
||||||
|
const MultibootMemoryMap *mmap = (const MultibootMemoryMap *)it;
|
||||||
|
if(mmap->type == 1)
|
||||||
|
kprintf("Memory Map: [%d + %d] %s\n", (uint32_t)mmap->base, (uint32_t)mmap->length, mmap->type == 1 ? "free" : "preserved");
|
||||||
|
it += mmap->entry_size + 4; // Stupid offset :P
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: MB_DRIVES
|
||||||
|
// TODO: MB_CONFIG_TABLE
|
||||||
|
if(mbHeader->flags & MB_BOOTLOADER_NAME)
|
||||||
|
{
|
||||||
|
kprintf("Bootloader Name: %s\n", mbHeader->bootLoaderName);
|
||||||
|
}
|
||||||
|
// TODO: MB_APS_TABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const MultibootStructure *mbHeader)
|
||||||
|
{
|
||||||
|
(void)debug_test;
|
||||||
|
(void)dumpMB;
|
||||||
|
|
||||||
|
ksetcolor(COLOR_BLACK, COLOR_LIGHTGRAY);
|
||||||
|
kclear();
|
||||||
|
kputs("Welcome to \x12\x05nucleo\x12\x07!\n");
|
||||||
|
|
||||||
|
//dumpMB(mbHeader);
|
||||||
|
|
||||||
|
kputs("Initialize physical memory management: ");
|
||||||
|
pmm_init(mbHeader);
|
||||||
|
kputs("success.\n");
|
||||||
|
// uint32_t freeMem = pmm_calc_free();
|
||||||
|
//kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20);
|
||||||
|
|
||||||
|
ksleep(1);
|
||||||
|
|
||||||
|
kputs("Initialize virtual memory management: ");
|
||||||
|
vmm_init();
|
||||||
|
kputs("success.\n");
|
||||||
|
|
||||||
|
kputs("Initialize interrupts: ");
|
||||||
|
intr_init();
|
||||||
|
kputs("success.\n");
|
||||||
|
|
||||||
|
kputs("Enable hw interrupts: ");
|
||||||
|
irq_enable();
|
||||||
|
kputs("success.\n");
|
||||||
|
|
||||||
|
//__asm__ volatile("sti");
|
||||||
|
|
||||||
|
kputs("Prepare heap memory: ");
|
||||||
|
for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096)
|
||||||
|
{
|
||||||
|
vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM);
|
||||||
|
}
|
||||||
|
kputs("success.\n");
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
kputs("x");
|
||||||
|
ksleep(1);
|
||||||
|
}
|
||||||
|
}
|
253
src/interrupts.c
Normal file
253
src/interrupts.c
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "cpustate.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
#define GDT_ENTRIES 5
|
||||||
|
#define IDT_ENTRIES 256
|
||||||
|
|
||||||
|
static uint64_t gdt[GDT_ENTRIES];
|
||||||
|
static uint64_t idt[IDT_ENTRIES];
|
||||||
|
|
||||||
|
static const char *interruptNames[] = {
|
||||||
|
"Divide-by-zero Error",// 0 (0x0) Fault #DE No
|
||||||
|
"Debug",// 1 (0x1) Fault/Trap #DB No
|
||||||
|
"Non-maskable Interrupt",// 2 (0x2) Interrupt - No
|
||||||
|
"Breakpoint",// 3 (0x3) Trap #BP No
|
||||||
|
"Overflow",// 4 (0x4) Trap #OF No
|
||||||
|
"Bound Range Exceeded",// 5 (0x5) Fault #BR No
|
||||||
|
"Invalid Opcode",// 6 (0x6) Fault #UD No
|
||||||
|
"Device Not Available",// 7 (0x7) Fault #NM No
|
||||||
|
"Double Fault",// 8 (0x8) Abort #DF Yes
|
||||||
|
"Coprocessor Segment Overrun",// 9 (0x9) Fault - No
|
||||||
|
"Invalid TSS",// 10 (0xA) Fault #TS Yes
|
||||||
|
"Segment Not Present",// 11 (0xB) Fault #NP Yes
|
||||||
|
"Stack-Segment Fault",// 12 (0xC) Fault #SS Yes
|
||||||
|
"General Protection Fault",// 13 (0xD) Fault #GP Yes
|
||||||
|
"Page Fault",// 14 (0xE) Fault #PF Yes
|
||||||
|
"Reserved",// 15 (0xF) - - No
|
||||||
|
"x87 Floating-Point Exception",// 16 (0x10) Fault #MF No
|
||||||
|
"Alignment Check",// 17 (0x11) Fault #AC Yes
|
||||||
|
"Machine Check",// 18 (0x12) Abort #MC No
|
||||||
|
"SIMD Floating-Point Exception",// 19 (0x13) Fault #XM/#XF No
|
||||||
|
"Virtualization Exception",// 20 (0x14) Fault #VE No
|
||||||
|
"Reserved 21",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 22",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 23",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 24",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 25",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 26",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 27",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 28",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Reserved 29",// 21-29 (0x15-0x1D) - - No
|
||||||
|
"Security Exception",// 30 (0x1E) - #SX Yes
|
||||||
|
"Reserved 31",// 31 (0x1F) - - No
|
||||||
|
"IRQ 0",
|
||||||
|
"IRQ 1",
|
||||||
|
"IRQ 2",
|
||||||
|
"IRQ 3",
|
||||||
|
"IRQ 4",
|
||||||
|
"IRQ 5",
|
||||||
|
"IRQ 6",
|
||||||
|
"IRQ 7",
|
||||||
|
"IRQ 8",
|
||||||
|
"IRQ 9",
|
||||||
|
"IRQ 10",
|
||||||
|
"IRQ 11",
|
||||||
|
"IRQ 12",
|
||||||
|
"IRQ 13",
|
||||||
|
"IRQ 14",
|
||||||
|
"IRQ 15",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t interruptNameCount = sizeof(interruptNames) / sizeof(interruptNames[0]);
|
||||||
|
|
||||||
|
#include "intr_stubs.h"
|
||||||
|
|
||||||
|
void intr_routine(CpuState *state)
|
||||||
|
{
|
||||||
|
const char *name = "Unknown";
|
||||||
|
if(state->intr < interruptNameCount)
|
||||||
|
name = interruptNames[state->intr];
|
||||||
|
if(state->intr < 0x20)
|
||||||
|
{
|
||||||
|
kprintf("\n\x12\x04Exception [%d] %s!\x12\0x7\n", state->intr, name);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
__asm__ volatile("cli; hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state->intr >= 0x20 && state->intr <= 0x2f)
|
||||||
|
{
|
||||||
|
if (state->intr >= 0x28)
|
||||||
|
{
|
||||||
|
// EOI an Slave-PIC
|
||||||
|
outb(0xa0, 0x20);
|
||||||
|
}
|
||||||
|
// EOI an Master-PIC
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kprintf("\n\x12\x04Interrupt [%d] %s occurred!\x12\0x7\n", state->intr, name);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
// Prozessor anhalten
|
||||||
|
__asm__ volatile("cli; hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gdt_entry(int i, uint32_t base, uint32_t limit, int flags)
|
||||||
|
{
|
||||||
|
gdt[i] = limit & 0xffffLL;
|
||||||
|
gdt[i] |= (base & 0xffffffLL) << 16;
|
||||||
|
gdt[i] |= (flags & 0xffLL) << 40;
|
||||||
|
gdt[i] |= ((limit >> 16) & 0xfLL) << 48;
|
||||||
|
gdt[i] |= ((flags >> 8 )& 0xffLL) << 52;
|
||||||
|
gdt[i] |= ((base >> 24) & 0xffLL) << 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idt_entry(int i, void (*fn)(), unsigned int selector, int flags)
|
||||||
|
{
|
||||||
|
unsigned long int handler = (unsigned long int) fn;
|
||||||
|
idt[i] = handler & 0xffffLL;
|
||||||
|
idt[i] |= (selector & 0xffffLL) << 16;
|
||||||
|
idt[i] |= (flags & 0xffLL) << 40;
|
||||||
|
idt[i] |= ((handler>> 16) & 0xffffLL) << 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_gdt(void)
|
||||||
|
{
|
||||||
|
memset(gdt, 0, sizeof(gdt));
|
||||||
|
|
||||||
|
gdt_entry(0, 0, 0, 0);
|
||||||
|
gdt_entry(1, 0, 0xfffff, GDTF_SEGMENT | GDTF_32_BIT |
|
||||||
|
GDTF_CODESEG | GDTF_4K_GRAN | GDTF_PRESENT);
|
||||||
|
gdt_entry(2, 0, 0xfffff, GDTF_SEGMENT | GDTF_32_BIT |
|
||||||
|
GDTF_DATASEG | GDTF_4K_GRAN | GDTF_PRESENT);
|
||||||
|
gdt_entry(3, 0, 0xfffff, GDTF_SEGMENT | GDTF_32_BIT |
|
||||||
|
GDTF_CODESEG | GDTF_4K_GRAN | GDTF_PRESENT | GDTF_RING3);
|
||||||
|
gdt_entry(4, 0, 0xfffff, GDTF_SEGMENT | GDTF_32_BIT |
|
||||||
|
GDTF_DATASEG | GDTF_4K_GRAN | GDTF_PRESENT | GDTF_RING3);
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t limit;
|
||||||
|
void* pointer;
|
||||||
|
} __attribute__((packed)) gdtp =
|
||||||
|
{
|
||||||
|
.limit = GDT_ENTRIES * 8 - 1,
|
||||||
|
.pointer = gdt,
|
||||||
|
};
|
||||||
|
__asm__ volatile("lgdt %0" : : "m" (gdtp));
|
||||||
|
__asm__ volatile(
|
||||||
|
"mov $0x10, %ax;"
|
||||||
|
"mov %ax, %ds;"
|
||||||
|
"mov %ax, %es;"
|
||||||
|
"mov %ax, %ss;"
|
||||||
|
"ljmp $0x8, $.1;"
|
||||||
|
".1:"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IDT_FLAG_INTERRUPT_GATE 0xe
|
||||||
|
#define IDT_FLAG_PRESENT 0x80
|
||||||
|
#define IDT_FLAG_RING0 0x00
|
||||||
|
#define IDT_FLAG_RING3 0x60
|
||||||
|
|
||||||
|
static void init_pic(void)
|
||||||
|
{
|
||||||
|
// Master-PIC initialisieren
|
||||||
|
outb(0x20, 0x11); // Initialisierungsbefehl fuer den PIC
|
||||||
|
outb(0x21, 0x20); // Interruptnummer fuer IRQ 0
|
||||||
|
outb(0x21, 0x04); // An IRQ 2 haengt der Slave
|
||||||
|
outb(0x21, 0x01); // ICW 4
|
||||||
|
|
||||||
|
// Slave-PIC initialisieren
|
||||||
|
outb(0xa0, 0x11); // Initialisierungsbefehl fuer den PIC
|
||||||
|
outb(0xa1, 0x28); // Interruptnummer fuer IRQ 8
|
||||||
|
outb(0xa1, 0x02); // An IRQ 2 haengt der Slave
|
||||||
|
outb(0xa1, 0x01); // ICW 4
|
||||||
|
|
||||||
|
// Alle IRQs aktivieren (demaskieren)
|
||||||
|
outb(0x20, 0x0);
|
||||||
|
outb(0xa0, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_idt(void)
|
||||||
|
{
|
||||||
|
memset(idt, 0, sizeof(idt));
|
||||||
|
|
||||||
|
#define SET_ENTRY(i) idt_entry(i, intr_stub_ ## i, 0x08, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_PRESENT | IDT_FLAG_RING0)
|
||||||
|
|
||||||
|
for(size_t i = 0; i < IDT_ENTRIES; i++) {
|
||||||
|
idt_entry(i, intr_stub_0, 0x08, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_PRESENT | IDT_FLAG_RING0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// System Interrupts
|
||||||
|
SET_ENTRY(0);
|
||||||
|
SET_ENTRY(1);
|
||||||
|
SET_ENTRY(2);
|
||||||
|
SET_ENTRY(3);
|
||||||
|
SET_ENTRY(4);
|
||||||
|
SET_ENTRY(6);
|
||||||
|
SET_ENTRY(7);
|
||||||
|
SET_ENTRY(8);
|
||||||
|
SET_ENTRY(9);
|
||||||
|
SET_ENTRY(10);
|
||||||
|
SET_ENTRY(11);
|
||||||
|
SET_ENTRY(12);
|
||||||
|
SET_ENTRY(13);
|
||||||
|
SET_ENTRY(14);
|
||||||
|
SET_ENTRY(15);
|
||||||
|
SET_ENTRY(16);
|
||||||
|
SET_ENTRY(17);
|
||||||
|
SET_ENTRY(18);
|
||||||
|
|
||||||
|
// Hardware handler
|
||||||
|
SET_ENTRY(32);
|
||||||
|
SET_ENTRY(33);
|
||||||
|
SET_ENTRY(34);
|
||||||
|
SET_ENTRY(35);
|
||||||
|
SET_ENTRY(36);
|
||||||
|
SET_ENTRY(37);
|
||||||
|
SET_ENTRY(38);
|
||||||
|
SET_ENTRY(39);
|
||||||
|
SET_ENTRY(40);
|
||||||
|
SET_ENTRY(41);
|
||||||
|
SET_ENTRY(42);
|
||||||
|
SET_ENTRY(43);
|
||||||
|
SET_ENTRY(44);
|
||||||
|
SET_ENTRY(45);
|
||||||
|
SET_ENTRY(46);
|
||||||
|
SET_ENTRY(47);
|
||||||
|
|
||||||
|
// System call
|
||||||
|
SET_ENTRY(48);
|
||||||
|
|
||||||
|
#undef SET_ENTRY
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t limit;
|
||||||
|
void* pointer;
|
||||||
|
} __attribute__((packed)) idtp =
|
||||||
|
{
|
||||||
|
.limit = IDT_ENTRIES * 8 - 1,
|
||||||
|
.pointer = idt,
|
||||||
|
};
|
||||||
|
__asm__ volatile("lidt %0" : : "m" (idtp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void intr_init(void)
|
||||||
|
{
|
||||||
|
// Initialize global descriptor table
|
||||||
|
init_gdt();
|
||||||
|
|
||||||
|
// Initialize interrupt descriptor table
|
||||||
|
init_idt();
|
||||||
|
|
||||||
|
// Initialize Programmable Interrupt Controller
|
||||||
|
init_pic();
|
||||||
|
}
|
39
src/interrupts.h
Normal file
39
src/interrupts.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define GDTF_DATASEG 0x02
|
||||||
|
#define GDTF_CODESEG 0x0a
|
||||||
|
#define GDTF_TSS 0x09
|
||||||
|
|
||||||
|
#define GDTF_SEGMENT 0x10
|
||||||
|
#define GDTF_RING0 0x00
|
||||||
|
#define GDTF_RING3 0x60
|
||||||
|
#define GDTF_PRESENT 0x80
|
||||||
|
|
||||||
|
#define GDTF_4K_GRAN 0x800
|
||||||
|
#define GDTF_32_BIT 0x400
|
||||||
|
|
||||||
|
#define INTR_GATE 6
|
||||||
|
#define INTR_TRAP_GATE 7
|
||||||
|
#define INTR_TASK_GATE 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes interrupt handling and the global descriptor table.
|
||||||
|
*/
|
||||||
|
void intr_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables physical interrupts.
|
||||||
|
*/
|
||||||
|
static inline void irq_enable(void)
|
||||||
|
{
|
||||||
|
__asm__ volatile("sti");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables physical interrupts.
|
||||||
|
*/
|
||||||
|
static inline void irq_disable(void)
|
||||||
|
{
|
||||||
|
__asm__ volatile("cli");
|
||||||
|
}
|
||||||
|
|
46
src/intr_stubs.h
Normal file
46
src/intr_stubs.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define STUB(num) extern void intr_stub_ ## num ()
|
||||||
|
|
||||||
|
STUB(0);
|
||||||
|
STUB(1);
|
||||||
|
STUB(2);
|
||||||
|
STUB(3);
|
||||||
|
STUB(4);
|
||||||
|
STUB(5);
|
||||||
|
STUB(6);
|
||||||
|
STUB(7);
|
||||||
|
STUB(8);
|
||||||
|
STUB(9);
|
||||||
|
STUB(10);
|
||||||
|
STUB(11);
|
||||||
|
STUB(12);
|
||||||
|
STUB(13);
|
||||||
|
STUB(14);
|
||||||
|
STUB(15);
|
||||||
|
STUB(16);
|
||||||
|
STUB(17);
|
||||||
|
STUB(18);
|
||||||
|
|
||||||
|
STUB(32);
|
||||||
|
STUB(33);
|
||||||
|
STUB(34);
|
||||||
|
STUB(35);
|
||||||
|
STUB(36);
|
||||||
|
STUB(37);
|
||||||
|
STUB(38);
|
||||||
|
STUB(39);
|
||||||
|
STUB(40);
|
||||||
|
STUB(41);
|
||||||
|
STUB(42);
|
||||||
|
STUB(43);
|
||||||
|
STUB(44);
|
||||||
|
STUB(45);
|
||||||
|
STUB(46);
|
||||||
|
STUB(47);
|
||||||
|
|
||||||
|
STUB(48);
|
||||||
|
|
||||||
|
STUB(80);
|
||||||
|
|
||||||
|
#undef STUB
|
13
src/io.h
Normal file
13
src/io.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inttypes.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Outputs a byte on the given port.
|
||||||
|
* @param port The port number.
|
||||||
|
* @param data The byte to send.
|
||||||
|
*/
|
||||||
|
static inline void outb(uint16_t port, uint8_t data)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
|
||||||
|
}
|
7
src/kernel.h
Normal file
7
src/kernel.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
void die(const char *msg);
|
||||||
|
|
||||||
|
void ksleep(uint32_t time);
|
249
src/malloc.c
Normal file
249
src/malloc.c
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
/* Copyright (c) 2002, 2004, 2010 Joerg Wunsch
|
||||||
|
Copyright (c) 2010 Gerben van den Broeke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* $Id: malloc.c 2149 2010-06-09 20:45:37Z joerg_wunsch $ */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct __freelist {
|
||||||
|
size_t sz;
|
||||||
|
struct __freelist *nx;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t __malloc_margin = 32;
|
||||||
|
char * const __malloc_heap_start = (char *)0x400000;
|
||||||
|
char * const __malloc_heap_end = (char *)0x800000;
|
||||||
|
|
||||||
|
char *__brkval;
|
||||||
|
struct __freelist *__flp;
|
||||||
|
|
||||||
|
void *malloc(size_t len)
|
||||||
|
{
|
||||||
|
struct __freelist *fp1, *fp2, *sfp1, *sfp2;
|
||||||
|
char *cp;
|
||||||
|
size_t s, avail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our minimum chunk size is the size of a pointer (plus the
|
||||||
|
* size of the "sz" field, but we don't need to account for
|
||||||
|
* this), otherwise we could not possibly fit a freelist entry
|
||||||
|
* into the chunk later.
|
||||||
|
*/
|
||||||
|
if (len < sizeof(struct __freelist) - sizeof(size_t))
|
||||||
|
len = sizeof(struct __freelist) - sizeof(size_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, walk the free list and try finding a chunk that
|
||||||
|
* would match exactly. If we found one, we are done. While
|
||||||
|
* walking, note down the smallest chunk we found that would
|
||||||
|
* still fit the request -- we need it for step 2.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
for (s = 0, fp1 = __flp, fp2 = 0;
|
||||||
|
fp1;
|
||||||
|
fp2 = fp1, fp1 = fp1->nx) {
|
||||||
|
if (fp1->sz < len)
|
||||||
|
continue;
|
||||||
|
if (fp1->sz == len) {
|
||||||
|
/*
|
||||||
|
* Found it. Disconnect the chunk from the
|
||||||
|
* freelist, and return it.
|
||||||
|
*/
|
||||||
|
if (fp2)
|
||||||
|
fp2->nx = fp1->nx;
|
||||||
|
else
|
||||||
|
__flp = fp1->nx;
|
||||||
|
return &(fp1->nx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (s == 0 || fp1->sz < s) {
|
||||||
|
/* this is the smallest chunk found so far */
|
||||||
|
s = fp1->sz;
|
||||||
|
sfp1 = fp1;
|
||||||
|
sfp2 = fp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Step 2: If we found a chunk on the freelist that would fit
|
||||||
|
* (but was too large), look it up again and use it, since it
|
||||||
|
* is our closest match now. Since the freelist entry needs
|
||||||
|
* to be split into two entries then, watch out that the
|
||||||
|
* difference between the requested size and the size of the
|
||||||
|
* chunk found is large enough for another freelist entry; if
|
||||||
|
* not, just enlarge the request size to what we have found,
|
||||||
|
* and use the entire chunk.
|
||||||
|
*/
|
||||||
|
if (s) {
|
||||||
|
if (s - len < sizeof(struct __freelist)) {
|
||||||
|
/* Disconnect it from freelist and return it. */
|
||||||
|
if (sfp2)
|
||||||
|
sfp2->nx = sfp1->nx;
|
||||||
|
else
|
||||||
|
__flp = sfp1->nx;
|
||||||
|
return &(sfp1->nx);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Split them up. Note that we leave the first part
|
||||||
|
* as the new (smaller) freelist entry, and return the
|
||||||
|
* upper portion to the caller. This saves us the
|
||||||
|
* work to fix up the freelist chain; we just need to
|
||||||
|
* fixup the size of the current entry, and note down
|
||||||
|
* the size of the new chunk before returning it to
|
||||||
|
* the caller.
|
||||||
|
*/
|
||||||
|
cp = (char *)sfp1;
|
||||||
|
s -= len;
|
||||||
|
cp += s;
|
||||||
|
sfp2 = (struct __freelist *)cp;
|
||||||
|
sfp2->sz = len;
|
||||||
|
sfp1->sz = s - sizeof(size_t);
|
||||||
|
return &(sfp2->nx);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Step 3: If the request could not be satisfied from a
|
||||||
|
* freelist entry, just prepare a new chunk. This means we
|
||||||
|
* need to obtain more memory first. The largest address just
|
||||||
|
* not allocated so far is remembered in the brkval variable.
|
||||||
|
* Under Unix, the "break value" was the end of the data
|
||||||
|
* segment as dynamically requested from the operating system.
|
||||||
|
* Since we don't have an operating system, just make sure
|
||||||
|
* that we don't collide with the stack.
|
||||||
|
*/
|
||||||
|
if (__brkval == 0)
|
||||||
|
__brkval = __malloc_heap_start;
|
||||||
|
cp = __malloc_heap_end;
|
||||||
|
if (cp <= __brkval)
|
||||||
|
/*
|
||||||
|
* Memory exhausted.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
avail = cp - __brkval;
|
||||||
|
/*
|
||||||
|
* Both tests below are needed to catch the case len >= 0xfffe.
|
||||||
|
*/
|
||||||
|
if (avail >= len && avail >= len + sizeof(size_t)) {
|
||||||
|
fp1 = (struct __freelist *)__brkval;
|
||||||
|
__brkval += len + sizeof(size_t);
|
||||||
|
fp1->sz = len;
|
||||||
|
return &(fp1->nx);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Step 4: There's no help, just fail. :-/
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void free(void *p)
|
||||||
|
{
|
||||||
|
struct __freelist *fp1, *fp2, *fpnew;
|
||||||
|
char *cp1, *cp2, *cpnew;
|
||||||
|
|
||||||
|
/* ISO C says free(NULL) must be a no-op */
|
||||||
|
if (p == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpnew = p;
|
||||||
|
cpnew -= sizeof(size_t);
|
||||||
|
fpnew = (struct __freelist *)cpnew;
|
||||||
|
fpnew->nx = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trivial case first: if there's no freelist yet, our entry
|
||||||
|
* will be the only one on it. If this is the last entry, we
|
||||||
|
* can reduce __brkval instead.
|
||||||
|
*/
|
||||||
|
if (__flp == 0) {
|
||||||
|
if ((char *)p + fpnew->sz == __brkval)
|
||||||
|
__brkval = cpnew;
|
||||||
|
else
|
||||||
|
__flp = fpnew;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, find the position where our new entry belongs onto the
|
||||||
|
* freelist. Try to aggregate the chunk with adjacent chunks
|
||||||
|
* if possible.
|
||||||
|
*/
|
||||||
|
for (fp1 = __flp, fp2 = 0;
|
||||||
|
fp1;
|
||||||
|
fp2 = fp1, fp1 = fp1->nx) {
|
||||||
|
if (fp1 < fpnew)
|
||||||
|
continue;
|
||||||
|
cp1 = (char *)fp1;
|
||||||
|
fpnew->nx = fp1;
|
||||||
|
if ((char *)&(fpnew->nx) + fpnew->sz == cp1) {
|
||||||
|
/* upper chunk adjacent, assimilate it */
|
||||||
|
fpnew->sz += fp1->sz + sizeof(size_t);
|
||||||
|
fpnew->nx = fp1->nx;
|
||||||
|
}
|
||||||
|
if (fp2 == 0) {
|
||||||
|
/* new head of freelist */
|
||||||
|
__flp = fpnew;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Note that we get here either if we hit the "break" above,
|
||||||
|
* or if we fell off the end of the loop. The latter means
|
||||||
|
* we've got a new topmost chunk. Either way, try aggregating
|
||||||
|
* with the lower chunk if possible.
|
||||||
|
*/
|
||||||
|
fp2->nx = fpnew;
|
||||||
|
cp2 = (char *)&(fp2->nx);
|
||||||
|
if (cp2 + fp2->sz == cpnew) {
|
||||||
|
/* lower junk adjacent, merge */
|
||||||
|
fp2->sz += fpnew->sz + sizeof(size_t);
|
||||||
|
fp2->nx = fpnew->nx;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If there's a new topmost chunk, lower __brkval instead.
|
||||||
|
*/
|
||||||
|
for (fp1 = __flp, fp2 = 0;
|
||||||
|
fp1->nx != 0;
|
||||||
|
fp2 = fp1, fp1 = fp1->nx)
|
||||||
|
/* advance to entry just before end of list */;
|
||||||
|
cp2 = (char *)&(fp1->nx);
|
||||||
|
if (cp2 + fp1->sz == __brkval) {
|
||||||
|
if (fp2 == NULL)
|
||||||
|
/* Freelist is empty now. */
|
||||||
|
__flp = NULL;
|
||||||
|
else
|
||||||
|
fp2->nx = NULL;
|
||||||
|
__brkval = cp2 - sizeof(size_t);
|
||||||
|
}
|
||||||
|
}
|
91
src/multiboot.h
Normal file
91
src/multiboot.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define MB_MEMSIZE (1<<0)
|
||||||
|
#define MB_BOOTDEVICE (1<<1)
|
||||||
|
#define MB_COMMANDLINE (1<<2)
|
||||||
|
#define MB_MODULES (1<<3)
|
||||||
|
#define MB_SYMS_AOUT (1<<4)
|
||||||
|
#define MB_SYMS_ELF (1<<5)
|
||||||
|
#define MB_MEMORYMAP (1<<6)
|
||||||
|
#define MB_DRIVES (1<<7)
|
||||||
|
#define MB_CONFIG_TABLE (1<<8)
|
||||||
|
#define MB_BOOTLOADER_NAME (1<<9)
|
||||||
|
#define MB_APS_TABLE (1<<10)
|
||||||
|
#define MB_VBE (1<<11)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t entry_size;
|
||||||
|
uint64_t base;
|
||||||
|
uint64_t length;
|
||||||
|
uint32_t type;
|
||||||
|
} __attribute__((packed)) MultibootMemoryMap;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uintptr_t start;
|
||||||
|
uintptr_t end;
|
||||||
|
uintptr_t name;
|
||||||
|
uint32_t reserved;
|
||||||
|
} __attribute__((packed)) MultibootModule;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t size;
|
||||||
|
uint8_t number;
|
||||||
|
uint8_t mode;
|
||||||
|
uint16_t cylinders;
|
||||||
|
uint8_t heads;
|
||||||
|
uint8_t sectors;
|
||||||
|
uint16_t ports[0];
|
||||||
|
// 0x10 size-0x10 drive_ports I/O-Ports, die von diesem Gerät benutzt werden
|
||||||
|
} __attribute__((packed)) MultibootDrive;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t cseg;
|
||||||
|
uint32_t offset;
|
||||||
|
uint16_t cseg_16;
|
||||||
|
uint16_t dseg;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t cseg_len;
|
||||||
|
uint16_t cseg_16_len;
|
||||||
|
uint16_t dseg_len;
|
||||||
|
} __attribute__((packed)) MultibootAPMTable;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t memLower;
|
||||||
|
uint32_t memUpper;
|
||||||
|
uint32_t bootDevice;
|
||||||
|
uintptr_t commandline;
|
||||||
|
uint32_t moduleCount;
|
||||||
|
uintptr_t modules;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t tabsize;
|
||||||
|
uint32_t strsize;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t reserved;
|
||||||
|
} __attribute__((packed)) symsAssemblerOut;
|
||||||
|
struct {
|
||||||
|
uint32_t num;
|
||||||
|
uint32_t size;
|
||||||
|
uintptr_t addr;
|
||||||
|
uintptr_t shndx;
|
||||||
|
} __attribute__((packed)) symsELF;
|
||||||
|
};
|
||||||
|
uint32_t memoryMapLength;
|
||||||
|
uintptr_t memoryMap;
|
||||||
|
uint32_t drivesLength;
|
||||||
|
uintptr_t drives;
|
||||||
|
uintptr_t configTable;
|
||||||
|
uintptr_t bootLoaderName;
|
||||||
|
uintptr_t apmTable;
|
||||||
|
uint32_t vbeControlInfo;
|
||||||
|
uint32_t vbeModeInfo;
|
||||||
|
uint16_t vbeMode;
|
||||||
|
uint16_t vbeInterfaceSegment;
|
||||||
|
uint16_t vbeInterfaceOffset;
|
||||||
|
uint16_t vbeInterfaceLength;
|
||||||
|
} __attribute__((packed)) MultibootStructure;
|
142
src/pmm.c
Normal file
142
src/pmm.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "pmm.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
#define BITMAP_SIZE 32768
|
||||||
|
|
||||||
|
extern const void kernelStart;
|
||||||
|
extern const void kernelEnd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores for every page in 4 GB RAM if it is free or not.
|
||||||
|
* A set bit indicates that the page is free.
|
||||||
|
*/
|
||||||
|
static uint32_t bitmap[BITMAP_SIZE];
|
||||||
|
|
||||||
|
static inline void resolve(void *pptr, uint32_t *idx, uint32_t *bit)
|
||||||
|
{
|
||||||
|
uintptr_t ptr = (uintptr_t)pptr;
|
||||||
|
ptr >>= 12; // Calculate page ID
|
||||||
|
|
||||||
|
*idx = ptr / 32; // B32 offset in bitmap.
|
||||||
|
*bit = ptr % 32; // Bit offset in bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *rebuild(uint32_t idx, uint32_t bit)
|
||||||
|
{
|
||||||
|
uintptr_t ptr = 32 * idx + bit;
|
||||||
|
ptr <<= 12;
|
||||||
|
return (void*)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks an address used or free
|
||||||
|
* @param addr The address that will be marked
|
||||||
|
* @param used If != 0, the addr will be marked as used, else it will be marked as free.
|
||||||
|
*/
|
||||||
|
static inline void mark(uintptr_t addr, uint32_t used)
|
||||||
|
{
|
||||||
|
uint32_t bit, idx;
|
||||||
|
resolve((void*)addr, &idx, &bit);
|
||||||
|
if(used)
|
||||||
|
bitmap[idx] &= ~(1<<bit);
|
||||||
|
else
|
||||||
|
bitmap[idx] |= (1<<bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a section in memory as used or free.
|
||||||
|
* @param start The start address of the section.
|
||||||
|
* @param end The end address of the section.
|
||||||
|
* @param used If 0 the section will be freed, else it will be marked as used.
|
||||||
|
*/
|
||||||
|
static inline void markSection(uintptr_t start, uintptr_t end, uint32_t used)
|
||||||
|
{
|
||||||
|
uintptr_t it = start;
|
||||||
|
while(it < end)
|
||||||
|
{
|
||||||
|
mark(it, used);
|
||||||
|
it += 0x1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pmm_init(const MultibootStructure *mb)
|
||||||
|
{
|
||||||
|
if((mb->flags & MB_MEMORYMAP) == 0)
|
||||||
|
die("Multiboot header missing memory map. Cannot initialize PMM.");
|
||||||
|
|
||||||
|
// Make all memory used
|
||||||
|
memset(bitmap, 0, sizeof(bitmap));
|
||||||
|
|
||||||
|
// Free the memory map
|
||||||
|
{
|
||||||
|
uintptr_t it = mb->memoryMap;
|
||||||
|
for(size_t i = 0; i < mb->memoryMapLength; i++)
|
||||||
|
{
|
||||||
|
const MultibootMemoryMap *mmap = (const MultibootMemoryMap *)it;
|
||||||
|
if(mmap->type == 1)
|
||||||
|
{
|
||||||
|
markSection(mmap->base, mmap->base + mmap->length, 0);
|
||||||
|
}
|
||||||
|
it += mmap->entry_size + 4; // Stupid offset :P
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the whole kernel as "used"
|
||||||
|
{
|
||||||
|
uintptr_t start = (uintptr_t)&kernelStart;
|
||||||
|
uintptr_t end = (uintptr_t)&kernelEnd;
|
||||||
|
markSection(start, end, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark all kernel modules as "used"
|
||||||
|
if(mb->flags & MB_MODULES)
|
||||||
|
{
|
||||||
|
const MultibootModule *mod = (const MultibootModule *)mb->modules;
|
||||||
|
for(size_t i = 0; i < mb->moduleCount; i++)
|
||||||
|
{
|
||||||
|
markSection(mod[i].start, mod[i].end, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pmm_calc_free(void)
|
||||||
|
{
|
||||||
|
uint32_t mem = 0;
|
||||||
|
for(uint32_t idx = 0; idx < BITMAP_SIZE; idx++)
|
||||||
|
{
|
||||||
|
for(uint32_t bit = 0; bit < 32; bit++)
|
||||||
|
{
|
||||||
|
if(bitmap[idx] & (1<<bit))
|
||||||
|
mem += 0x1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pmm_free(void *pptr)
|
||||||
|
{
|
||||||
|
mark((uintptr_t)pptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *pmm_alloc(void)
|
||||||
|
{
|
||||||
|
for(uint32_t idx = 0; idx < BITMAP_SIZE; idx++)
|
||||||
|
{
|
||||||
|
for(uint32_t bit = 0; bit < 32; bit++)
|
||||||
|
{
|
||||||
|
if(bitmap[idx] & (1<<bit))
|
||||||
|
{
|
||||||
|
// Allocate here
|
||||||
|
bitmap[idx] &= ~(1<<bit);
|
||||||
|
return rebuild(idx, bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die("out of physical memory");
|
||||||
|
return (void*)0xDEADBEEF;
|
||||||
|
}
|
24
src/pmm.h
Normal file
24
src/pmm.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes physical memory management.
|
||||||
|
* @param mb The multi boot structure used for gathering information about free memory.
|
||||||
|
*/
|
||||||
|
void pmm_init(const MultibootStructure *mb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a page of physical memory.
|
||||||
|
*/
|
||||||
|
void pmm_free(void *pptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a page of physical memory.
|
||||||
|
*/
|
||||||
|
void *pmm_alloc(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the free memory in bytes.
|
||||||
|
*/
|
||||||
|
uint32_t pmm_calc_free(void);
|
73
src/stdlib.c
Normal file
73
src/stdlib.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
static void reverse(char *str, int length)
|
||||||
|
{
|
||||||
|
int start = 0;
|
||||||
|
int end = length -1;
|
||||||
|
while (start < end)
|
||||||
|
{
|
||||||
|
char tmp = *(str+start);
|
||||||
|
*(str+start) = *(str+end);
|
||||||
|
*(str+end) = tmp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *itoa(int num, char *str, int base)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int isNegative = 0;
|
||||||
|
|
||||||
|
/* Handle 0 explicitely, otherwise empty string is printed for 0 */
|
||||||
|
if (num == 0)
|
||||||
|
{
|
||||||
|
str[i++] = '0';
|
||||||
|
str[i] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In standard itoa(), negative numbers are handled only with
|
||||||
|
// base 10. Otherwise numbers are considered unsigned.
|
||||||
|
if (num < 0 && base == 10)
|
||||||
|
{
|
||||||
|
isNegative = 1;
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process individual digits
|
||||||
|
while (num != 0)
|
||||||
|
{
|
||||||
|
int rem = num % base;
|
||||||
|
str[i++] = (rem > 9)? (rem-10) + 'A' : rem + '0';
|
||||||
|
num = num/base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If number is negative, append '-'
|
||||||
|
if (isNegative)
|
||||||
|
{
|
||||||
|
str[i++] = '-';
|
||||||
|
}
|
||||||
|
str[i] = '\0'; // Append string terminator
|
||||||
|
|
||||||
|
// Reverse the string
|
||||||
|
reverse(str, i);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int atoi(const char *str)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
for (int i = 0; str[i] != '\0'; ++i)
|
||||||
|
{
|
||||||
|
res = res * 10 + str[i] - '0';
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove( void *destination, const void *source, size_t num)
|
||||||
|
{
|
||||||
|
// TODO: Implement memmove
|
||||||
|
return nullptr;
|
||||||
|
}
|
81
src/stdlib.h
Normal file
81
src/stdlib.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "varargs.h"
|
||||||
|
|
||||||
|
char *itoa(int value, char *str, int base);
|
||||||
|
int atoi(const char *str);
|
||||||
|
float atof(const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a block of memory
|
||||||
|
* @param size Minimum size of the memory block
|
||||||
|
* @return Pointer to the allocated memory area
|
||||||
|
*/
|
||||||
|
void *malloc(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a previously allocated block of memory.
|
||||||
|
* @param mem The block of memory.
|
||||||
|
*/
|
||||||
|
void free(void *mem);
|
||||||
|
|
||||||
|
static inline void *memset(void *ptr, int value, size_t num)
|
||||||
|
{
|
||||||
|
uint8_t *it = (uint8_t*)ptr;
|
||||||
|
while((num--) > 0)
|
||||||
|
{
|
||||||
|
*(it++) = (uint8_t)(value & 0xFF);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *memcpy(void *destination, const void *source, size_t num)
|
||||||
|
{
|
||||||
|
uint8_t *to = (uint8_t*)destination;
|
||||||
|
uint8_t *from = (uint8_t*)source;
|
||||||
|
while((num--) > 0)
|
||||||
|
{
|
||||||
|
*(to++) = *(from++);
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove(void *destination, const void *source, size_t num);
|
||||||
|
|
||||||
|
static inline char *strcpy(char *destination, const char *source)
|
||||||
|
{
|
||||||
|
while(*source)
|
||||||
|
{
|
||||||
|
*(destination++) = *(source++);
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *strcat(char *destination, const char *source)
|
||||||
|
{
|
||||||
|
char *it = destination;
|
||||||
|
while(*it++);
|
||||||
|
it--;
|
||||||
|
while(*source)
|
||||||
|
{
|
||||||
|
*it++ = *source++;
|
||||||
|
}
|
||||||
|
*it = 0;
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t strlen(const char *str)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
while(*(str++) != 0) size++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *calloc(size_t size)
|
||||||
|
{
|
||||||
|
void *mem = malloc(size);
|
||||||
|
memset(mem, 0, size);
|
||||||
|
return mem;
|
||||||
|
}
|
6
src/varargs.h
Normal file
6
src/varargs.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
#define va_start(ap, X) __builtin_va_start(ap, X)
|
||||||
|
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||||
|
#define va_end(ap) __builtin_va_end(ap)
|
81
src/vmm.c
Normal file
81
src/vmm.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#include "vmm.h"
|
||||||
|
#include "pmm.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uintptr_t *directory;
|
||||||
|
} VmmContext;
|
||||||
|
|
||||||
|
VmmContext *context = nullptr;
|
||||||
|
|
||||||
|
VmmContext* vmm_create_context(void)
|
||||||
|
{
|
||||||
|
VmmContext* context = (VmmContext*)pmm_alloc();
|
||||||
|
|
||||||
|
// Initialize page directory
|
||||||
|
context->directory = pmm_alloc();
|
||||||
|
for (uint32_t i = 0; i < 1024; i++)
|
||||||
|
{
|
||||||
|
context->directory[i] = 0;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vmm_activate_context(VmmContext* context)
|
||||||
|
{
|
||||||
|
__asm__ volatile("mov %0, %%cr3" : : "r" (context->directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags)
|
||||||
|
{
|
||||||
|
// Prepare parameters
|
||||||
|
// Align 12 bit
|
||||||
|
virtual = (virtual >> 12) << 12;
|
||||||
|
physical = (physical >> 12) << 12;
|
||||||
|
flags &= 0x0007;
|
||||||
|
|
||||||
|
uint32_t pageIndex = virtual / 4096;
|
||||||
|
|
||||||
|
uint32_t dirIdx = pageIndex / 1024; // Index in page directory
|
||||||
|
uint32_t tableIdx = pageIndex % 1024; // Index in page table
|
||||||
|
|
||||||
|
uintptr_t *table = nullptr;
|
||||||
|
if((context->directory[dirIdx] & VM_PRESENT) == 0)
|
||||||
|
{
|
||||||
|
// Allocate page table if not exists.
|
||||||
|
table = pmm_alloc();
|
||||||
|
for(uint32_t i = 0; i < 1024; i++)
|
||||||
|
{
|
||||||
|
table[i] = 0;
|
||||||
|
}
|
||||||
|
context->directory[dirIdx] = (uintptr_t)table | VM_PRESENT | VM_WRITABLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
table = (uintptr_t*)(context->directory[dirIdx] & 0xfffff000);
|
||||||
|
}
|
||||||
|
table[tableIdx] = physical | flags;
|
||||||
|
|
||||||
|
__asm__ volatile("invlpg %0" : : "m" (*(char*)virtual));
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_init(void)
|
||||||
|
{
|
||||||
|
context = vmm_create_context();
|
||||||
|
|
||||||
|
/* Die ersten 4 MB an dieselbe physische wie virtuelle Adresse mappen */
|
||||||
|
for (uintptr_t ptr = 0; ptr < 0x400000; ptr += 0x1000)
|
||||||
|
{
|
||||||
|
vmm_map(ptr, ptr, VM_PRESENT | VM_WRITABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
vmm_activate_context(context);
|
||||||
|
|
||||||
|
uint32_t cr0;
|
||||||
|
__asm__ volatile("mov %%cr0, %0" : "=r" (cr0));
|
||||||
|
cr0 |= (1 << 31);
|
||||||
|
__asm__ volatile("mov %0, %%cr0" : : "r" (cr0));
|
||||||
|
}
|
21
src/vmm.h
Normal file
21
src/vmm.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define VM_PRESENT 0x01
|
||||||
|
#define VM_WRITABLE 0x02
|
||||||
|
#define VM_USER 0x04
|
||||||
|
|
||||||
|
#define VM_KERNEL (VM_PRESENT | VM_WRITABLE
|
||||||
|
#define VM_PROGRAM (VM_PRESENT | VM_WRITABLE | VM_USER)
|
||||||
|
|
||||||
|
void vmm_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a physical address to a virtual address.
|
||||||
|
* @param virtual The virtual address to be mapped.
|
||||||
|
* @param physical Target physical address
|
||||||
|
* @param flags Flags for the mapping
|
||||||
|
* @remarks If flags is 0, the mapping will be undone.
|
||||||
|
*/
|
||||||
|
void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags);
|
212
trainscript.md
Normal file
212
trainscript.md
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
# Trainscript Version 1 Specification
|
||||||
|
|
||||||
|
## Basic Language Features
|
||||||
|
|
||||||
|
The language is not case sensitive.
|
||||||
|
|
||||||
|
Keywords should be written **CAPITALIZED**.
|
||||||
|
|
||||||
|
Identifieres should be written **lowercased**.
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
Comments are written with a starting #
|
||||||
|
|
||||||
|
normal code
|
||||||
|
# comment
|
||||||
|
normal code # comment
|
||||||
|
|
||||||
|
### Types
|
||||||
|
The language has the following built in primitive types:
|
||||||
|
|
||||||
|
- VOID
|
||||||
|
- BOOL
|
||||||
|
- INT
|
||||||
|
- REAL
|
||||||
|
- TEXT
|
||||||
|
|
||||||
|
`VOID` is a special type that can only be used in function
|
||||||
|
return values indicating the function does not return anything
|
||||||
|
|
||||||
|
### Pointers
|
||||||
|
The language supports pointers by using special operators.
|
||||||
|
Pointers can exist to every type the language supports, not
|
||||||
|
including pointers.
|
||||||
|
|
||||||
|
### Blocks
|
||||||
|
Blocks are defined by indentation in this language. An
|
||||||
|
indentation by a 2 spaces is required:
|
||||||
|
|
||||||
|
blockA
|
||||||
|
blockB
|
||||||
|
blockB
|
||||||
|
blockC
|
||||||
|
blockC
|
||||||
|
blockb
|
||||||
|
blockA
|
||||||
|
blockA
|
||||||
|
|
||||||
|
## Grammarless Description
|
||||||
|
|
||||||
|
### Variable Declaration
|
||||||
|
|
||||||
|
VAR name : type;
|
||||||
|
|
||||||
|
### Expressions And Assignments
|
||||||
|
|
||||||
|
An expression is a piece of code that calculates a value.
|
||||||
|
An assignment assigns the result of an expression to a
|
||||||
|
variable. The assignment is either done by `->` or `→`.
|
||||||
|
|
||||||
|
1 → a;
|
||||||
|
a → b;
|
||||||
|
a + b → c;
|
||||||
|
a * (b + c) → d;
|
||||||
|
|
||||||
|
### Control Structures
|
||||||
|
|
||||||
|
The language supports the most basic control structures:
|
||||||
|
|
||||||
|
- IF
|
||||||
|
- IF/ELSE
|
||||||
|
- IF/ELSEIF/ELSE
|
||||||
|
- REPEAT
|
||||||
|
- REPEAT WHILE
|
||||||
|
- REPEAT UNTIL
|
||||||
|
- REPEAT FROM TO
|
||||||
|
|
||||||
|
Each control structure except `REPEAT` takes an expression
|
||||||
|
for defining the control. The expression is executed once or
|
||||||
|
multiple times depending on the behaviour of the control
|
||||||
|
structure.
|
||||||
|
|
||||||
|
# Simple condition
|
||||||
|
IF expr
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# Condition with alternative
|
||||||
|
IF expr
|
||||||
|
loc;
|
||||||
|
ELSE
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# Condition with multiple alternatives
|
||||||
|
IF expr
|
||||||
|
loc;
|
||||||
|
ELSEIF expr2
|
||||||
|
loc;
|
||||||
|
|
||||||
|
IF expr
|
||||||
|
loc;
|
||||||
|
ELSEIF expr2
|
||||||
|
loc;
|
||||||
|
ELSE
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# Endless loop
|
||||||
|
REPEAT
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# "While" loop
|
||||||
|
REPEAT WHILE expr
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# Inverted "Do-While" loop
|
||||||
|
REPEAT UNTIL expr
|
||||||
|
loc;
|
||||||
|
|
||||||
|
# "For" loop
|
||||||
|
REPEAT a FROM 1 TO 10
|
||||||
|
loc;
|
||||||
|
|
||||||
|
### Function Calls
|
||||||
|
|
||||||
|
Every function returns a value and thus can be included in an expression.
|
||||||
|
Functions calls do not have to be in an expression and can discard the return value.
|
||||||
|
|
||||||
|
fn();
|
||||||
|
fn(a);
|
||||||
|
fn(a,b);
|
||||||
|
fn() → a;
|
||||||
|
fn(a) → b;
|
||||||
|
fn(a,b) → c;
|
||||||
|
|
||||||
|
### Function Declaration
|
||||||
|
|
||||||
|
Functions are declared by using either the `PUB` or the `PRI` keyword.
|
||||||
|
Each script file can be seen as a module that exports a set of functions.
|
||||||
|
`PUB` declares a function that can be seen from outside the module, `PRI`
|
||||||
|
declares a hidden function.
|
||||||
|
|
||||||
|
Each function has a set of local variables that have a specific type.
|
||||||
|
|
||||||
|
Returning a value is done by declaring a special local variable that can
|
||||||
|
be named as wanted.
|
||||||
|
|
||||||
|
# Program that returns 0
|
||||||
|
PUB main() → result : INT
|
||||||
|
0 → result;
|
||||||
|
|
||||||
|
PUB noReturn()
|
||||||
|
otherFn();
|
||||||
|
|
||||||
|
# Private function that doubles the given value squared.
|
||||||
|
PRI fn(x : REAL) → y : REAL
|
||||||
|
2 * x * x → y;
|
||||||
|
|
||||||
|
|
||||||
|
### Pointer Declaration And Usage
|
||||||
|
|
||||||
|
A pointer is declared by using `PTR(type)` as the type.
|
||||||
|
|
||||||
|
VAR name : PTR(INT);
|
||||||
|
|
||||||
|
To retrieve a pointer value or write to it, `VAL(pointer)` must be used:
|
||||||
|
|
||||||
|
VAL(pointer) → a;
|
||||||
|
a → VAL(pointer);
|
||||||
|
|
||||||
|
The address of a variable can be retrieved by using `REF(variable)`:
|
||||||
|
|
||||||
|
REF(variable) → pointer;
|
||||||
|
|
||||||
|
## Example File
|
||||||
|
|
||||||
|
PUB inOut() | a : INT
|
||||||
|
printStr("Enter a number:");
|
||||||
|
readInt() → a;
|
||||||
|
printStr("You entered: ");
|
||||||
|
printInt(a);
|
||||||
|
printLn(); # Prints a newline ('\n')
|
||||||
|
|
||||||
|
PUB isEven(x : INT) → even : BOOL
|
||||||
|
IF (x % 2) =/= 0
|
||||||
|
false → even
|
||||||
|
ELSE
|
||||||
|
true → even
|
||||||
|
|
||||||
|
PUB fibonacci(n : INT) → f : INT
|
||||||
|
IF n = 0
|
||||||
|
0 → f;
|
||||||
|
ELSEIF n = 1
|
||||||
|
1 → f;
|
||||||
|
ELSE
|
||||||
|
fibonacci(n - 1) + fibonacci(n - 2) → f;
|
||||||
|
|
||||||
|
PUB factorial(number : INT) → result : INT
|
||||||
|
IF number <= 1
|
||||||
|
1 → result;
|
||||||
|
ELSE
|
||||||
|
number * factorial(number - 1) → result;
|
||||||
|
|
||||||
|
PRI double(ptr : PTR(INT)) → previous : INT
|
||||||
|
VAL(ptr) → previous;
|
||||||
|
2 * previous → VAL(ptr);
|
||||||
|
|
||||||
|
PUB ptrTest() | a : INT, b : INT
|
||||||
|
10 → a;
|
||||||
|
double(REF(a)) → b;
|
||||||
|
IF a = 20
|
||||||
|
printStr("double has doubled a.");
|
||||||
|
IF a = (2 * b)
|
||||||
|
printStr("double has returned the correct previous value");
|
||||||
|
|
Loading…
Reference in a new issue