From 657b716f77dbde46323d366850c29c15d402cac4 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Sun, 6 Jan 2019 21:47:37 -0600 Subject: [PATCH] Previous commit was a blunder. This commit setups up Malloc proper and includes a working string concat. --- include/buildnumber.h | 9 ++ include/memorymanager.h | 20 +++++ include/pci.h | 34 ++++++++ include/port.h | 15 ++++ make_buildnum.sh | 27 ++++++ src/kernel.c | 185 ++++++++++++++++++++++++++++++++++++++++ src/memorymanager.c | 70 +++++++++++++++ src/pci.c | 92 ++++++++++++++++++++ src/port.c | 35 ++++++++ 9 files changed, 487 insertions(+) create mode 100644 include/buildnumber.h create mode 100644 include/memorymanager.h create mode 100644 include/pci.h create mode 100644 include/port.h create mode 100644 make_buildnum.sh create mode 100644 src/kernel.c create mode 100644 src/memorymanager.c create mode 100644 src/pci.c create mode 100644 src/port.c diff --git a/include/buildnumber.h b/include/buildnumber.h new file mode 100644 index 0000000..fa2ab55 --- /dev/null +++ b/include/buildnumber.h @@ -0,0 +1,9 @@ +#ifndef BUILD_NUMBER +#define BUILD_NUMBER "48" +#endif +#ifndef VERSION_STR +#define VERSION_STR "0.0.2.48 - Sun Jan 6 21:40:38 CST 2019" +#endif +#ifndef VERSION_STR_SHORT +#define VERSION_STR_SHORT "0.0.2.48" +#endif diff --git a/include/memorymanager.h b/include/memorymanager.h new file mode 100644 index 0000000..72cac61 --- /dev/null +++ b/include/memorymanager.h @@ -0,0 +1,20 @@ +#ifndef __MEMORYMANAGER_H +#define __MEMORYMANAGER_H + +#include "system.h" + +typedef struct MemoryChunk +{ + struct MemoryChunk* Prev; + struct MemoryChunk* Next; + size_t Size; + bool Allocated; +}; + +void MemoryManager(size_t start, size_t size); + +void* Malloc(size_t size); + +void Free(void* ptr); + +#endif \ No newline at end of file diff --git a/include/pci.h b/include/pci.h new file mode 100644 index 0000000..e3e6959 --- /dev/null +++ b/include/pci.h @@ -0,0 +1,34 @@ +#ifndef __PCI_H +#define __PCI_H + +#include "system.h" + + typedef struct DeviceDescriptor + { + uint32_t PortBase; + uint32_t Interrupt; + uint16_t Bus; + uint16_t Device; + uint16_t Function; + + uint16_t VendorId; + uint16_t DeviceId; + + uint8_t ClassId; + uint8_t SubClassId; + uint8_t InterfaceId; + + uint8_t Revision; + }; + + uint32_t Read(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber, uint32_t registerOffset); + + void Write(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber, uint32_t registerOffset, uint32_t value); + + bool DeviceHasFunctions(uint16_t bus, uint16_t device); + + void EnumPCISubsystem(void); + + struct DeviceDescriptor GetDeviceDescriptor(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber); + +#endif \ No newline at end of file diff --git a/include/port.h b/include/port.h new file mode 100644 index 0000000..da8d7f2 --- /dev/null +++ b/include/port.h @@ -0,0 +1,15 @@ +#ifndef __PORT_H +#define __PORT_H + +#include "system.h" + +uint8_t Read8Bit(uint16_t portNumber); +void Write8Bit(uint16_t portNumber, uint8_t data); + +uint16_t Read16Bit(uint16_t portNumber); +void Write16Bit(uint16_t portNumber, uint16_t data); + +uint32_t Read32Bit(uint16_t portNumber); +void Write32Bit(uint16_t portNumber, uint32_t data); + +#endif \ No newline at end of file diff --git a/make_buildnum.sh b/make_buildnum.sh new file mode 100644 index 0000000..3e4202a --- /dev/null +++ b/make_buildnum.sh @@ -0,0 +1,27 @@ +#!sh +# FILE: make_buildnum.sh +#version="`sed 's/^ *//' major_version`" +version="0.0.2." +old="`sed 's/^ *//' build.number`" +old=$(($old + 1)) +echo $old > build.number +#echo $old | bc > build.number.temp +#mv build.number.temp build.number +#versión.. +#echo "$version`sed 's/^ *//' build.number` - `date`" > version.number +#header +echo "#ifndef BUILD_NUMBER" > include/buildnumber.h +echo "#define BUILD_NUMBER \"`sed 's/^ *//' build.number`\"" >> include/buildnumber.h +echo "#endif" >> include/buildnumber.h + +echo "#ifndef VERSION_STR" >> include/buildnumber.h +echo "#define VERSION_STR \"$version`sed 's/^ *//' build.number` - `date`\"" >> include/buildnumber.h +echo "#endif" >> include/buildnumber.h + +echo "#ifndef VERSION_STR_SHORT" >> include/buildnumber.h +echo "#define VERSION_STR_SHORT \"$version`sed 's/^ *//' build.number`\"" >> include/buildnumber.h +echo "#endif" >> include/buildnumber.h + +#echo "#ifndef COMPILE_DATE" >> include/buildnumber.h +#echo "#define COMPILE_DATE \"`sed 's/^ *//' date`\"" >> include/buildnumber.h +#echo "#endif" >> include/buildnumber.h \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..51f748c --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,185 @@ +#include "../include/system.h" +#include "../include/gdt.h" +#include "../include/idt.h" +#include "../include/scrn.h" +#include "../include/shell.h" +#include "../include/port.h" +#include "../include/buildnumber.h" +#include "../include/pci.h" +#include "../include/memorymanager.h" + +unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count) +{ + /* Add code here to copy 'count' bytes of data from 'src' to + * 'dest', finally return 'dest' */ + const char *sp = (const char *)src; + char *dp = (char *)dest; + for(; count != 0; count--) *dp++ = *sp++; + return dest; +} + +unsigned char *memset(unsigned char *dest, unsigned char val, int count) +{ + /* Add code here to set 'count' bytes in 'dest' to 'val'. + * Again, return 'dest' */ + char *temp = (char *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +unsigned short *memsetw(unsigned short *dest, unsigned short val, int count) +{ + /* Same as above, but this time, we're working with a 16-bit + * 'val' and dest pointer. Your code can be an exact copy of + * the above, provided that your local variables if any, are + * unsigned short */ + unsigned short *temp = (unsigned short *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +int strlen(const char *str) +{ + /* This loops through character array 'str', returning how + * many characters it needs to check before it finds a 0. + * In simple words, it returns the length in bytes of a string */ + //size_t retval; + unsigned int retval; + for(retval = 0; *str != '\0'; str++) retval++; + return retval; +} + +bool strcmp(char* str1, char* str2) +{ + int len1 = strlen(str1); + int len2 = strlen(str2); + + if(len1 != len2) return false; + + for(int i = len1; i >= 0; i--) if(str1[i] != str2[i]) return false; + + return true; +} +//Code reference: +//http://www.strudel.org.uk/itoa/ +char* int_to_string(int value, int base) +{ + static char buf[32] = {0}; + + if(value == 0) + { + buf[0] = '0'; + return &buf[0]; + } + + int i = 30; + + for(; value && i; --i, value /= base) + { + buf[i] = "0123456789ABCDEF"[value % base]; + } + + return &buf[i+1]; +} + +//Not working +unsigned char strconcat(unsigned char *dest, unsigned char* src) +{ + int dest_length = strlen(dest); + int src_length = strlen(src); + unsigned char* buffer = (unsigned char*)Malloc(dest_length + src_length + 1); + + for(uint32_t i = 0; i < dest_length; i++) + { + *buffer++ = dest[i]; + } + + for(uint32_t j = 0; j < src_length; j++) + { + *buffer++ = src[j]; + } + *buffer++ = '\0'; + + return *buffer; +} + +/* We will use this later on for reading from the I/O ports to get data +* from devices such as the keyboard. We are using what is called +* 'inline assembly' in these routines to actually do the work */ +unsigned char inportb (unsigned short _port) +{ + unsigned char rv; + __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +/* We will use this to write to I/O ports to send bytes to devices. This +* will be used in the next tutorial for changing the textmode cursor +* position. Again, we use some inline assembly for the stuff that simply +* cannot be done in C */ +void outportb (unsigned short _port, unsigned char _data) +{ + __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} + +/* This is a very simple main() function. All it does is sit in an +* infinite loop. This will be like our 'idle' loop */ +void main() +{ + /* You would add commands after here */ + init_video(); + puts("Video initialized.\n"); + gdt_install(); + puts("Global Descriptor Table initialized.\n"); + + size_t heap = 10 * 1024 * 1024; + MemoryManager(heap, heap * 30 * 1024); + puts("heap: 0x"); + puts(int_to_string(heap, 16)); + + void* allocated = Malloc(2048); + puts("\nAllocated: 0x"); + puts(int_to_string(allocated, 16)); + puts("\n"); + + void* al = Malloc(3096); + puts("\nAllocated: 0x"); + puts(int_to_string(al, 16)); + puts("\n"); + + idt_install(); + puts("Interrupt Descriptor Table initialized.\n"); + isrs_install(); + puts("Interrupt Service Routines installed.\n"); + irq_install(); + __asm__ __volatile__ ("sti"); + puts("Interrupt Requests now allowed.\n"); + //puts("Probing PCI subsystem for devices.\n"); + //EnumPCISubsystem(); + //puts("Finished probing PCI subsystem.\n"); + //timer_install(); + //puts("Installed Timer.\n"); + kb_install(); + puts("Keyboard installed.\n"); + puts("SDOS Version "); + puts(VERSION_STR_SHORT); + puts(" Initialized.\n"); + puts("Compile Date "); + puts(__DATE__); + puts("\n"); + puts(strconcat("Hello ", "World!\n")); + //puts(__DATE__); + //puts("\n"); + //puts(__TIME__); + //puts("\n"); + run_shell(); + //puts(&__BUILD_DATE); + //puts(&__BUILD_NUMBER); + //puts("Divide by zero check:\n"); + //puts(5 / 0); +} + +void idle() +{ + __asm__ __volatile__ ("hlt"); +} \ No newline at end of file diff --git a/src/memorymanager.c b/src/memorymanager.c new file mode 100644 index 0000000..f9f5520 --- /dev/null +++ b/src/memorymanager.c @@ -0,0 +1,70 @@ +#include "../include/memorymanager.h" +#include "../include/system.h" + +static struct MemoryChunk* First; + +struct MemoryManager* ActiveMemoryManager = {0}; + +void MemoryManager(size_t start, size_t size) +{ + if(size < sizeof(struct MemoryChunk)) + { + First = 0; + return; + } + + First = (struct MemoryChunk*) start; + + First->Allocated = false; + First->Prev = 0; + First->Next = 0; + First->Size = size - sizeof(struct MemoryChunk); +} + +void* Malloc(size_t size) +{ + struct MemoryChunk *freeChunk = 0; + + for(struct MemoryChunk* chunk = First; chunk != 0 && freeChunk == 0; chunk = chunk->Next) + { + if(chunk->Size > size && !chunk->Allocated) + freeChunk = chunk; + } + + if(freeChunk == 0) + return 0; + + if(freeChunk->Size >= size + sizeof(struct MemoryChunk)) + { + struct MemoryChunk* temp = (struct MemoryChunk*)((size_t)freeChunk + sizeof(struct MemoryChunk) + size); + + temp->Allocated = false; + temp->Size = freeChunk->Size - size - sizeof(struct MemoryChunk); + temp->Prev = freeChunk; + temp->Next = freeChunk->Next; + + if(temp->Next != 0) + temp->Next->Prev = temp; + + freeChunk->Size = size; + freeChunk->Next = temp; + } + + freeChunk->Allocated = true; + + return (void*)(((size_t) freeChunk) + sizeof(struct MemoryChunk)); +} + +void Free(void* ptr) +{ + struct MemoryChunk* chunk = (struct MemoryChunk*)((size_t) ptr - sizeof(struct MemoryChunk)); + + chunk->Allocated = false; + + if(chunk->Prev != 0 && !chunk->Prev->Allocated) + { + chunk->Prev->Next = chunk->Next; + + + } +} \ No newline at end of file diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 0000000..73406ba --- /dev/null +++ b/src/pci.c @@ -0,0 +1,92 @@ +#include "../include/pci.h" +#include "../include/system.h" +#include "../include/port.h" +#include "../include/scrn.h" + +uint32_t Read(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber, uint32_t registerOffset) +{ + puts("Read "); + puts(int_to_string(functionNumber, 10)); + puts("\n"); + uint32_t id = + 0x1 << 31 + | ((busNumber & 0xFF) << 16) + | ((deviceNumber & 0x1F) << 11) + | ((functionNumber & 0x07) << 8) + | (registerOffset & 0xFC); + Write32Bit(0xCF8, id); + uint32_t result = Read32Bit(0xCFC); + return result >> (8 * (registerOffset %4)); +} + +void Write(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber, uint32_t registerOffset, uint32_t value) +{ + uint32_t id = + 0x1 << 31 + | ((busNumber & 0xFF) << 16) + | ((deviceNumber & 0x1F) << 11) + | ((functionNumber & 0x07) << 8) + | (registerOffset & 0xFC); + Write32Bit(0xCF8, id); + Write32Bit(0xCFC, value); +} + +bool DeviceHasFunctions(uint16_t bus, uint16_t device) +{ + //Checks the 7th bit to determine if the device has a function. + return Read(bus, device, 0, 0x0E) & (1 << 7); +} + +void EnumPCISubsystem() +{ + for(int bus = 0; bus < 8; bus++) + { + for(int device = 0; device < 32; device++) + { + int functionCount = DeviceHasFunctions(bus, device) ? 8 : 1;//8 or 1 + + for(int function = 0; function < functionCount; function++) + { + //puts(", Function "); + //puts(int_to_string(function, 16)); + struct DeviceDescriptor dev = {0}; + dev = GetDeviceDescriptor(bus, device, function); + + if(dev.VendorId == 0x0000 || dev.VendorId == 0xFFFF) + break;//Break loop, no more funcitons. + //puts("PCI BUS "); + //puts(int_to_string(bus, 16)); + //puts("Device "); + //puts(int_to_string(device, 16)); + //puts(" = Vendor "); + //puts(int_to_string(dev.VendorId, 16)); + //puts(", Device "); + //puts(int_to_string(dev.DeviceId, 16)); + //puts(" Class "); + //puts(int_to_string(dev.ClassId, 16)); + //puts("\n"); + } + } + } +} + +struct DeviceDescriptor GetDeviceDescriptor(uint16_t busNumber, uint16_t deviceNumber, uint16_t functionNumber) +{ + struct DeviceDescriptor result; + + result.Bus = busNumber; + result.Device = deviceNumber; + result.Function = functionNumber; + + result.VendorId = Read(busNumber, deviceNumber, functionNumber, 0x00); + result.DeviceId = Read(busNumber, deviceNumber, functionNumber, 0x02); + + result.ClassId = Read(busNumber, deviceNumber, functionNumber, 0x0B); + result.SubClassId = Read(busNumber, deviceNumber, functionNumber, 0x0A); + result.InterfaceId = Read(busNumber, deviceNumber, functionNumber, 0x09); + + result.Revision = Read(busNumber, deviceNumber, functionNumber, 0x08); + result.Interrupt = Read(busNumber, deviceNumber, functionNumber, 0x3C); + + return result; +} \ No newline at end of file diff --git a/src/port.c b/src/port.c new file mode 100644 index 0000000..de6a3dd --- /dev/null +++ b/src/port.c @@ -0,0 +1,35 @@ +#include "../include/port.h" +#include "../include/system.h" + +uint8_t Read8Bit(uint16_t portNumber) +{ + uint8_t result; + __asm__ volatile("inb %1, %0" : "=a" (result) : "Nd" (portNumber)); + return result; +} +void Write8Bit(uint16_t portNumber, uint8_t data) +{ + __asm__ volatile("outb %0, %1" : : "a" (data), "Nd" (portNumber)); +} + +uint16_t Read16Bit(uint16_t portNumber) +{ + uint16_t result; + __asm__ volatile("inw %1, %0" : "=a" (result) : "Nd" (portNumber)); + return result; +} +void Write16Bit(uint16_t portNumber, uint16_t data) +{ + __asm__ volatile("outb %0, %1" : : "a" (data), "Nd" (portNumber)); +} + +uint32_t Read32Bit(uint16_t portNumber) +{ + uint32_t result; + __asm__ volatile("inl %1, %0" : "=a" (result) : "Nd" (portNumber)); + return result; +} +void Write32Bit(uint16_t portNumber, uint32_t data) +{ + __asm__ volatile("outb %0, %1" : : "a" (data), "Nd" (portNumber)); +}