Merge into main the new state of the operating system/kernel #1

Open
Nigel wants to merge 120 commits from dev into main
25 changed files with 427 additions and 55 deletions
Showing only changes of commit c9b789ed7b - Show all commits

View File

@ -5,7 +5,7 @@ CC = ${HOME}/opt/cross/bin/i686-elf-gcc
CPP = ${HOME}/opt/cross/bin/i686-elf-g++
CFLAGS = -ffreestanding -O2 -Wall -Wextra
OFILES = $(BUILD_DIR)/boot.o $(BUILD_DIR)/kterm.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/io.o $(BUILD_DIR)/MMU.o $(BUILD_DIR)/idt.o $(BUILD_DIR)/pic.o
OFILES = $(BUILD_DIR)/boot.o $(BUILD_DIR)/kterm.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/io.o $(BUILD_DIR)/MMU.o $(BUILD_DIR)/idt.o $(BUILD_DIR)/pic.o $(BUILD_DIR)/string.o
SRC_DIR = src
BUILD_DIR = build
@ -79,3 +79,6 @@ $(BUILD_DIR)/idt.o:
$(BUILD_DIR)/pic.o:
$(CPP) -c $(SRC_DIR)/kernel/arch/i386/pic/pic.cpp -o $(BUILD_DIR)/pic.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/string.o:
$(CC) -c $(SRC_DIR)/libc/include/string.c -o $(BUILD_DIR)/string.o $(CFLAGS) -std=gnu99

View File

@ -1,4 +1,5 @@
#include "MMU.h"
#include <stdint.h>
@ -34,8 +35,13 @@ void MMU::enable(){
enablePaging();
}
uint32_t MMU::readTableEntry(int entry){
return this->page_directory[entry];
/*
void IdentityPaging(uint32_t *first_pte, vaddr from, int size)
{
from = from & 0xFFFFF000; // Discard the bits we don't want
for (; size > 0; from += 4096, first_pte++)
{
*first_pte = from | 1; // makr page present.
}
}
*/

View File

@ -1,13 +1,26 @@
#pragma once
#include <stdint.h>
extern "C" void loadPageDirectory (long unsigned int* addr );
extern "C" void loadPageDirectory (uint32_t* addr );
extern "C" void enablePaging();
typedef uintptr_t address_t;
#define KB 1024
static const int MAX_PAGES = 1024 * KB; // 4GB , 4kB/page
static volatile address_t pmem_stack[MAX_PAGES];
static volatile address_t pmem_stack_top = MAX_PAGES; // top down allocation
struct page_directory_entry {};
struct page_table_entry{};
class MMU {
public:
void enable ();
uint32_t readTableEntry(int);
private:
uint32_t page_directory[1024] __attribute__((aligned(4096)));

View File

@ -21,7 +21,6 @@ stack_bottom:
stack_top:
.section .text
/*
* Interupt handlers
*/
@ -469,7 +468,7 @@ loadPageDirectory:
.type _start, @function
_start:
/*Setup the stack pointer to point to the beginning of our stack */
/* I believe its a hight address growing down to lower adress for the stack on x86*/
/* I believe its a high address growing down to lower adress for the stack on x86*/
mov $stack_top, %esp
/*Reset EFLAGS*/
@ -484,6 +483,7 @@ _start:
call early_main
cli
load_gdt:
lgdt gdt

View File

@ -1,5 +1,5 @@
#include "gdtc.h"
#include "../tty/kterm.h"
gdtEntry_t gdt[3];
@ -18,6 +18,8 @@ void gdtSetGate(int num, uint64_t base, uint64_t limit, uint8_t access,
}
void setupGdt(){
printf("setupGdt is called!");
gdtPointer.limit = (sizeof(gdtEntry_t) * 3) - 1;
gdtPointer.base = &gdt;

View File

@ -1,5 +1,5 @@
#include <stdint.h>
extern "c"{
extern "C"{
typedef struct {
uint16_t lLimit;

View File

@ -44,7 +44,7 @@ void irq_handler (registers regs) {
// Keyboard interrupt !!
int scan;
register int i;
/*register*/int i;
// Read scancode

View File

@ -8,7 +8,6 @@
extern "C"{
#include "../tty/kterm.h"
}
#define AS_KERNEL() ( kterm_writestring("[KERNEL]:"))
extern "C" {

View File

@ -6,10 +6,11 @@ ENTRY(_start)
kernel image. */
SECTIONS
{
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */
. = 1M;
kernel_begin = .;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
@ -40,4 +41,7 @@ SECTIONS
/* 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 = .;
}

View File

@ -49,7 +49,7 @@ void PIC_sendEOI (unsigned char irq);
}
static uint16_t __pic_get_irq_reg(int ocw3);
//static uint16_t __pic_get_irq_reg(int ocw3);
uint16_t pic_get_irr(void);
uint16_t pic_get_isr(void);

View File

@ -1,4 +1,5 @@
#include "kterm.h"
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
@ -201,8 +202,10 @@ void printf ( const char *format, ...) {
switch (c)
{
case 'd':
kterm_writestring("Not implemented!!");
break;
case 'u':
break;
case 'x':
itoa(buf, c, *((int *) arg++));

View File

@ -6,6 +6,10 @@
#include "../vga/colors.h"
#include "../../../io.h"
#include "./../../../../libc/include/string.h"
void kterm_init();
/* Kernel terminal - Colour functions*/
@ -31,7 +35,7 @@ int get_cursor_y (uint16_t cursor_pos);
void printf ( const char *format, ...);
static void itoa (char *buf, int base, int d);
//static void itoa (char *buf, int base, int d);
#define KernelTag "[Kernel]: "
#define AS_KERNEL() ( kterm_setcolor(VGA_COLOR_LIGHT_BLUE),\

View File

@ -33,7 +33,7 @@ void CheckMBT ( multiboot_info_t* mbt ){
/* Are mods_* valid? */
if(CHECK_FLAG ( mbi->flags, 3)){
multiboot_module_t *mod;
int i;
uint32_t i;
printf("mods count = %d, mods_addr = 0x%x\n", (int) mbi->mods_count, (int) mbi->mods_addr);

View File

@ -1,6 +1,6 @@
#include <cpuid.h> // NOTE: Only available in GCC
static int get_model(){
// NOT currently usefull!
/* static int get_model(){
int ebx, unused;
__cpuid(0, unused, ebx, unused, unused);
return ebx;
@ -14,3 +14,4 @@
__get_cpuid(1, &eax, &unused, &unused, &edx);
return edx & CPUID_FEAT_EDX_APIC;
}
*/

17
src/kernel/disk.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
// Let's write an ATA PIO | ATA driver for now. Mostly to show that I can in theory interact with a
// storage device
// PRIMARY_ATA_BUS
// 0x1F0 through 0x1F7
// SECONDARY_ATA_BUS
// 0x170 through 0x177
#define DEVICE_CONTROL_REGISTER 0x3F6
#define DEVICE_CONTROL_ALTERNATE 0x376
// IRQ14 Primary bus interrupt
// IRQ15 Secondary bus interrupt

View File

@ -1,19 +1,24 @@
#include "io.h"
unsigned char inb_p(unsigned short ){
// TODO: implement me!
return 0;
}
unsigned short inw(unsigned short ){
// TODO: implement me!
return 0;
}
unsigned short inw_p(unsigned short ){
// TODO: implement me!
return 0;
}
unsigned int inl(unsigned short ){
// TODO: implement me!
return 0;
}
unsigned int inl_p(unsigned short ){
// TODO: implement me!
return 0;
}

View File

@ -23,11 +23,20 @@ extern "C" {
/* Are mmap_* valid? */
if (CHECK_FLAG(mbt->flags, 6)){
multiboot_memory_map_t *mmap = (multiboot_memory_map_t*) mbt->mmap_addr;
uint32_t memorySizeInBytes = 0;
uint32_t reservedMemoryInBytes = 0;
printf("mmap_addr = 0x%x, mmap_length = 0x%x\n",
(unsigned) mbt->mmap_addr, (unsigned) mbt->mmap_length);
for (mmap; (unsigned long) mmap < mbt->mmap_addr + mbt->mmap_length; mmap = (multiboot_memory_map_t *) ((unsigned long) mmap + mmap->size + sizeof(mmap->size))){
for (; (unsigned long) mmap < mbt->mmap_addr + mbt->mmap_length; mmap = (multiboot_memory_map_t *) ((unsigned long) mmap + mmap->size + sizeof(mmap->size))){
if ( mmap->type == MULTIBOOT_MEMORY_AVAILABLE){
memorySizeInBytes += mmap->len;
} else {
reservedMemoryInBytes += mmap->len;
}
printf(
"size = 0x%x, base_addr = 0x%x%08x, length = 0x%x%08x, type = 0x%x\n",
@ -39,17 +48,31 @@ extern "C" {
(unsigned) mmap->type);
}
uint32_t memorySizeInGiB = memorySizeInBytes / 1073741824;
printf("Available Memory: 0x%x bytes, 0x%x GiB\n", memorySizeInBytes, memorySizeInGiB );
printf("Reserved Memory: 0x%x bytes\n", reservedMemoryInBytes );
}
//int cpu_model = get_model();
//int local_apic = check_apic();
//printf( "CPU Model: %x, Local APIC: %D\n", cpu_model, local_apic);
/* Setup Paging and memory Managment*/
//MMU MemoryManagementUnit = MMU();
//MemoryManagementUnit.enable(); // Warning: Causes triple page fault
//printf("Pages available: %9d\n", pmm_available());
/* Draw diagonal blue line */
if (CHECK_FLAG (mbi->flags, 12)){
if (CHECK_FLAG (mbt->flags, 12)){
printf("Can draw!");
}
int cpu_model = get_model();
int local_apic = check_apic();
printf( "CPU Model: %x, Local APIC: %D\n", cpu_model, local_apic);
//setupGdt();
}
@ -57,19 +80,12 @@ extern "C" {
init_serial();
while (true){
while (false){
//Read time indefinetely
read_rtc();
printf( "UTC time: %02d-%02d-%02d %02d:%02d:%02d [ Formatted as YY-MM-DD h:mm:ss]\r" ,year, month, day, hour, minute, second);
delay(1000);
}
}
}

View File

@ -1,10 +1,11 @@
#pragma once
extern "C" {
#include "../libc/include/string.h"
#include "arch/i386/tty/kterm.h"
#include "pmm.h"
}
#include "../libc/include/string.h"
#include "multiboot.h"
#include "bootcheck.h"
#include "arch/i386/idt/idt.h"

108
src/kernel/pci.cpp Normal file
View File

@ -0,0 +1,108 @@
#include "pci.h"
uint16_t ConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset){
uint32_t address;
uint32_t lbus = (uint32_t) bus;
uint32_t lslot = (uint32_t) slot;
uint32_t lfunc = (uint32_t) func;
uint16_t tmp = 0;
/* Create configuration address as per Figure 1 */
address = (uint32_t) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xFC) |((uint32_t) 0x80000000) );
/*write out the address */
outl(CONFIG_ADDRESS, address);
/* read in the data */
/* (offset & 2 ) * 8 ) = o will choosse the first word of the 32 bits register*/
tmp = (uint16_t)((inl(CONFIG_DATA)) >> ((offset & 2) * 8) & 0xFFFF);
return (tmp);
}
uint16_t CheckVendor (uint8_t bus, uint8_t slot) {
uint16_t vendor, device;
/*
Try and read the first configuration register. Since there ar no
vendors that == 0xFFFF, it must be a non-existent device.
*/
if((vendor = ConfigReadWord(bus, slot, 0,0)) != 0xFFFF) {
device = ConfigReadWord(bus, slot, 0,2);
// Possible read more config values ...
} return (vendor);
}
void checkDevice (uint8_t bus, uint8_t device ) {
uint8_t function = 0;
uint16_t vendorID = CheckVendor(bus, device);
if (vendorID == 0xFFFF) {
return;
}
checkFunction (bus, device, function );
headerType = getHeaderType(bus, device, function );
if( (headerType & 0x80) != 0) {
/* It is a multi-function device, so check remaining functions */
for (function = 1; function < 8; function++){
if (CheckVendor(bus, device)!= 0xFFFF){
checkFunction(bus, device, function );
}
}
}
}
void checkFunction (uint8_t bus, uint8_t device, uint8_t function ){
uint8_t baseClass;
uint8_t subClass;
uint8_t secondaryBus;
baseClass = getBaseClass(bus, device, function);
subClass = getSubClass (bus, device, function );
if ( (baseClass == 0x06) && (subClass == 0x04)){
secondaryBus = getSecondaryBus(bus,device, function);
checkBus(secondaryBus);
}
}
// Brute-force scan
void checkAllBuses (){
uint16_t bus;
uint8_t device;
for(bus = 0; bus < 256; bus++){
for(device = 0; device < 32; device++){
checkDevice(bus,device);
}
}
}
// Recursive scan
void checkBus (uint8_t bus){
uint8_t device;
for(device = 0; device < 32; device ++){
checkDevice(bus,device);
}
}
void checkAllBuses(){
uint8_t function;
uint8_t bus;
headerType = getHeaderType(0,0,0);
if ( (headerType & 0x80) == 0 ){
/* Single PCI host controller */
checkBus(0);
} else{
/* Multiple PCI host controllers */
for (function = 0; function < 8; function++){
if( CheckVendor(0,0) != 0xFFFF) {
break;
}
bus = function;
checkBus(bus);
}
}
}

58
src/kernel/pci.h Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <stdint.h>
#include "io.h"
// Configuration Space Access Mechanism #1
#define CONFIG_ADDRESS 0xCF8 // Configuration adress that is to be accessed
#define CONFIG_DATA 0xCFC // Will do the actual configuration operation
/*
CONFIG_ADDRESS
32 bit register
bit 31 Enable bit (Should CONFIG_DATA be translatedc to configuration cycles)
bit 30 - 24 Reserved
bit 23 - 16 Bus Number (Choose a specific PCI BUS)
bit 15 - 11 Device Number (Selects specific device one the pci bus)
bit 10 - 8 Function Number (Selects a specific function in a device)
bit 7 - 0 Register Offset (Offset in the configuration space of 256 Bytes ) NOTE: lowest two bits will always be zero
*/
/*
PCI Device structure
Register offset bits 31-24 bits 23-16 bits 15-8 bits 7-0
00 00 Device ID <---- Vendor ID <-------
01 04 Status <---- Command <-------
02 08 Class code Sub class Prog IF Revision ID
03 0C BIST Header Type Ltncy Timer Cache line Size
04 10 Base address #0 (BAR0)
05 14 Base address #1 (BAR1)
06 18 Base address #2 (BAR2)
07 1C Base address #3 (BAR3)
08 20 Base address #4 (BAR4)
09 24 Base address #5 (BAR5)
0A 28 Cardbus CIS Pointer
0B 2C Subsystem ID <------ Subsystem Vendor ID <-------
0C 30 Expansion ROM base address
0D 34 Reserved <------- Capabilities Pointer <------
0E 38 Reserved <------- <-------- <--------
0F 3C Max ltncy Min Grant Interrupt PIN Interrupt Line
*/
/*
The idea for now is to support the minimal things necessary to find ATA supported drives
*/
// Lets write some boiler plate configuration code
uint16_t ConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
uint16_t CheckVendor (uint8_t bus, uint8_t slot);
void checkDevice (uint8_t bus, uint8_t device );

1
src/kernel/pmm.cpp Normal file
View File

@ -0,0 +1 @@
#include "pmm.h"

125
src/kernel/pmm.h Normal file
View File

@ -0,0 +1,125 @@
#pragma once
#include <stdint.h>
// Lets assume we have 2 gigabytes of memory
// NOTE: We should really detect how much memory we have
#define KiloByte 1024 // bytes
#define MegaByte 1048576 // bytes
#define GigaByte 1073741824 // bytes
#define MemorySize 2147483648 // bytes
const uint32_t bitmapSize = MemorySize / 8;
extern void *kernel_begin;
extern void *kernel_end;
struct __attribute__((packed)) PMSegment {
void* address;
uint32_t size;
PMSegment* Next;
};
static PMSegment pmStart;
static uint32_t AvailablePhysicalMemory;
static uint32_t AllocatedMemorySize;
void initPhysicalMemoryManager(){
AvailablePhysicalMemory = MemorySize;
AllocatedMemorySize = 0;
// Map the kernel
PMSegment KernelSegment = PMSegment();
printf("end of kernel: 0x%x\n", &kernel_end);
printf("start of kernel: 0x%x\n", &kernel_begin);
printf("pointer to kernel: 0x%x\n", &KernelSegment);
pmStart = KernelSegment;
KernelSegment.address = kernel_begin;
KernelSegment.size = &kernel_end - &kernel_begin;
AllocatedMemorySize += KernelSegment.size;
KernelSegment.Next = 0;
// make sure We allocate space for ourselves
/*PMSegment start = PMSegment();
start.address = KernelSegment.address + KernelSegment.size ;
start.size = (MemorySize / sizeof(PMSegment) ) + sizeof (uint32_t) * 2;
*/
//KernelSegment.Next = &start;
//AllocatedMemorySize += start.size;
}
void printMemorySegments()
{
printf("Memory Segments:\n");
printf( "Start Segment: [addr: 0x%x, size: 0x%x, Next: 0x%x]\n" ,pmStart.address, pmStart.size, pmStart.Next);
printf("----------------------------\n");
}
void pmem_free (void* address){
PMSegment* before = 0;
PMSegment* current = &pmStart;
printf("Address of pmStart : 0x%x\n", pmStart);
printf("Looking for segment with address: 0x%x \n", address );
printf("Address of pmStart(a.k.a current) : 0x%x \n", current);
while( current )
{
//printf("address of current segment 0x%x\n", current->address );
if ( current->address == address ) {
// this is the address we want to free
printf("Segment found!! Segment address: 0x%x \n", current->address);
if ( current->Next && before ){
before->Next = current->Next;
}else{
before->Next = 0;
}
// TODO: Clean memory [ Something like memset to zeroes]
printf("Removing segment of size: 0x%x\n", current->size);
AllocatedMemorySize -= current->size;
break;
}
before = current;
current = current->Next;
}
}
void* pmem_alloc ( uint32_t size ){
// Get the last segment
PMSegment* lastSegment = &pmStart;
while (lastSegment ) {
if( lastSegment->Next == 0){
break;
}
lastSegment = lastSegment->Next;
}
printf("LastSegment is for address: 0x%x\n", lastSegment->address);
// So now we have the last segment available
PMSegment newSegment = PMSegment();
newSegment.address = (PMSegment*)((uint32_t)lastSegment->address + lastSegment->size +1);
printf("NewSegment for Address: 0x%x\n", newSegment.address);
newSegment.size = size;
lastSegment->Next = &newSegment;
if ( AllocatedMemorySize + newSegment.size > AvailablePhysicalMemory){
// No segment available of this size
/// ERROR!!
return 0;
}
AllocatedMemorySize += newSegment.size;
return newSegment.address;
}

View File

@ -49,6 +49,8 @@ void read_rtc() {
year = get_RTC_register(0x09);
if(century_register != 0) {
century = get_RTC_register(century_register);
} else {
century = 21;
}
do {
@ -141,7 +143,7 @@ void WriteTOCMOS(unsigned char array[])
asm("cli\n\t" // Clear interrupts
"mov al,index\n\t" // move index address
"out 0x70,al\n\t" // copy address to CMOS register
/* some kind of real delay here is probably best
// some kind of real delay here is probably best
"mov al,tvalue\n\t" // move value to al
"out 0x71,al\n\t" // write 1 byte to CMOS
"sti\n\\t" ); // Enable interrupts

View File

@ -0,0 +1,9 @@
#include "string.h"
size_t strlen(const char* str) {
size_t len = 0;
while(str[len]){
len++;
}
return len;
}

View File

@ -1,8 +1,3 @@
#pragma once
#include <stddef.h>
size_t strlen(const char* str){
size_t len = 0;
while(str[len]){
len++;
}
return len;
}
size_t strlen(const char* str);