Compare commits

...

95 Commits

Author SHA1 Message Date
Nigel Barink 2522492835 Couple of small changes
* Commented out the map page function call to handle page not present
* Mapped the ACPI_RECLAIMABLE_MEMORY
* Set VBE to false when VBE is not initialized by the bootloader
2023-10-28 20:42:28 +02:00
Nigel Barink e82392e9d9 FAT Filesystem implementation additions 2023-10-27 18:07:11 +02:00
Nigel Barink 64c87a2a58 Fixing an issue in the CoreLib 2023-10-27 18:04:09 +02:00
Nigel Barink 04470edcc6 Adding gdb init and adjusting some of the build automation steps 2023-10-27 18:03:45 +02:00
Nigel Barink 2970806705 ACPI reading memory when mapped to higher half 2023-09-11 23:23:38 +02:00
Nigel Barink e8df6ec628 Updating Build scripts 2023-09-11 23:21:43 +02:00
Nigel Barink 5781f730d9 Implemented the basis for syscalls
A software interrupt with vector 0x50 will cause a syscall to start executing.
The EAX register will hold the syscall_num.
Other registers and the stack can be used to hold further arguments.
2023-02-27 00:34:30 +01:00
Nigel Barink 2d0bb16fad Fixed up ACPI Version 1.0 checksum validation code 2023-02-27 00:32:16 +01:00
Nigel Barink e6901f0526 We can now open and read files on the harddisk through a messy virtual filesystem
The uri has to contain 8.3 filenames for now as I have not yet figured out
how to convert from that to regular filenaming for the name comparison.

reading files is still limited to 1 sector
2023-02-26 13:44:41 +01:00
Nigel Barink 61f1852420 Added file reading without cluster chain following 2023-02-25 21:03:10 +01:00
Nigel Barink 32b0d990df Added ctype std lib functions 2023-02-25 20:41:21 +01:00
Nigel Barink 745656eb2d Fixup C++ compiler path in makefile of CoreLib
memcpy implementation added
2023-02-25 20:04:34 +01:00
Nigel Barink 644ff5b1f5 Adding subdir functionality
Added FAT16 driver ability to list subdir entries
Removed structure of FAT32 (we won't be using it anytime soon)
2023-02-24 21:31:20 +01:00
Nigel Barink a77621faf5 Shellscript improvement plus FAT driver implementations
- Improved the run bash script to exit when an error occurs in one of the sub tasks
- Wrote basic FAT16 functions that should give enough information to properly implement the rest of the driver
- FAT structure namings are now in accordence with the microsoft spec of March 2005
2023-02-23 23:54:02 +01:00
Nigel Barink 50bf952a49 Basic idea's are created for the storage solution
- Added boot device info parsing to the kernel
- Added a pointer in the kernel to our pre-kernel BootInfo structure
- Created a layout for the FAT driver
- Created a layout for the virtual filesystem
- Separated IDE driver from the basic atapio driver.
	This will ensure we are not using one or the other
- The create_harddrive shell script will now actually build a harddrive image of
	the kernel
- The virtual filesystem initializes and creates a filesystem structure
	for every FAT16 partition in the master boot record
2023-02-21 21:43:14 +01:00
Nigel Barink ef2bba5c1c Started fleshing out the storage API 2023-02-21 14:36:20 +01:00
Nigel Barink 81f7351fe6 Created a few shell scripts to update and create an build of the Kernel/Operating System.
A python script can be run to run the scripts in the correct order and immediatly try the build.
2023-02-20 01:03:46 +01:00
Nigel Barink dea8ab7d71 Improved build system
Added new entries to .gitignore
Moved away from source directory as central spot for all source code
2023-02-20 00:29:06 +01:00
Nigel Barink 2bcc79216e Remove mlibc submodule. The standarc C/C++ will use later on will be added later.
It may or not be mlibc
2023-02-19 23:47:43 +01:00
Nigel Barink b07b4f0d38 Moving certain aspects into their own static library
Problem:
	As our kernel grows we need more complex datastructures and functions these would come from
	the standard C/C++ library with normal programs.
	The kernel is a freestanding programme and has no access to standard libraries.

Solution:
	We build a mini version of the standard C/C++ library which will contain the
	datastructures and functions we want. This library can then be statically linked
	into our kernel binary.

	Making it a statically linked library also gives more structure to the project.
	Keeping these random functions and datastructures in the kernel just clutters the
	kernel source code with less relevant source code.
2023-02-19 23:38:32 +01:00
Nigel Barink 94a2de3847 Started on path resolution algorithm
- The algorithm will work once I am of better mind to deal with
raw C strings
- The resolution should look at each entry divided by '/'.
  if the entry is not there then we can quit early, however for
now I am mostly concerned with getting the names of directory entries
we would need to look for.
2023-02-19 22:17:56 +01:00
Nigel Barink dbb147e110 Primitie listing rootdir of FAT16 filesystem 2023-02-19 14:17:47 +01:00
Nigel Barink 37542b736f Remove cpu.h and cpu.cpp in favor of i386/processor.[h|cpp]
Moving enable protected Mode to processor class
2023-02-17 22:01:32 +01:00
Nigel Barink 490529099b Started implementing the virtual file system
- The FAT command is no longer available
- At Startup the FileSystem initialise funciton
is called, it should execute the same code as the FAT command did.
- ACPI::initialise is commented out because it causes a Exception
2023-02-17 21:52:03 +01:00
Nigel Barink 133c16cae7 Added CPUID based checks 2023-02-17 16:27:36 +01:00
Nigel Barink ecab248cd6 Clean up jump into RING 3 2023-02-17 14:46:44 +01:00
Nigel Barink 4ce7cc093b Cleanup of PCI API 2023-02-17 14:42:42 +01:00
Nigel Barink c9a036bfbb Ring 3 ready
- Fixed issue with setting up the Task Segment Register
2023-02-13 22:44:47 +01:00
Nigel Barink 1f90a5d862 Starting to move towards proper HAL and ring3
- slight clean up of PCI driver
- Added TaskSegment header
- Rename some folders
2023-02-11 12:22:45 +01:00
Nigel Barink 520104a43a Moved reading file from disk to its own super visor terminal command
- Updated gdt assembly
- Updated Interrupt service request handlers
- Improved virtual memory manager
- NOTE: we're dependent on identity mappings for the heap to work
2023-02-08 14:07:44 +01:00
Nigel Barink 7993a2d172 Merge interrupts into dev 2023-02-05 10:30:10 +01:00
Nigel Barink 27e99fe4f2 Merged FAT16 into Dev
Hopefully with success
2023-02-03 21:47:05 +01:00
Nigel Barink 749f2aa492 Updating folders name's (1)
This should help merging into dev branch
2023-02-03 20:01:31 +01:00
Nigel Barink 891085e151 Successfully able to create a disk-image file
- Created a scripts folder
- Written instructions on how to create the disk image
- Working on a python build script that executes all other scripts

The scripts folder should contain scripts to build a full installation of
our operating system. Scripts like creating a filesystem should be found here
2023-02-02 14:59:42 +01:00
Nigel Barink 364d10d02e src folder -> source folder; makes merging with dev a bit easier. 2022-09-10 20:06:49 +02:00
Nigel Barink 68371475d9 Marking memory management features as done. Work still needs to be done but the bare minimum for memory management is there. 2022-09-03 17:38:22 +02:00
Nigel Barink 16e2354019 KERNEL: Moved serials test function into the test folder 2022-09-03 17:27:41 +02:00
Nigel Barink a47879f404 KERNEL: First Kernel heap implementation 2022-09-03 17:27:29 +02:00
Nigel Barink 656ca0baa8 KERNEL: Pre-kernel sets up the physical memory manager.
* BUG: allocated blocks is possibly incorrect!
* prekernel no longer gets compiled as being in physical memory
2022-09-03 01:00:17 +02:00
Nigel Barink 01fcb0aa15 KERNEL: Improved Physical memory allocation code / Code refactor
* Moved tests to a different folder
* Adjusted the memory map address locations
* Improved readability of `kernel.cpp`
2022-09-02 21:09:51 +02:00
Nigel Barink 13e9beea79 KERNEL: Implementing VMM & cleaning up
Folders now are alll lower case

Started working on the implementation of the Virtual memory manager. Implemented allocate and free page funtionality for as far as I can atm.

Implemented the
2022-09-01 20:16:16 +02:00
Nigel Barink 9893a0bd17 KERNEL: Cleanup
Removing quite a few unnecessary parts.
2022-09-01 17:02:04 +02:00
Nigel Barink a70ae5ca31 KERNEL: Mapping the bios region ( below 1Mib)
Keyboard.h: remove the incorrect use of typedef

PhysicalMemoryManager.cpp:
Map the Bios region as used. This prevents us from allocation the area used by the bios
2022-09-01 16:42:56 +02:00
Nigel Barink 15443601a6 Adding dev-scripts (Without much content) .. this can later help setting up the projects on other pc's. 2022-09-01 16:15:24 +02:00
Nigel Barink c90e90bd84 Moving the images from the repo into the disk folder 2022-09-01 16:15:24 +02:00
Nigel Barink a5e7fdd07e KERNEL: Physical Page Frame allocation
Rewriting the setup to allow for physical memory allocation again to work.
2022-09-01 16:15:10 +02:00
Nigel Barink 59ba41f3d2 Multiboot Memory Map get copied to a "safe" place 2022-08-23 21:35:19 +02:00
Nigel Barink 5051b8903c Divided the kernel into seperate distinct phases
The first stage after GRUB will be Pre-Kernel. This stage will organize the
information we receive from the bootloader. (in our case that will be grub)

The second stage is for now called early_main. The program will at this
point already be running in virtual higher-half / higher-quarter address space.
The goal of the second stage is to set up the kernel in such a way that we are
ready to jump in to usermode.

The third stage is for now called kernel_main. This stage will jump us into
usermode and load the startup programs.

- Added a GRUB entry for tests
- Started writing the pre-kernel stage
- Removed knowledge of multiboot from early_main
- Edited the linkerscript to link variables in pre-kernel to
	lower address space. ( from 1MB and up)
2022-08-22 21:16:34 +02:00
Nigel Barink 0f0fc9f252 Adding a skeleton for the memory management code
Moved the PMM away from being object orientated as it is just plain annoying
renamed src folder to source
Set timeout to 5 seconds in the grub config
2022-08-21 21:18:53 +02:00
Nigel Barink e70f56a005 Improving the memory mapping boot code
Removed the need to map the extra MBI structure in as a seperate pagetable
Renaming / Restructuring the memory folder
2022-08-21 21:15:15 +02:00
Nigel Barink 560dd64e64 Kernel is working in its full former glory as a higher half kernel 2022-08-19 23:44:38 +02:00
Nigel Barink 9436e6e033 End of the day cleanup.
* Added symbol files to .gitignore
* Improved text in #PG and #GP handlers
* Added the printing of the multiboot structure address and the magic value
* Added page fault screenshot to readme
2022-08-19 01:05:10 +02:00
Nigel Barink d280aa0584 Page faults and protetion faults will now hang with a helpful message
to explain what is going on.

I removed previously set barriers from the code to load
the kernel further.
2022-08-19 00:44:52 +02:00
Nigel Barink 7d6c823d79 Basic Launch of Higher half kernel
We now can launch the kernel at 0xC0000000 (or 3 GiB mark) with paging enabled.
A lot of early main is currently not executed to keep debugging as simple as possible
during the initial testing of higher half kernel loading.

A lot of the implementation is straight from wiki.osdev.org/Higher_Half_x86_Bare_Bones. Thanks to all the folks
who keep that wiki updated, its really resourceful.
2022-08-18 01:26:49 +02:00
Nigel Barink bbfea39c23 Fixing include paths for new structure
Removed non-sensical libc folder from project
2022-08-17 14:57:50 +02:00
Nigel Barink 3b3e2597a1 Restructering Kernel folder before moving to higher half kernel
The boot up process will be changed somewhat dramatically, therefor a
restructering of the kernel seems as a good starting point.
2022-08-17 14:29:26 +02:00
Nigel Barink 0b0e37b762 Paging cleanup, more cpu testing and psuedo code for higher half kernel 2022-08-17 14:17:58 +02:00
Nigel Barink 388ac8e7f9 Added checks to be sure paging is actually enabled on the cpu.
- Made a special assembly file to put CPU check function in. E.G. functions to get the state of
	specific registers

In this case I have created a simple assembly function to get the contents of the CR0 register.
With the help of the c++ preprocessor the value can then be used to check if certains bits are set.
For example to check if the PG (paging) bit is set, indicating that paging is enabled for the
processor.
2022-08-16 19:06:16 +02:00
Nigel Barink 9172da075a Added identity paging basics
Followed wiki.osdev.org/Setting_Up_Paging
2022-08-15 19:51:22 +02:00
Nigel Barink 23c68d9863 Setup paging function signatures... Ready to be implemented. 2022-03-18 22:09:04 +01:00
Nigel Barink 2e2693d1ea Build some structures will need for the virtual filesystem 2022-03-15 21:56:32 +01:00
Nigel Barink a93bf566c8 Added FAT-16 screenshot 2022-03-12 17:04:38 +01:00
Nigel Barink 2e59e6593e Add proper Physical memory management to this branch
to ensure it doesn't get too out of date

We can now run the FAT command to demo reading out the FAT16 filesystem,
however this will cause the need for a reboot as after this command. We are FOR NOW
not able to put in any new commands
2022-03-12 16:56:50 +01:00
Nigel Barink b4cff3e667 Basic block allocation for physical memory allocation.
- 1 block = 4096 bytes : because this will make page fault handling possibly
somewhat easier

- 1 byte in the bitmap = 8 blocks of physical memory

unsure if the allocation is perfect ... guess i'll find out some day if this is actually correct.

The bitmap needs 16kb to keep track of 2gb of physical memory. Seems a decent percentage to me.
2022-02-26 20:55:34 +01:00
Nigel Barink 7330b81a10 Started definition file for a CMOS driver 2021-12-29 16:28:55 +01:00
Nigel Barink 97606dbf71 Clean up of debugging logs and new commands.
As this project grows it becomes important to keep things properly organised.
In this commit I've put some effort into making the kernel.cpp file more consise and thus improve its
readability.
Certain parts of the code have gotten their own definition file where before it
was only a header file.

- Moving the Supervisor Terminal into its own definition file.
- Subtracting debugging messages with preprocessor ifdef's
- Time and Date is now not just a header but has its own proper definition file
- Banner is displayed when booting up
- Terminal has a couple new commands

	Commmand		Description
	=================|||||===================================================
	DATE (was TIME)		Displays the curren time, date and ticks
	VERSION			Displays system version information
	MEMORY			Displays memory information
2021-12-29 16:15:18 +01:00
Nigel Barink 7496299761 Basic Intel Exceptions
Any interrupt thrown for any Intel defined Exception is not only being caught but
displays an appropriate message to the screen.

Changes made in src/kernel/idt/idt.cpp
2021-12-28 19:54:10 +01:00
Nigel Barink 0d8ef065e0 Interactive supervisor mode
To ease the pain of debuggin I can now interact with the system through a
very simplistic terminal. Hopefully things can be tested more easily by activating
the piece through a simple command. The max characters for a command is 10.

To achieve this I have had to make the following changes.
- Changed IRQ to update a global status variable
- Added a standalone keyboard driver with getKey functions
- Changed the main kernel loop to display a prompt
- Added a strncmp function to the clib/string file
2021-12-28 19:52:48 +01:00
Nigel Barink 19b9cfe908 Reading files from disk
- Modified makefile to start the virtualbox vm on `make run`
- Listing files in rootdirectory with their properties and
	content
2021-12-27 19:35:24 +01:00
Nigel Barink b8d75dddae Moving lots into seperate folders to cleanup the project structure
- Drivers have now gotten Category folders
- RSDP is now called ACPI
- Ports folders is now called Serial to show that its a serial driver
- Paging assembly definition is moved to the memory folder
- VGA folder has moved into the drivers
- Patched the makefile and include statements to reflect the changes
	in the project structure
2021-12-27 15:26:32 +01:00
Nigel Barink fb2a19e11d FAT16 structures read from disk using ATA.
The proper reading of folders and files is not yet implemented. Although
it is close.
2021-12-24 21:31:10 +01:00
Nigel Barink 72008b0a7a Find RSD Table in early BIOS memory
Adding functions and structures to read the RSD.
2021-12-24 20:13:28 +01:00
Nigel Barink 2621399349 Small code fix up
- Moved memcmp function to temporary libc/mem.h
- I/O functions are inlined
- ATA_DEVICE read function won't print the 512 bytes by default
2021-12-24 20:08:18 +01:00
Nigel Barink 767dac7e73 Adjustments to IDE driver 2021-12-23 17:46:27 +01:00
Nigel Barink 6d946ddce3 Struct defining the EXT2 filesystems superblock 2021-12-23 17:44:27 +01:00
Nigel Barink 9173b90eb1 Structures added for MasterBootRecord support 2021-12-23 17:43:25 +01:00
Nigel Barink bd5d3f5d49 Basic PIO ATA driver which can read and identify ata drives 2021-12-23 17:41:07 +01:00
Nigel Barink 88cc1d75bb Re-enabled interrupts from keyboard, Enabled and configured the PIT to throw interrupts at a regular interval 2021-12-20 21:53:57 +01:00
Nigel Barink 2db83b33e1 ATAPI can identify a device correctly 2021-12-01 00:00:45 +01:00
Nigel Barink 5a68f77b33 Started the base implementation for PCI IDE drivers 2021-11-29 20:00:28 +01:00
Nigel Barink 72438ae70d Makefile: Added ISO test option for qemu. 2021-11-28 23:06:21 +01:00
Nigel Barink a36e3d1c16 PCI support checked of on features.md, PCI enumeration screenshot added to readme.md 2021-11-28 21:12:12 +01:00
Nigel Barink 08b97af863 PCI: enumeration code cleanup 2021-11-28 21:07:05 +01:00
Nigel Barink 5089da5e9e PCI: Improved syntax of PCI enumeration, Added a PCI information storage class and structs 2021-11-28 16:46:16 +01:00
Nigel Barink ec654143c6 Basic PCI Enumeration 2021-11-25 22:05:16 +01:00
Nigel Barink 5f39f7e7ed Merge branch 'dev' into InterruptHandling 2021-11-02 21:56:57 +01:00
Nigel Barink d455735ea2 Modified screenshot?? 2021-11-02 21:44:50 +01:00
Nigel Barink 9dc7a05da1 Basic keyboard input 2021-07-21 21:31:57 +01:00
Nigel Barink 59bcc17668 Kernel now responding to keyboard interrupts 2021-05-28 22:20:13 +01:00
Nigel Barink 5f50f8c013 Fix up wrong interrupt handler numbers in boot.s 2021-05-28 22:18:50 +01:00
Nigel Barink 595a7d5163 Nicer time print 2021-05-22 19:24:29 +01:00
Nigel Barink e84d196b00 Kernel now enter continuous time telling mode 2021-05-18 21:14:26 +01:00
Nigel Barink f71a3a8ed6 Removed itoa and printf from idt 2021-05-18 21:13:14 +01:00
Nigel Barink 63ea825e2e Added CMOS time read function, Added cariage return support to kterm 2021-05-18 21:11:48 +01:00
Nigel Barink a094f510d3 More work on interrupt handling, Started timer interrupt implementation, PIC remapped hopefully successfull 2021-05-16 15:53:14 +01:00
154 changed files with 5756 additions and 1604 deletions

7
.gdbinit Normal file
View File

@ -0,0 +1,7 @@
target remote localhost:1234
file root/boot/myos.bin
symbol-file kernel.sym
break prekernel/prekernel.cpp:18
continue

13
.gitignore vendored
View File

@ -1,8 +1,15 @@
build
CON
.vscode
build/
bin/
.vscode/
.idea/
isodir/
root/
*.iso
*.img
*.sym
*.o
*.a
/CoreLib/warnings.log
/kernel/warnings.log

12
CoreLib/List.h Normal file
View File

@ -0,0 +1,12 @@
//
// Created by nigel on 25/02/23.
//
#pragma once
class List {
public:
List* next;
void* data;
};

35
CoreLib/Makefile Normal file
View File

@ -0,0 +1,35 @@
CPP = /opt/cross/bin/i686-elf-g++
CFLAGS = -ffreestanding -Og -ggdb -Wall -Wextra
BUILD_DIR = ../build/CoreLib
OBJ_FOLDER = ../bin/CoreLib
OUTPUTFILE = $(BUILD_DIR)/libCoreLib.a
OFILES = $(OBJ_FOLDER)/ctype.o $(OBJ_FOLDER)/memory.o $(OBJ_FOLDER)/path.o $(OBJ_FOLDER)/stack.o $(OBJ_FOLDER)/string.o $(OBJ_FOLDER)/stringview.o
.phony: all
all: $(OUTPUTFILE)
cp *.h $(BUILD_DIR)/include/CoreLib
$(OUTPUTFILE): $(OFILES)
pwd
ar -rc $(OUTPUTFILE) $(OFILES)
$(OBJ_FOLDER)/ctype.o: ctype.cpp
$(CPP) -c ctype.cpp -o $(OBJ_FOLDER)/ctype.o $(CFLAGS)
$(OBJ_FOLDER)/memory.o: Memory.cpp
$(CPP) -c Memory.cpp -o $(OBJ_FOLDER)/memory.o $(CFLAGS)
$(OBJ_FOLDER)/path.o: Path.cpp
$(CPP) -c Path.cpp -o $(OBJ_FOLDER)/path.o $(CFLAGS)
$(OBJ_FOLDER)/stack.o: Stack.cpp
$(CPP) -c Stack.cpp -o $(OBJ_FOLDER)/stack.o $(CFLAGS)
$(OBJ_FOLDER)/string.o: String.cpp
$(CPP) -c String.cpp -o $(OBJ_FOLDER)/string.o $(CFLAGS)
$(OBJ_FOLDER)/stringview.o: StringView.cpp
$(CPP) -c StringView.cpp -o $(OBJ_FOLDER)/stringview.o $(CFLAGS)

107
CoreLib/Memory.cpp Normal file
View File

@ -0,0 +1,107 @@
//
// Created by nigel on 19/02/23.
//
#include "Memory.h"
void* memset (void* ptr, int value, size_t num)
{
for( int i = 0; i < num; i++ )
{
unsigned char* data = (unsigned char*)ptr+ i;
*data = (unsigned char)value;
}
return ptr;
}
int memcmp( const void* ptr1, const void* ptr2, size_t num)
{
auto* cs = (const unsigned char*) ptr1;
auto* ct = (const unsigned char*) ptr2;
for (int i = 0 ; i < num ; i++, cs++, ct++ ){
if( *cs != *ct)
return *cs - *ct;
}
return 0;
}
[[maybe_unused]] void memcpy (void* dest, const void* src, size_t count ){
for( int i = 0; i < count; i++){
((char *)dest)[i] = ((const char*)src)[i];
}
}
size_t strlen(const char* str) {
size_t len = 0;
while(str[len]){
len++;
}
return len;
}
int strncmp ( const char* str1, const char* str2, size_t num ){
for( int i = 0; i < num ; i++){
if( str1[i] < str2[i]){
return -1;
}
if( str1[i] > str2[i] ){
return 1;
}
}
return 0;
}
char* strchr(const char* s , int c){
while(*s) {
if(*s == c) return const_cast<char*>(s);
s++;
}
return NULL;
}
char* strtok(char* str, const char* delim , char**saveptr){
char *begin;
if(str) {
begin = str;
}
else if (*saveptr) {
begin = *saveptr;
}
else {
return NULL;
}
while(strchr(delim, begin[0])) {
begin++;
}
char *next = NULL;
for(int i = 0; i < strlen(delim); i++) {
char *temp = strchr(begin, delim[i]);
if(temp < next || next == NULL) {
next = temp;
}
}
if(!next) {
*saveptr = NULL;
return begin;
}
*next = 0;
*saveptr=next+1;
return begin;
}

16
CoreLib/Memory.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
void* memset (void* ptr, int value, size_t num);
int memcmp( const void* ptr1, const void* ptr2, size_t num);
[[maybe_unused]] void memcpy (void* dest, const void* src, size_t count );
size_t strlen(const char* str);
int strncmp ( const char* str1, const char* str2, size_t num );
char* strtok(char* str, const char* delim , char**saveptr);

24
CoreLib/Path.cpp Normal file
View File

@ -0,0 +1,24 @@
//
// Created by nigel on 19/02/23.
//
#include "Path.h"
Path::Path(String path)
: path(path)
{
}
StringView Path::getbasename()
{
unsigned int path_length = path.length();
int i = path_length;
while (path[i] != '/')
i--;
return {path,static_cast<unsigned int>(i +1), path_length};
}
char* Path::str() {
return path.str();
}

22
CoreLib/Path.h Normal file
View File

@ -0,0 +1,22 @@
//
// Created by nigel on 19/02/23.
//
#pragma once
#include <stddef.h>
#include "StringView.h"
class Path{
public:
explicit Path(String path);
StringView getbasename();
char* str();
private:
String path;
};

3
CoreLib/Stack.cpp Normal file
View File

@ -0,0 +1,3 @@
//
// Created by nigel on 19/02/23.
//

73
CoreLib/Stack.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include "../kernel/memory/KernelHeap.h"
#include <stdint.h>
template <typename T>
class Stack {
public:
inline Stack() {
elements = (T[MAX_STACK_SIZE]) malloc(MAX_STACK_SIZE * sizeof(T));
num = 0;
}
inline void Push(T element){
num++;
if(num > MAX_STACK_SIZE)
grow();
element[num] = element;
}
inline T Pop()
{
T temp = elements[num];
num --;
return temp;
}
inline bool isEmpty()
{
return num == 0;
}
inline bool isFull()
{
return num == MAX_STACK_SIZE;
}
inline int count()
{
return num;
}
inline ~Stack()
{
free(elements);
}
private:
unsigned int MAX_STACK_SIZE;
T[MAX_STACK_SIZE] elements;
unsigned int num;
inline void grow (){
MAX_STACK_SIZE = MAX_STACK_SIZE + (int)(MAX_STACK_SIZE / 4);
T[] new_elements =(T[MAX_STACK_SIZE]) malloc(MAX_STACK_SIZE * sizeof(T));
for ( int i = 0; i < num ; i++){
new_elements[i] = elements[i];
}
free(elements);
elements = new_elements;
}
};

39
CoreLib/String.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "String.h"
#include <stdint.h>
#include <stddef.h>
String::String(char* characters)
: chars(characters)
{
}
char* String::str(){
return chars;
}
unsigned int String::length ()
{
int i = 0;
while ( chars[i] != '\0'){
i++;
}
return i;
}
// Returns a null character if size exceeds limits
char String::operator[] (size_t idx)
{
if( idx > this->length())
return '\0';
return chars[idx];
}
const char String::operator[](size_t idx) const {
return (const char) chars[idx];
}

18
CoreLib/String.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <stddef.h>
class String {
public:
String(char* characters);
String(String&) = default;
unsigned int length();
char* str ();
char operator[](size_t index) ;
const char operator[](size_t idx) const;
protected:
char* chars;
};

14
CoreLib/StringView.cpp Normal file
View File

@ -0,0 +1,14 @@
//
// Created by nigel on 19/02/23.
//
#include "StringView.h"
StringView::StringView(String string, unsigned int start, unsigned int end)
: String(string), begin(start), end(end)
{
}
char* StringView::str(){
//TODO: Not implemented
}

14
CoreLib/StringView.h Normal file
View File

@ -0,0 +1,14 @@
//
// Created by nigel on 19/02/23.
//
#pragma once
#include "String.h"
class StringView : String {
public:
StringView(String string, unsigned int start, unsigned int end );
char* str ();
private:
unsigned int begin;
unsigned int end;
};

141
CoreLib/ctype.cpp Normal file
View File

@ -0,0 +1,141 @@
//
// Created by nigel on 25/02/23.
//
#include "ctype.h"
int isupper (int ch){
if( ch >= 'A' && ch <= 'Z'){
return 1;
}
return 0;
}
int islower (int ch){
if(ch >= 'a' && ch <= 'z'){
return 1;
}
return 0;
}
int isalpha (int ch) {
if(isupper(ch)){
return 1;
}
if(islower(ch)){
return 1;
}
return 0;
}
int isdigit (int ch){
if(ch >= '0' && ch <= '9'){
return 1;
}
return 0;
}
int isxdigit (int ch){
if(isdigit(ch)){
return 1;
}
if( ch >= 'a' && ch <= 'f'){
return 1;
}
if( ch >= 'A' && ch <= 'F'){
return 1;
}
return 0;
}
int iscntrl (int ch){
if(ch >= 0x00 && ch <= 0x1f )
return 1;
if(ch == 0x7f)
return 1;
return 0;
}
int isgraph (int ch){
if(isdigit(ch))
return 1;
if(isupper(ch))
return 1;
if(islower(ch))
return 1;
if(ispunct(ch))
return 1;
return 0;
}
int isspace(int ch){
if (ch == 0x20)
return 1;
if(ch == 0x0c)
return 1;
if(ch == 0x0a)
return 1;
if(ch == 0x0d)
return 1;
if(ch == 0x09)
return 1;
if(ch == 0x0b)
return 1;
return 0;
}
int isblank (int ch){
if( ch == 0x20 || ch == 0x09)
return 1;
return 0;
}
int ispunct(int ch){
if(ch >= '!' && ch <= '~')
return 1;
return 0;
}
int isprint (int ch){
if (isdigit(ch))
return 1;
if(isupper(ch))
return 1;
if(islower(ch))
return 1;
if(ispunct(ch))
return 1;
if(isspace(ch))
return 1;
return 0;
}
int tolower(int ch){
if(islower(ch)) return ch;
int diff = 'a' - 'A';
return ch + diff;
}
int toupper(int ch){
if(isupper(ch)) return ch;
int diff = 'a' - 'A';
return ch - diff;
}
int isalnum (int ch){
if(isdigit(ch)){
return 1;
}
if(isalpha(ch)){
return 1;
}
return 0;
}

21
CoreLib/ctype.h Normal file
View File

@ -0,0 +1,21 @@
//
// Created by nigel on 25/02/23.
//
#pragma once
//NOTE: Uses default locale
int isupper (int ch);
int islower (int ch);
int isalpha (int ch);
int isdigit (int ch);
int isxdigit (int ch);
int iscntrl (int ch);
int isgraph(int ch);
int isspace(int ch);
int isblank(int ch);
int ispunct(int ch);
int isprint(int ch);
int isalnum (int ch);
int tolower(int ch);
int toupper(int ch);

View File

@ -1,87 +0,0 @@
EMULATOR = qemu-system-i386
AS = ${HOME}/opt/cross/bin/i686-elf-as
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)/PhysicalMemoryManager.o $(BUILD_DIR)/io.o $(BUILD_DIR)/PageDirectory.o $(BUILD_DIR)/gdtc.o $(BUILD_DIR)/idt.o $(BUILD_DIR)/pic.o $(BUILD_DIR)/string.o
SRC_DIR = src
BUILD_DIR = build
CRTBEGIN_OBJ = $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ = $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
CRTI_OBJ = $(BUILD_DIR)/crti.o
CRTN_OBJ = $(BUILD_DIR)/crtn.o
OBJ_LINK_LIST = $(CRTI_OBJ) $(CRTBEGIN_OBJ) $(OFILES) $(CRTEND_OBJ) $(CRTN_OBJ)
INTERNAL_OBJS = $(CRTI_OBJ) $(OFILES) $(CRTN_OBJ)
all: clean build
build: build_kernel iso
clean_iso:
if [[ -a isodir/boot ]] ; then rm root/boot -rd ; fi
if [ -f build/barinkOS.iso ] ; then rm build/barinkOS.iso ; fi
iso: clean_iso clean build
mkdir -p root/boot/grub
cp build/myos.bin root/boot/myos.bin
cp src/grub.cfg root/boot/grub/grub.cfg
grub-mkrescue -o build/barinkOS.iso root
test:
$(EMULATOR) -kernel $(BUILD_DIR)/myos.bin -serial stdio -vga std -monitor stdio -display gtk -m 2G -cpu core2duo
build_kernel: $(OBJ_LINK_LIST)
$(CC) -T $(SRC_DIR)/kernel//linker.ld -o $(BUILD_DIR)/myos.bin \
-ffreestanding -O2 -nostdlib $(OBJ_LINK_LIST) -lgcc
build_x86_64:
$(AS) $(SRC_DIR)/cgc/x86_64/crti.s -o $(BUILD_DIR)/crti_64.o
$(AS) $(SRC_DIR)/cgc/x86_64/crtn.s -o $(BUILD_DIR)/crtn.o
clean:
rm -f $(BUILD_DIR)/myos.bin $(INTERNAL_OBJS)
$(BUILD_DIR)/kernel.o:
$(CPP) -c $(SRC_DIR)/kernel/kernel.cpp -o $(BUILD_DIR)/kernel.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/kterm.o:
$(CPP) -c $(SRC_DIR)/kernel/tty/kterm.cpp -o $(BUILD_DIR)/kterm.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/boot.o:
$(AS) $(SRC_DIR)/kernel//boot.S -o $(BUILD_DIR)/boot.o
$(BUILD_DIR)/crti.o:
$(AS) $(SRC_DIR)/kernel/crti.s -o $(BUILD_DIR)/crti.o
$(BUILD_DIR)/crtn.o:
$(AS) $(SRC_DIR)/kernel/crtn.s -o $(BUILD_DIR)/crtn.o
$(BUILD_DIR)/io.o:
$(CPP) -c $(SRC_DIR)/kernel/io.cpp -o $(BUILD_DIR)/io.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/PageDirectory.o:
$(CPP) -c $(SRC_DIR)/kernel/memory/PageDirectory.cpp -o $(BUILD_DIR)/PageDirectory.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/idt.o:
$(CPP) -c $(SRC_DIR)/kernel/idt/idt.cpp -o $(BUILD_DIR)/idt.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/gdtc.o:
$(CPP) -c $(SRC_DIR)/kernel/gdt/gdtc.cpp -o $(BUILD_DIR)/gdtc.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/pic.o:
$(CPP) -c $(SRC_DIR)/kernel/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
$(BUILD_DIR)/PhysicalMemoryManager.o:
$(CPP) -c $(SRC_DIR)/kernel/memory/PhysicalMemoryManager.cpp -o $(BUILD_DIR)/PhysicalMemoryManager.o $(CFLAGS) -fno-exceptions -fno-rtti

View File

@ -16,10 +16,24 @@ W.I.P - Working on interrupt handling
![Multiboot integration](screenshots/multiboot.png) \
Multiboot information can be read by the kernel.
![Page faulting](screenshots/PageFault.png) \
Enabled paging and am getting page faults!
![PCI enumeration](screenshots/PCIBusEnumeration.png) \
Enumerating the PCI bus
![ATAPI CD-ROM Identification](screenshots/CD-ROM_Identify.png) \
Correctly identified our ATAPI device 🎉
![Reading Files from FAT-16](screenshots/ReadingFilesFromFAT16.png) \
Reading a FILE from a FAT-16 Formatted drive
________________________
### The goal
Writing a hobby operating system to better understand the basic building blocks of any operating system.
Writing a hobby operating system to better understand the basic building blocks of any operating system.Initially I'd like for my
operating system to be able to run bash.
________________________
### Operating System Technical specs/details

View File

@ -1,29 +1,37 @@
# TODO list
## Start planning
<input type="checkbox" checked/> Setup Cross-Compiler \
<input type="checkbox" checked/> Multiboot to kernel \
<input type="checkbox" checked/> Printing string to the screen \
<input type="checkbox" checked/> Printing values/numbers to the screen (a.k.k itoa) \
## Basics
<label>
<input type="checkbox" checked/>
</label> Setup Cross-Compiler
<input type="checkbox" checked> Multiboot to kernel \
<input type="checkbox" checked/> Printing string to the screen \
<input type="checkbox" checked/> Printing values/numbers to the screen \
<input type="checkbox" checked/> Basic Terminal \
<input type="checkbox" checked/> Extend Multiboot implementation \
<input type="checkbox" checked/> Output to serial port \
<input type="checkbox" checked/> Move to protected mode \
<input type="checkbox" checked/> Enabel CMOS clock \
<input type="checkbox" /> Time measurement (PIC &| PIT) \
<input type="checkbox" checked/> Enable CMOS clock \
<input type="checkbox" checked/> Time measurement (PIC &| PIT) \
<input type="checkbox" /> Detect CPU speed \
<input type="checkbox" checked/> Interrupt / exception system (API) \
<input type="checkbox" checked/> Plan your memory map (virtual, and physical) : decide where you want the data to be. \
<input type="checkbox" /> The heap: allocating memory at runtime (malloc and free) is almost impossible to go without. \
<input type="checkbox" checked/> PCI support \
<input type="checkbox" checked/> ATA PIO Mode support \
<input type="checkbox" checked/> FAT Filesystem \
<input type="checkbox" /> Virtual filesystem \
<input type="checkbox" checked/> Keyboard support ( P/S2 Keyboard) \
<input type="checkbox" checked/> Physical memory management \
<input type="checkbox" checked/> Paging \
<input type="checkbox" checked/> Virtual memory management \
<input type="checkbox" checked/> The heap: allocating memory at runtime (malloc and free) is almost impossible to go without. \
<input type="checkbox" /> Enable SIMD Extensions (SSE)
## Other features I am thinking of:
<input type="checkbox" /> PCI support \
<input type="checkbox" /> ATA PIO Mode support \
<input type="checkbox" checked/> PCI support \
<input type="checkbox" checked/> ATA PIO Mode support \
<input type="checkbox" /> USTAR Filesystem ( For its simplicity this is very likely the first filesystem the OS is going to support) \
<input type="checkbox" /> ACPI support ( Or some other basic way to support shutdown, reboot and possibly hibernation ) \
<input type="checkbox" /> ATAPI support \
<input type="checkbox" /> Keyboard support ( P/S2 Keyboard) \
<input type="checkbox" checked/> Memory Management (MMU)
<input type="checkbox" /> Hardware Management system
<input type="checkbox" /> Preemptive multi tasking \
<input type="checkbox" /> Processes \
<input type="checkbox" /> Threads
@ -32,9 +40,11 @@
<input type="checkbox" /> POSIX compliance (partially) \
<input type="checkbox" /> RPC - for interprocess communication \
<input type="checkbox" /> Sync primitives - Semaphores, Mutexes, spinlocks et al. \
<input type="checkbox" /> Basic Terminal \
<input type="checkbox" /> Extend hardware recognition ( CPU codename, memory, ATA harddisk, RAW diskSpace, CPU speed through SMBIOS et al. ) \
<input type="checkbox" /> ACPI support \
<input type="checkbox" /> ATAPI support \
<input type="checkbox" /> Basic Window server/client \
## Support for more filesystems if I like the challenge in writing these ...
<input type="checkbox" /> FAT Filesystem \
<input type="checkbox" /> EXT2 Filesystem
<input type="checkbox" /> USTAR Filesystem \
<input type="checkbox" /> FAT16 Filesystem \

BIN
images/BarinkOS.png (Stored with Git LFS)

Binary file not shown.

BIN
images/BarinkOS_logo(standard).svg (Stored with Git LFS)

Binary file not shown.

BIN
images/BarinkOS_logo.svg (Stored with Git LFS)

Binary file not shown.

132
kernel/Makefile Normal file
View File

@ -0,0 +1,132 @@
AS = /opt/cross/bin/i686-elf-as
CC = /opt/cross/bin/i686-elf-gcc
CPP = /opt/cross/bin/i686-elf-g++
CFLAGS = -ffreestanding -Og -ggdb -Wall -Wextra -I ../build/CoreLib/include
BUILD_DIR = ../build/kernel
OBJ_DIR = ../bin/kernel
CRTBEGIN_OBJ = $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ = $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
CRTI_OBJ = $(OBJ_DIR)/crti.o
CRTN_OBJ = $(OBJ_DIR)/crtn.o
OFILES = $(OBJ_DIR)/boot.o \
$(OBJ_DIR)/kterm.o \
$(OBJ_DIR)/kernel.o \
$(OBJ_DIR)/memory.o \
$(OBJ_DIR)/paging.o \
$(OBJ_DIR)/VFS.o \
$(OBJ_DIR)/pit.o \
$(OBJ_DIR)/time.o \
$(OBJ_DIR)/keyboard.o \
$(OBJ_DIR)/io.o \
$(OBJ_DIR)/processor.o \
$(OBJ_DIR)/gdtc.o \
$(OBJ_DIR)/idt.o \
$(OBJ_DIR)/pic.o \
$(OBJ_DIR)/sv-terminal.o \
$(OBJ_DIR)/prekernel.o \
$(OBJ_DIR)/KHeap.o \
$(OBJ_DIR)/pci.o \
$(OBJ_DIR)/pcidevice.o \
$(OBJ_DIR)/atapiDevice.o \
$(OBJ_DIR)/ataDevice.o \
$(OBJ_DIR)/rsdp.o \
$(OBJ_DIR)/acpi.o \
$(OBJ_DIR)/fat.o
OBJ_LINK_LIST = $(CRTI_OBJ) $(CRTBEGIN_OBJ) $(OFILES) $(CRTEND_OBJ) $(CRTN_OBJ)
INTERNAL_OBJS = $(CRTI_OBJ) $(OFILES) $(CRTN_OBJ)
all: clean build
clean:
rm $(OBJ_DIR)/* -r
build: $(OBJ_LINK_LIST)
$(CPP) -T linker.ld -o $(BUILD_DIR)/myos.bin -ffreestanding -ggdb -Og -nostdlib $(OBJ_LINK_LIST) -lgcc -L ../build/CoreLib -lCoreLib
# C++ definition -> Object files
$(OBJ_DIR)/kernel.o: kernel.cpp
$(CPP) -c kernel.cpp -o $(OBJ_DIR)/kernel.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/kterm.o:
$(CPP) -c terminal/kterm.cpp -o $(OBJ_DIR)/kterm.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/io.o:
$(CPP) -c io/io.cpp -o $(OBJ_DIR)/io.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/idt.o:
$(CPP) -c interrupts/idt.cpp -o $(OBJ_DIR)/idt.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/gdtc.o:
$(CPP) -c memory/gdt/gdtc.cpp -o $(OBJ_DIR)/gdtc.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/pic.o:
$(CPP) -c drivers/pic/pic.cpp -o $(OBJ_DIR)/pic.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/PhysicalMemoryManager.o:
$(CPP) -c memory/PhysicalMemoryManager.cpp -o $(OBJ_DIR)/PhysicalMemoryManager.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/pci.o:
$(CPP) -c pci/pci.cpp -o $(OBJ_DIR)/pci.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/pcidevice.o:
$(CPP) -c pci/pciDevice.cpp -o $(OBJ_DIR)/pcidevice.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/atapiDevice.o:
$(CPP) -c storage/atapi/atapiDevice.cpp -o $(OBJ_DIR)/atapiDevice.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/ataDevice.o:
$(CPP) -c "storage/ata pio/ATAPIO.cpp" -o $(OBJ_DIR)/ataDevice.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/rsdp.o:
$(CPP) -c acpi/rsdp.cpp -o $(OBJ_DIR)/rsdp.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/acpi.o:
$(CPP) -c acpi/acpi.cpp -o $(OBJ_DIR)/acpi.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/pit.o:
$(CPP) -c drivers/pit/pit.cpp -o $(OBJ_DIR)/pit.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/VFS.o:
$(CPP) -c storage/vfs/vfs.cpp -o $(OBJ_DIR)/VFS.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/keyboard.o:
$(CPP) -c drivers/ps-2/keyboard.cpp -o $(OBJ_DIR)/keyboard.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/time.o:
$(CPP) -c time.cpp -o $(OBJ_DIR)/time.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/sv-terminal.o:
$(CPP) -c supervisorterminal/superVisorTerminal.cpp -o $(OBJ_DIR)/sv-terminal.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/memory.o:
$(CPP) -c memory/PhysicalMemoryManager.cpp -o $(OBJ_DIR)/memory.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/paging.o:
$(CPP) -c memory/VirtualMemoryManager.cpp -o $(OBJ_DIR)/paging.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/KHeap.o:
$(CPP) -c memory/KernelHeap.cpp -o $(OBJ_DIR)/KHeap.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/prekernel.o:
$(CPP) -c prekernel/prekernel.cpp -o $(OBJ_DIR)/prekernel.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/processor.o:
$(CPP) -c i386/processor.cpp -o $(OBJ_DIR)/processor.o $(CFLAGS) -fno-exceptions -fno-rtti
$(OBJ_DIR)/fat.o:
$(CPP) -c storage/filesystems/FAT/FAT.cpp -o $(OBJ_DIR)/fat.o $(CFLAGS) -fno-exceptions -fno-rtti
# Assembly -> Object files
$(OBJ_DIR)/boot.o:
$(AS) boot/boot.s -o $(OBJ_DIR)/boot.o
$(OBJ_DIR)/crti.o:
$(AS) crti.s -o $(OBJ_DIR)/crti.o
$(OBJ_DIR)/crtn.o:
$(AS) crtn.s -o $(OBJ_DIR)/crtn.o

76
kernel/acpi/acpi.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "acpi.h"
#include "../../CoreLib/Memory.h"
#include "../memory/VirtualMemoryManager.h"
RSDPDescriptor* ACPI::rsd_ptr;
RSCPDescriptor20* ACPI::rsd2_ptr;
RSDT* ACPI::rsd_table;
const int KERNEL_OFFSET = 0xC0000000;
void ACPI::initialize(){
// Find the Root System Description Pointer
ACPI::rsd_ptr = FindRSD();
printf("RSD address: 0x%x\n", ACPI::rsd_ptr);
printRSD(rsd_ptr);
if( rsd_ptr->Revision == 0 ){
// Using version 1.0 of the ACPI specification
int sum = rsd_ptr->Checksum;
for (int i =0; i < sizeof(RSDPDescriptor) ; i++) {
sum += ((char*)rsd_ptr)[i];
}
printf(" 0x%x sum\n", sum);
if(sum & 0xfff0)
printf("valid rsd!\n");
else
printf("invalid rsd\n");
printf("rsdp: 0x%x\n", rsd_ptr);
printf("0x%x address\n", (rsd_ptr->RsdtAddress));
Immediate_Map(rsd_ptr->RsdtAddress + KERNEL_OFFSET, rsd_ptr->RsdtAddress);
RSDT* rootSystemDescriptionTable = (RSDT*)(rsd_ptr->RsdtAddress + KERNEL_OFFSET);
//printf("0x%x Root System Descriptor address\n", rootSystemDescriptionTable);
// checksum it, but we'll ignore it for now
printf("signature ");
for (int i = 0; i < 4; i++) {
kterm_put( rootSystemDescriptionTable->h.Signature[i]);
}
kterm_put('\n');
int entries = (rootSystemDescriptionTable->h.Length - sizeof (rootSystemDescriptionTable->h)) /4;
printf("%d num entries\n", entries);
for( int i = 0; i < entries; i++){
ACPISDTHeader* h = (ACPISDTHeader*) rootSystemDescriptionTable->PointerToSDT + i ;
if(strncmp(h->Signature, "FACP", 4)){
printf("Found FACP Entry!\n");
}
}
} else{
// parse it as of version2.0
printf("rsd2_ptr\n");
ACPI::rsd2_ptr = (RSCPDescriptor20*)rsd_ptr;
}
/*
auto tableHeader = &rootSystemDescriptionTable->h;
// do checksum
sum = 0;
for(int i = 0; i < tableHeader->Length; i ++) {
sum += ((char*) tableHeader)[i];
}
if( sum != 0)
printf("Table invalid!");*/
}

14
kernel/acpi/acpi.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "rsdp.h"
class ACPI {
public:
static void initialize();
// In the future ACPI might start
// doing more systems initialization
static RSDPDescriptor* rsd_ptr;
static RSCPDescriptor20* rsd2_ptr;
static RSDT* rsd_table;
private:
};

44
kernel/acpi/rsdp.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "rsdp.h"
#include "../memory/VirtualMemoryManager.h"
#include "../../CoreLib/Memory.h"
void printRSD(RSDPDescriptor* rsd){
printf("Signature: ");
for(int i = 0; i < 8; i++){
kterm_put(rsd->signature[i]);
}
kterm_put('\n');
printf("OEMID: ");
for(int i =0; i < 6 ; i++){
kterm_put (rsd->OEMID[i]);
}
kterm_put('\n');
printf("Revision: %d\n", rsd->Revision);
}
RSDPDescriptor* FindRSD(){
char* memory_byte = (char*) 0x000f2e14;
const void* string = "RSD PTR ";
for( ; (uint32_t) memory_byte < 0x0100000; memory_byte+=10){
if( memcmp(memory_byte , string , 8 ) == 0 ) {
printf("RSD PTR found at 0x%x !\n", memory_byte);
return (RSDPDescriptor*) memory_byte;
break;
}
}
memory_byte = (char*) 0x000E0000;
for ( ;(uint32_t) memory_byte < 0x000FFFFF; memory_byte += 1)
{
if( memcmp(memory_byte , string , 8 ) == 0 ) {
printf("RSD PTR found at 0x%x !\n", memory_byte);
return (RSDPDescriptor*) memory_byte;
break;
}
}
}

45
kernel/acpi/rsdp.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include "../terminal/kterm.h"
#include <CoreLib/Memory.h>
#include <stdint-gcc.h>
struct ACPISDTHeader{
char Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t CheckSum;
char OEMID[6];
char OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
};
struct RSDT{
struct ACPISDTHeader h;
uint32_t *PointerToSDT; // Length of array : (header.Length - sizeof(header))/ 4
}__attribute__((packed));
struct RSDPDescriptor {
char signature[8];
uint8_t Checksum ;
char OEMID [6];
uint8_t Revision;
uint32_t RsdtAddress;
}__attribute__((packed));
struct RSCPDescriptor20{
RSDPDescriptor base;
uint32_t Length;
uint64_t XsdtAddress;
uint8_t ExtendedChecksum;
uint8_t reserved[3];
}__attribute__((packed));
RSDPDescriptor* FindRSD();
void printRSD(RSDPDescriptor* rsd);
RSDT* getRSDT(RSDPDescriptor* rsd);

38
kernel/bitmap.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
inline void bitmap_set( uint32_t* map , int index )
{
map[index/32] |= (1 << (index % 32));
}
inline void bitmap_unset(uint32_t* map , int index)
{
map[index/32] &= ~(1 << (index % 32));
}
inline uint32_t bitmap_first_unset( uint32_t* map , int map_size)
{
for ( int i = 0 ; i < map_size ; i ++ )
{
// a bit or more is set within this byte!
if( (map[i] & 0xFFFFFFFF) > 0 ){
// which bit is set?
for(int j = 0 ; j < 32 ; j++){
if ( (map[i] & (0x00000001 << j)) > 0)
{
return (i*32)+j;
}
}
}
}
return -1;
}

130
kernel/boot/boot.s Normal file
View File

@ -0,0 +1,130 @@
.include "./boot/multiboot.s"
/*
* Allocate initial stack
*/
.section .bootstrap_stack, "aw", @nobits
stack_bottom:
.skip 16384 # 16 KiB
.globl stack_top
stack_top:
/*
* Preallocate a couple pages to get us bootstrapped
* Being carefull to not use any address the bootloader might
* be using for its multiboot structures
*/
.section .bss, "aw", @nobits
.align 4096
.globl boot_page_directory
boot_page_directory:
.skip 4096
.globl boot_page_table
boot_page_table:
.skip 4096
.globl multiboot_page_table
multiboot_page_table:
.skip 4096
# More page tables may be required
# Entry point
.section .multiboot.text, "a"
.globl _start
.type _start, @function
_start:
# Get physical address of the boot_page_table
movl $(boot_page_table - 0xC0000000), %edi
# Map address 0
movl $0, %esi
1:
cmpl $(kernel_end - 0xC0000000), %esi
jge 3f
# Map physical address as "present and writable"
movl %esi, %edx
orl $0x003, %edx
movl %edx, (%edi)
2: # Size of page is 4096 bytes
addl $4096, %esi
# Size of entries in boot_page_table is 4 bytes
addl $4, %edi
# Loop to the next entry if we haven't finished.
loop 1b
3: # Map VGA video memory to 0xC03FF00 as "present, writable"
movl $(0x000B8000 | 0x003), boot_page_table - 0xC0000000 + 1023 * 4
# Map the page table to both virtual addresss 0x00000000 and 0xC0000000
movl $(boot_page_table - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0
movl $(boot_page_table - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4
# Set cr3 to the address of the boot_page_directory
movl $(boot_page_directory - 0xC0000000), %ecx
movl %ecx, %cr3
# Enable paging and the write-protect bit
movl %cr0, %ecx
orl $0x80010000, %ecx
movl %ecx, %cr0
# Jump to higher half with an absolute jump
lea 4f, %ecx
jmp *%ecx
.section .text
4:
# At this point, paging is fully set up and enabled
isPaging:
# Reload cr3 to force tlb flush
movl %cr3, %ecx
movl %ecx, %cr3
/*Setup the stack pointer to point to the beginning of our stack */
/* I believe its a high address growing down to lower adress for the stack on x86*/
mov $stack_top, %esp
/*Reset EFLAGS*/
pushl $0
popf
/* push the pointer to the Multiboot information structure*/
pushl %ebx
/* push the magic value */
pushl %eax
call prekernelSetup
# Unmap the identity mapping as it is now unnecessary
# movl $0, boot_page_directory + 0
call kernel
cli
1: hlt
jmp 1b
.include "./memory/gdt/gdt.s"
.include "./irs_table.s"
.include "./irq_table.s"
.include "./interrupts/idt.s"
.globl jump_usermode
jump_usermode:
mov $((4*8) | 3) , %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %esp, %eax
push $( (3*8) | 3)
push %eax
pushf
push $( ( 3 * 8) | 3)
push startSuperVisorTerminal
iret

15
kernel/boot/multiboot.s Normal file
View File

@ -0,0 +1,15 @@
/*
* Multiboot
*/
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
.section .multiboot.data, "aw"
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM

View File

@ -1,8 +1,8 @@
#pragma once
#include "bootloader/multiboot.h"
#include "prekernel/multiboot.h"
#define CHECK_FLAG(flags, bit) ((flags) & (1 <<(bit)))
#include "tty/kterm.h"
#include "terminal/kterm.h"
@ -10,66 +10,81 @@ void CheckMBT ( multiboot_info_t* mbt ){
/* Set MBI to the addresss of the multiboot information structure*/
multiboot_info_t * mbi = (multiboot_info_t *) mbt;
#ifdef __VERBOSE__
/* Print out the flags */
printf("flags = 0x%x\n", (unsigned) mbi->flags);
#endif
/* Are mem_* valid? */
if ( CHECK_FLAG(mbi->flags,0)){
printf("mem_lower = %uKB, mem_upper = %uKB\n");
// Do nothing
}
/* is boot device valid ? */
if (CHECK_FLAG (mbi->flags, 1)){
if (CHECK_FLAG (mbi->flags, 1))
{
#ifdef __VERBOSE__
printf("boot_device = 0x0%x\n", (unsigned) mbi->boot_device);
#endif
}
/* is the command line passed? */
if (CHECK_FLAG ( mbi->flags,2)){
if (CHECK_FLAG ( mbi->flags,2))
{
#ifdef __VERBOSE__
printf("cmdline = %s\n", (char *) mbi->cmdline);
#endif
}
/* Are mods_* valid? */
if(CHECK_FLAG ( mbi->flags, 3)){
multiboot_module_t *mod;
uint32_t i;
#ifdef __VERBOSE__
printf("mods count = %d, mods_addr = 0x%x\n", (int) mbi->mods_count, (int) mbi->mods_addr);
for(i = 0, mod = (multiboot_module_t *) mbi->mods_addr; i < mbi->mods_count; i++ , mod++){
printf(" mod start = 0x%x, mod_end = 0x%x, cmdline = %s\n", (unsigned) mod->mod_start, (unsigned) mod->mod_end, (char*) mod->cmdline);
}
#endif
}
/* Bits 4 and 5 are mutually exclusive! */
if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG(mbi->flags, 5)){
if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG(mbi->flags, 5))
{
#ifdef __VERBOSE__
printf("Both bits 4 and 5 are set.\n");
#endif
return;
}
/* Is the symbol table of a.out valid? */
if (CHECK_FLAG(mbi->flags, 4)){
multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym);
#ifdef __VERBOSE__
printf( "multiboot_aout_symbol_table: tabsize = 0x%0x, strsize = 0x%x, addr = 0x%x\n",
(unsigned) multiboot_aout_sym->tabsize,
(unsigned) multiboot_aout_sym->strsize,
(unsigned) multiboot_aout_sym->addr);
#endif
}
/* Is the section header table of ELF valid? */
if (CHECK_FLAG(mbi->flags, 5)){
multiboot_elf_section_header_table_t *multiboot_elf_sec = &(mbi->u.elf_sec);
#ifdef __VERBOSE__
printf("multiboot_elf_sec: num = %u, size = 0x%x, addr = 0x%x, shnd = 0x%x\n",
(unsigned) multiboot_elf_sec->num, (unsigned) multiboot_elf_sec->size,
(unsigned) multiboot_elf_sec->addr, (unsigned) multiboot_elf_sec->shndx);
#endif
}
/* Draw diagonal blue line */
if (CHECK_FLAG (mbt->flags, 12)){
printf("Can draw!");
#ifdef __VERBOSE__
printf("Can draw!\n");
#endif
}

9
kernel/bootinfo.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "memory/memoryinfo.h"
struct BootInfo{
const char* BootStructureID = "BarinkOS";
MemoryInfo* memory;
};

9
kernel/definitions.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
/**
* Kernel definitions
*/
#define __DEBUG__ false
#define KERNEL_VERSION 0.03
#define ARCHITECTURE "I386"

View File

@ -0,0 +1,11 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
class BlockDevice {
virtual char* Read()=0;
virtual void Write() =0;
};

View File

@ -0,0 +1,11 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
class CharacterDevice {
virtual char Read()=0;
virtual void Write()=0;
};

View File

@ -0,0 +1,38 @@
void ReadFromCMOS(unsigned char array[])
{
unsigned char tvalue, index;
for (index = 0; index < 128; index++)
{
asm(
"cli\n\t" // Disable interrupts
"mov al, index\n\t" // Move index address
// since the 0x80 bit of al is not set, NMI is active
"out 0x70,al\n\t" // Copy address to CMOS register
// some kind of real delay here is probably best
"in al,0x71\n\t" // Fetch 1 byte to al
"sti\n\t" // Enable interrupts
"mov tvalue,al\n\t");
array[index] = tvalue;
}
}
void WriteTOCMOS(unsigned char array[])
{
unsigned char index;
for(index = 0; index < 128; index++)
{
unsigned char tvalue = array[index];
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
"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

@ -1,5 +1,7 @@
#pragma once
#include "../io.h"
#pragma once
#include <stdint-gcc.h>
#include "../../io/io.h"
#define PIC1 0x20 /* IO base address for master PIC */
#define PIC2 0xA0 /* IO base address for slave PIC */

View File

@ -0,0 +1,54 @@
#include "pit.h"
#include "../../terminal/kterm.h"
uint32_t pit_tick = 0;
void pit_initialise()
{
asm volatile("CLI");
#ifdef __VERBOSE__
printf("Init PIT!\n");
#endif
// clear mask for IRQ 0
uint8_t value = inb(0x21) & ~(1<< 0);
outb(0x21, value);
io_wait();
const int freq = 500;
uint32_t divisor = 1193180 / freq;
outb(PIT_COMMAND, 0x36);
uint8_t l = (uint8_t) (divisor & 0xFF);
uint8_t h = (uint8_t) ( (divisor>>8) & 0xff);
outb(PIT_DATA_0, l);
outb(PIT_DATA_0,h);
asm volatile("STI");
}
void get_pit_count()
{
asm volatile ("CLI");
outb(PIT_COMMAND, 0);
uint16_t count = inb(PIT_DATA_0);
count |= inb(PIT_DATA_0) << 8;
printf("PIT count: 0x%x\n", count);
asm volatile("STI");
}
void set_pit_count()
{
}

18
kernel/drivers/pit/pit.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <stdint-gcc.h>
#include "../../io/io.h"
#define PIT_DATA_0 0x40
#define PIT_DATA_1 0x41
#define PIT_DATA_2 0x42
#define PIT_COMMAND 0x43
extern uint32_t pit_tick;
void pit_initialise();
void get_pit_count();
void set_pit_count();

View File

@ -0,0 +1,51 @@
#include "keyboard.h"
KeyPressInfo keyPress {};
void KeyHandled(){
keyPress.ScanCode= 0x00;
keyPress.PressedModifiers = 0x00;
}
char getASCIIKey(){
char keyPressed;
// Wait until a key is pressed
while(keyPress.ScanCode == 0x00) {
asm volatile ("NOP");
}
// Translate keycode to ascii
// Probably a lookup table might be handy
// Until 0x37
const char* ASCIILookUp =
"\01234567890-=\0\0QWERTYUIOP[]\0\0ASDFGHJKL;\'`\0\\ZXCVBNM,./\0";
uint8_t ASCII_Index = keyPress.ScanCode - 3 ;
//printf("ASCII_INDEX: %x\n", ASCII_Index);
keyPressed = ASCIILookUp[ASCII_Index];
KeyHandled();
return keyPressed;
}
uint8_t getKey(){
// Wait until a key is pressed
while(keyPress.ScanCode == 0x00){
asm volatile ("NOP");
}
if( keyPress.ScanCode > 0x37){
keyPress.ScanCode = 0x00;
return 0;
}
uint8_t ScanCode = keyPress.ScanCode;
// KeyHandled();
return ScanCode ;
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
#include "../../terminal/kterm.h"
enum ScanCodeSet {
None = 0,
ScanCodeSet1 = 1,
ScanCodeSet2 = 2,
ScanCodeSet3 = 3,
};
enum Modifiers {
LSHIFT = 1,
RSHIFT = 2,
LCTRL = 3,
RCTRL = 4,
LALT = 5,
RALT = 6
};
struct KeyPressInfo{
uint8_t PressedModifiers;
uint8_t ScanCode;
};
extern KeyPressInfo keyPress;
void KeyHandled();
char getASCIIKey();
uint8_t getKey();

8
kernel/grub.cfg Normal file
View File

@ -0,0 +1,8 @@
GRUB_DEFAULT=0
GRUB_TIMEOUT=-1
GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUITE=true
menuentry "BarinkOS" {
multiboot /boot/myos.bin
}

2
kernel/i386/README.md Normal file
View File

@ -0,0 +1,2 @@
# architecture specific implementations
## This will contain I386 Architecture specific implementations

127
kernel/i386/processor.cpp Normal file
View File

@ -0,0 +1,127 @@
//
// Created by nigel on 17/02/23.
//
#include "processor.h"
uint32_t processor::cap_page;
uint32_t processor::cap_page1;
uint32_t processor::cap_page7 ;
void processor::initialize()
{
asm volatile ("movl $0x80000001, %%eax;"
"CPUID;"
"movl %%edx, %0"
:: "m"(cap_page));
asm volatile ("movl $0x01, %%eax; "
"CPUID;"
"movl %%edx, %0"
:: "m"(cap_page1));
asm volatile ("movl $0x07, %%eax;"
"movl $0x0, %%ecx;"
"CPUID;"
"movl %%edx, %0"
:: "m"(cap_page7));
}
bool processor::hasAMXExtension()
{
return (cap_page7 & AMX_TYPE::AMX_BF16) || (cap_page7 & AMX_TYPE::AMX_TILE) || (cap_page7 & AMX_TYPE::AMX_INT8);
}
/*
* PSE: page-size extensions for 32-bit paging.
* If CPUID.01H:EDX.PSE [bit 3] = 1, CR4.PSE may be set to 1, enabling support for 4-MByte pages with 32-bit paging
*/
bool processor::has32bitPagingSupport() {
// is the PSE bit set
return cap_page1 & (0x1 << 3);
}
/*
* PAE: physical-address extension.
* If CPUID.01H:EDX.PAE [bit 6] = 1, CR4.PAE may be set to 1, enabling PAE paging (this setting is also required
* for 4-level paging and 5-level paging).
*/
bool processor::hasPAEExtension(){
return cap_page1 & (0x1 << 6);
}
/*
* PGE: global-page support.
* If CPUID.01H:EDX.PGE [bit 13] = 1, CR4.PGE may be set to 1, enabling the global-page feature (see Section
* 4.10.2.4).
*/
bool processor::hasPageSupport(){
return cap_page1 & (0x1 << 13);
}
/*
* Page1GB: 1-GByte pages.
* If CPUID.80000001H:EDX.Page1GB [bit 26] = 1, 1-GByte pages may be supported with 4-level paging and 5-
* level paging (see Section 4.5).
*/
bool processor::gigabytePages() {
return cap_page & (0x1 << 26);
}
void processor::enable_protectedMode()
{
// Set the protected bit of control register 0
// this will put the CPU into protected mode
// NOTE: This should really be an assembly procedure
// We cant directly write to control register 0
// therefor we copy the value of control register 0 into eax
// once we are done manipulating the value we write the value in
// eax back to control register 0
asm volatile("mov %cr0, %eax ");
asm volatile("or $1, %eax");
asm volatile("mov %eax, %cr0");
}
uint32_t processor::GetEFLAGS()
{
uint32_t EFLAGS = 0;
asm volatile ("pushfl;" "movl 4(%%esp), %%edx" : "=d"(EFLAGS));
return EFLAGS;
}
uint32_t processor::GetCR0()
{
uint32_t cr0_value;
asm volatile ("movl %%cr0, %%edx" : "=d"(cr0_value));
return cr0_value;
}
uint32_t processor::GetCR2(){
uint32_t cr2_value;
__asm__ volatile("movl %%cr2, %%edx": "=d"(cr2_value));
return cr2_value;
}
uint32_t processor::GetCR3(){
uint32_t cr3_value;
__asm__ volatile("movl %%cr3, %%edx": "=d"(cr3_value));
return cr3_value;
}
uint32_t processor::GetCR4(){
uint32_t cr4_value;
__asm__ volatile("movl %%cr4, %%edx": "=d"(cr4_value));
return cr4_value;
}

36
kernel/i386/processor.h Normal file
View File

@ -0,0 +1,36 @@
//
// Created by nigel on 17/02/23.
//
#pragma once
#include "../terminal/kterm.h"
class processor {
public:
static void initialize();
// Based on information from https://en.wikichip.org/wiki/x86/amx#Detection
enum AMX_TYPE{
AMX_BF16 = (0x1 << 22),
AMX_TILE = (0x1 << 24),
AMX_INT8 = (0x1 << 25)
};
static bool hasAMXExtension();
static bool has32bitPagingSupport();
static bool hasPageSupport();
static bool gigabytePages();
static bool hasPAEExtension();
static void enable_protectedMode();
static uint32_t GetEFLAGS();
static uint32_t GetCR0();
static uint32_t GetCR2();
static uint32_t GetCR3();
static uint32_t GetCR4();
private:
static uint32_t cap_page;
static uint32_t cap_page1;
static uint32_t cap_page7;
};

427
kernel/interrupts/idt.cpp Normal file
View File

@ -0,0 +1,427 @@
#include "idt.h"
#include "../drivers/pit/pit.h"
#include "../drivers/ps-2/keyboard.h"
#include "../i386/processor.h"
#include "../memory/VirtualMemoryManager.h"
#include "../syscalls.h"
IDT_entry idt_table[256];
IDT_ptr idt_ptr;
void set_id_entry (uint8_t num , uint32_t base, uint16_t sel, uint8_t flags){
idt_table[num].offset_1 = base & 0xFFFF;
idt_table[num].selector = sel;
idt_table[num].zero = 0;
idt_table[num].type_attr = flags;
idt_table[num].offset_2 = (base >> 16) & 0xFFFF;
};
void irs_handler (registers* regs) {
uint32_t FaultingAddress;
printf("(IRS) Interrupt number: %d \n EAX: ", regs->int_no, regs->eax);
switch (regs->int_no)
{
case 0:
// Divide Error #DE
printf("#DE\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 1:
// Debug Exception #DB
printf("#DB\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 2:
// NMI Interrupt
printf("#NMI\n");
break;
case 3:
// Breakpoint Exception #BP
printf("#BP\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 4:
// Overflow Exception #OF
printf("#OF\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 5:
// BOUND Range Exceeded Exception #BR
printf("#BR\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 6:
// Invalid OpCode Exception #UD
printf("#UD\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 7:
// Device Not Available Exception #NM
printf("#NM\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 8:
// Double Fault Exception #DF
printf("#DF\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
while(true);
break;
case 9:
// Coprocessor Segment Overrun
printf("Coprocessor Segment overrun!\n");
break;
case 10:
// Invalid TSS Exception #TS
printf("#TS\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
__asm__("cli;" "1: hlt;" "jmp 1b;");
break;
case 11:
// Segment Not Present #NP
printf("#NP\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 12:
// Stack Fault Exception #SS
printf("#SS\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 13:{
// General Protection Exception #GP
printf("#GP\n");
printf("Accessing memory caused a general protection exception.\n");
printf("Faulting instruction at addres: 0x%x\n", regs->eip );
printf("Error code: 0x%x\n", regs->err_code);
if (regs->err_code != 0){
printf("Fault due to entry at index: 0x%x (%d)\n", (regs->err_code >> 3 & 0xFFF ) , regs->err_code);
uint8_t table = regs->err_code >> 1 & 0x3 ;
if(table == 0 ){
printf("* Index references GDT\n");
}
if(table == 1 ){
printf("* Index references IDT\n");
}
if(table == 2 ){
printf("* Index references LDT\n");
}
if(table == 3 ){
printf("* Index references IDT\n");
}
if( regs->err_code & 0x1)
{
printf("* Originated externally!\n");
}
}
__asm__("cli;" "1: hlt;" "jmp 1b;");
}
break;
case 14:
// Page Fault Exception #PF
printf("#PF\n");
#define ALIGN(addr, align) (((addr) & ~((align) - 1)) + (align))
FaultingAddress = processor::GetCR2();
printf("Accessing the linear address 0x%x resulted in a page fault!\n\n", FaultingAddress);
// Error code of 32 bits are on the stack
// CR2 register contains the 32-bit linear virtual address that generated the exception
// See Intel Software Developers manual Volume 3A Part 1 page 236 for more info
#define PF_ERR_PRESENT_BIT 0x1
#define PF_ERR_WRITE_BIT 0x2
#define PF_ERR_USER_BIT 0x3
#define PF_ERR_RESERVERD_WRITE_BIT 0x4
#define PF_ERR_INSTRUCTION_FETCH_BIT 0x5
#define PF_ERR_PROTECTION_KEY_BIT 0x6
#define PF_ERR_SHADOW_STACK_BIT 0x7
#define PF_ERR_SOFTWARE_GUARD_EXTENSION_BIT 0xE
printf("REASON: \n\n");
if (regs->err_code & PF_ERR_PRESENT_BIT ){
printf("* Page protection violation!\n");
} else{
printf("* Page not-present!\n");
//Immediate_Map(FaultingAddress, FaultingAddress);
}
if(regs->err_code & PF_ERR_WRITE_BIT){
printf("* Write access violation!\n");
} else{
printf("* Read access violation!\n");
}
if(regs->err_code & PF_ERR_USER_BIT){
printf("* Violation from user-space (CPL=3)\n");
}
if(regs->err_code & PF_ERR_INSTRUCTION_FETCH_BIT){
printf("* Caused by an instruction fetch. \n");
}
__asm__("cli;" "1: hlt;" "jmp 1b;");
break;
case 16:
// x87 FPU Floating-point Error #MF
printf("#MF\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 17:
// Alignment Check Exception #AC
printf("#AC\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 18:
// Machine-Check Exception #MC
printf("#MC\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 19:
// SIMD Floating-point Exception #XM
printf("#XM\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 20:
// Virtualization Exception #VE
printf("#VE\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 21:
// Control Protection Exception #CP
printf("#CP\n");
printf("EIP: 0x%x\n", regs->eip);
printf("EAX: 0x%x\n", regs->eax);
printf("EBP: 0x%x\n", regs->ebp);
break;
case 50:
printf("SYSTEMCALL\n");
printf("EAX 0x%x\n", regs->eax);
switch (regs->eax) {
case 0x0:
printf("test!\n");
break;
case 0x5:
sys_open();
break;
case 0x10:
sys_read((FILE*)regs->ebx, (char*)regs->ecx);
break;
case 0x20:
sys_write((FILE*)regs->ebx, (const char*)regs->ecx, regs->edx);
break;
case 0x666:
sys_version();
break;
};
break;
default:
// PANIC!!!
break;
}
}
void irq_handler (registers regs) {
switch (regs.int_no) {
case 0:
pit_tick++;
break;
case 1:
// Keyboard interrupt !!
int scan;
int i;/*register*/
// Read scancode
scan = inb(0x60);
// Send ack message!
i = inb(0x61);
outb(0x61, i|0x80);
outb(0x61, i);
// NOTE: check for special scan codes
// e.g. modifiers etc..
if( scan < 0x37){
//printf("Read from IO: 0x%x\n", scan);
keyPress.ScanCode = scan ;
//printf( "[From Interrupt] Scancode: %x\n", keyPress.ScanCode);
}
break;
case 12:
// PS2 Mouse interrupt
printf("Mouse event triggered!");
//int event = inb(0x60);
break;
default:
//printf("Interrupt happened!");
//printf("Received INT: 0x%x\n", regs.int_no);
break;
}
outb(0x20, 0x20); // send end of interrupt to master
if ( regs.int_no > 8 && regs.int_no <= 15) {
outb(0xA0, 0x20); // send end of interrupt to slave
}
if( regs.int_no == 13){
printf(" Error code: %d \n", regs.err_code);
}
}
void initidt(){
// Initialize the IDT pointer
idt_ptr.length = sizeof(IDT_entry) * 255;
idt_ptr.base = (uint32_t)&idt_table;
#ifdef __VERBOSE__
printf("Init IDT\n");
#endif
// TODO: Set everything to zero first
set_id_entry(0, (uint32_t) irs0 , 0x08, 0x8F);
set_id_entry(1, (uint32_t) irs1 , 0x08, 0x8E);
set_id_entry(2, (uint32_t) irs2 , 0x08, 0x8E);
set_id_entry(3, (uint32_t) irs3 , 0x08, 0x8E);
set_id_entry(4, (uint32_t) irs4 , 0x08, 0x8E);
set_id_entry(5, (uint32_t) irs5 , 0x08, 0x8E);
set_id_entry(6, (uint32_t) irs6 , 0x08, 0x8E);
set_id_entry(7, (uint32_t) irs7 , 0x08, 0x8E);
set_id_entry(8, (uint32_t) irs8 , 0x08, 0x8E);
set_id_entry(9, (uint32_t) irs9 , 0x08, 0x8E);
set_id_entry(10, (uint32_t) irs10 , 0x08, 0x8E);
set_id_entry(11, (uint32_t) irs11 , 0x08, 0x8E);
set_id_entry(12, (uint32_t) irs12 , 0x08, 0x8E);
set_id_entry(13, (uint32_t) irs13 , 0x08, 0x8E);
set_id_entry(14, (uint32_t) irs14 , 0x08, 0x8E);
set_id_entry(15, (uint32_t) irs15 , 0x08, 0x8E);
set_id_entry(16, (uint32_t) irs16 , 0x08, 0x8E);
set_id_entry(17, (uint32_t) irs17 , 0x08, 0x8E);
set_id_entry(18, (uint32_t) irs18 , 0x08, 0x8E);
set_id_entry(19, (uint32_t) irs19 , 0x08, 0x8E);
set_id_entry(20, (uint32_t) irs20 , 0x08, 0x8E);
set_id_entry(21, (uint32_t) irs21 , 0x08, 0x8E);
set_id_entry(22, (uint32_t) irs22 , 0x08, 0x8E);
set_id_entry(23, (uint32_t) irs23 , 0x08, 0x8E);
set_id_entry(24, (uint32_t) irs24 , 0x08, 0x8E);
set_id_entry(25, (uint32_t) irs25 , 0x08, 0x8E);
set_id_entry(26, (uint32_t) irs26 , 0x08, 0x8E);
set_id_entry(27, (uint32_t) irs27 , 0x08, 0x8E);
set_id_entry(28, (uint32_t) irs28 , 0x08, 0x8E);
set_id_entry(29, (uint32_t) irs29 , 0x08, 0x8E);
set_id_entry(30, (uint32_t) irs30 , 0x08, 0x8E);
set_id_entry(31, (uint32_t) irs31 , 0x08, 0x8E);
set_id_entry(0x50, (uint32_t) irs50, 0x08, 0x8E);
//print_serial("Remapping PIC\n");
PIC_remap(0x20, 0x28);
// clear mask for IRQ 12
uint8_t value = inb(0x21) & ~(1<< 12);
outb(0x21, value);
// pic IRQ Table
set_id_entry(32, (uint32_t)irq0, 0x08, 0x8E);
set_id_entry(33, (uint32_t)irq1, 0x08, 0x8E); // PS2 Keyboard
set_id_entry(34, (uint32_t)irq2, 0x08, 0x8E);
set_id_entry(35, (uint32_t)irq3, 0x08, 0x8E);
set_id_entry(36, (uint32_t)irq4, 0x08, 0x8E);
set_id_entry(37, (uint32_t)irq5, 0x08, 0x8E);
set_id_entry(38, (uint32_t)irq6, 0x08, 0x8E);
set_id_entry(39, (uint32_t)irq7, 0x08, 0x8E);
set_id_entry(40, (uint32_t)irq8, 0x08, 0x8E);
set_id_entry(41, (uint32_t)irq9, 0x08, 0x8E);
set_id_entry(42, (uint32_t)irq10, 0x08, 0x8E);
set_id_entry(43, (uint32_t)irq11, 0x08, 0x8E);
set_id_entry(44, (uint32_t)irq12, 0x08, 0x8E); // PS2 Mouse
set_id_entry(45, (uint32_t)irq13, 0x08, 0x8E);
set_id_entry(46, (uint32_t)irq14, 0x08, 0x8E);
set_id_entry(47, (uint32_t)irq15, 0x08, 0x8E);
idt_flush((uint32_t)&idt_ptr);
}

View File

@ -1,11 +1,11 @@
#pragma once
#include "stdint.h"
#include "stddef.h"
#include "../vga/colors.h"
#include "../pic/pic.h"
#include <stdint.h>
#include <stddef.h>
#include "../drivers/vga/colors.h"
#include "../drivers/pic/pic.h"
#include "../tty/kterm.h"
#include "../terminal/kterm.h"
extern "C" {
@ -32,11 +32,11 @@ extern "C" {
extern void idt_flush(uint32_t);
void set_id_entry (uint8_t num , uint32_t base, uint16_t sel, uint8_t flags);
void init_idt();
void initidt();
void irq_handler (registers regs);
void irs_handler (registers regs);
void irs_handler (registers* regs);
extern void irs0 ();
extern void irs1 ();
@ -70,6 +70,7 @@ extern "C" {
extern void irs29 ();
extern void irs30 ();
extern void irs31 ();
extern void irs50();

View File

@ -12,9 +12,10 @@ unsigned short inw_p(unsigned short ){
// TODO: implement me!
return 0;
}
unsigned int inl(unsigned short ){
// TODO: implement me!
return 0;
uint32_t inl( int port ){
unsigned int data;
asm volatile ("inl %w1, %0": "=a" (data): "d" (port));
return data;
}
unsigned int inl_p(unsigned short ){
// TODO: implement me!
@ -22,7 +23,7 @@ unsigned int inl_p(unsigned short ){
}
void outb_p(unsigned char , unsigned short ){
void b_p(unsigned char , unsigned short ){
}
void outw(unsigned short , unsigned short ){
@ -31,9 +32,12 @@ void outw(unsigned short , unsigned short ){
void outw_p(unsigned short , unsigned short ){
}
void outl(unsigned int , unsigned short ){
void outl( int port , uint32_t data ){
asm volatile ("outl %0, %1" :: "a" (data), "dn"(port));
}
void outl_p(unsigned int , unsigned short ){
}

View File

@ -12,21 +12,17 @@ static inline uint8_t inb(uint16_t port)
unsigned char inb_p(unsigned short port);
unsigned short inw(unsigned short port);
unsigned short inw_p(unsigned short port);
unsigned int inl(unsigned short port);
uint32_t inl( int port );
unsigned int inl_p(unsigned short port);
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
* The outb %al, %dx encoding is the only option for all other cases.
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
}
void outb_p(unsigned char value, unsigned short port);
void outw(unsigned short value, unsigned short port);
void outw_p(unsigned short value, unsigned short port);
void outl(unsigned int value, unsigned short port);
void outl( int port , uint32_t data );
void outl_p(unsigned int value, unsigned short port);
void insb(unsigned short port, void *addr,

55
kernel/irq_table.s Normal file
View File

@ -0,0 +1,55 @@
.globl irq0
.macro IRQ NAME, VECTOR
.globl irq\NAME
irq\NAME:
cli
push $0
push \VECTOR
jmp irq_common
.endm
IRQ 0 $0
IRQ 1 $1
IRQ 2 $2
IRQ 3 $3
IRQ 4 $4
IRQ 5 $5
IRQ 6 $6
IRQ 7 $7
IRQ 8 $8
IRQ 9 $9
IRQ 10 $10
IRQ 11 $11
IRQ 12 $12
IRQ 13 $13
IRQ 14 $14
IRQ 15 $15
irq_common:
pusha
mov %ds, %ax
push %eax
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
call irq_handler
pop %eax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
popa
add $8, %esp # cleans push error and irs code
sti
iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

87
kernel/irs_table.s Normal file
View File

@ -0,0 +1,87 @@
.code32
/*
* Interupt handlers
*/
.macro ISR_NOERRORCODE NAME, VECTOR
.globl irs\NAME
irs\NAME:
cli
push $0
push \VECTOR
jmp irs_common
.endm
.macro ISR_ERROCODE NAME, VECTOR
.globl irs\NAME
irs\NAME:
cli
push \VECTOR
jmp irs_common
.endm
ISR_NOERRORCODE 0 $0
ISR_NOERRORCODE 1 $1
ISR_NOERRORCODE 2 $2
ISR_NOERRORCODE 3 $3
ISR_NOERRORCODE 4 $4
ISR_NOERRORCODE 5 $5
ISR_NOERRORCODE 6 $6
ISR_NOERRORCODE 7 $7
ISR_NOERRORCODE 8 $8
ISR_NOERRORCODE 9 $9
ISR_NOERRORCODE 10 $10
ISR_NOERRORCODE 11 $11
ISR_NOERRORCODE 12 $12
ISR_NOERRORCODE 13 $13
ISR_NOERRORCODE 14 $14
ISR_NOERRORCODE 15 $15
ISR_NOERRORCODE 16 $16
ISR_NOERRORCODE 17 $17
ISR_NOERRORCODE 18 $18
ISR_NOERRORCODE 19 $19
ISR_NOERRORCODE 20 $20
ISR_NOERRORCODE 21 $21
ISR_NOERRORCODE 22 $22
ISR_NOERRORCODE 23 $23
ISR_NOERRORCODE 24 $24
ISR_NOERRORCODE 25 $25
ISR_NOERRORCODE 26 $26
ISR_NOERRORCODE 27 $27
ISR_NOERRORCODE 28 $28
ISR_NOERRORCODE 29 $29
ISR_NOERRORCODE 30 $30
ISR_NOERRORCODE 31 $31
ISR_NOERRORCODE 50 $50
irs_common:
pusha # Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov %ds, %ax
push %eax
/* load the kernel data segment descriptor*/
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %esp, %eax
push %eax
call irs_handler
pop %eax // pop stack pointer
pop %ebx // reload ther orignal data segment descriptor
mov %bx, %ds
mov %bx, %es
mov %bx, %fs
mov %bx, %gs
popa
add $8, %esp # cleans push error and irs code
iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

82
kernel/kernel.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
Copyright © Nigel Barink 2023
*/
#include "memory/memory.h"
#include "memory/KernelHeap.h"
#include "memory/gdt/gdtc.h"
#include "memory/TaskStateSegment.h"
#include "supervisorterminal/superVisorTerminal.h"
#include "drivers/vga/VBE.h"
#include "pci/pci.h"
#include "drivers/pit/pit.h"
#include "i386/processor.h"
#include "terminal/kterm.h"
#include "interrupts/idt.h"
#include "serial.h"
#include "storage/vfs/vfs.h"
#include "storage/filesystems/FAT/FAT.h"
#include "acpi/acpi.h"
#include "memory/VirtualMemoryManager.h"
extern BootInfoBlock* BIB;
extern "C" void LoadGlobalDescriptorTable();
extern "C" void jump_usermode();
void initBootDrive(){
printf("Boot device: 0x%x\n", BIB->bootDeviceID);
unsigned int part3 = BIB->bootDeviceID & 0xFF;
unsigned int part2 = (BIB->bootDeviceID & 0xFF00) >> 8;
unsigned int part1 = (BIB->bootDeviceID & 0xFF0000) >> 16;
unsigned int drive = (BIB->bootDeviceID & 0xFF000000) >> 24;
if (drive == 0x80 )
printf("booted from disk!\n");
if(drive == 0x00)
printf("booted from floppy disk\n");
printf("Part1: %d, Part2: %d, Part3: %d\n", part1, part2 , part3);
ATAPIO::Identify(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
}
extern "C" void kernel ()
{
init_serial();
kterm_init();
print_serial("kterm initialized...\n");
setup_tss();
initGDT();
initidt();
LoadGlobalDescriptorTable();
flush_tss();
printf("Memory setup complete!\n");
print_serial("Memory initialized....\n");
// Enable interrupts
asm volatile("STI");
initHeap();
print_serial("Heap initialized...\n");
//pit_initialise();
//ACPI::initialize();
//PCI::Scan();
processor::initialize();
processor::enable_protectedMode();
initBootDrive();
VirtualFileSystem::initialize();
print_serial("Run test!");
#define VFS_EXAMPLE
#ifdef VFS_EXAMPLE
auto fontFile = VirtualFileSystem::open("/FONT PSF", 0);
printf("Size of font file: %d bytes", fontFile->root->size); // COOL This Works like a charm
#endif
#ifdef USERMODE_RELEASE
// Lets jump into user mode
jump_usermode();
#else
startSuperVisorTerminal();
#endif
}

8
kernel/kernel.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#define CHECK_FLAG(flags, bit) ((flags) & (1 <<(bit)))
#define PANIC(message) {return;}

45
kernel/linker.ld Normal file
View File

@ -0,0 +1,45 @@
ENTRY(_start)
/* Tell where the various sections of the object files will be put in the final
kernel image. */
SECTIONS
{
. = 0x00100000; /* place code at 1MB mark*/
_kernel_start = .;
kernel_begin = .; /* For legacy reasons */
.multiboot.data : {
*(.multiboot.data)
}
.multiboot.text : {
*(multiboot.text)
}
. += 0xC0000000; /* Addresses in the following code need to be above the 3Gb mark */
.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
{
*(.text)
}
.rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC0000000)
{
*(.rodata)
*(.symtab)
}
.data ALIGN (4K) : AT (ADDR (.data) - 0xC0000000)
{
*(.data)
}
.bss ALIGN (4K) : AT (ADDR (.bss) - 0xC0000000)
{
*(COMMON)
*(.bss)
*(.bootstrap_stack)
}
_kernel_end = .;
kernel_end = .; /* For legacy reasons */
}

View File

@ -0,0 +1,86 @@
#include "KernelHeap.h"
#include "VirtualMemoryManager.h"
extern "C" const uint32_t kernel_end;
// Size of heap metadata is 5 bytes
struct heap_block{
uint8_t Used;
uint32_t Size;
};
uint32_t heap_size;
heap_block* start ;
void* malloc(size_t size)
{
//printf("Received request for %d bytes of memory\n", size);
heap_block* current = start;
// look for a free block
while(current < start + heap_size)
{
if(current->Size >= size && current->Used == false )
{
// We found a spot
// printf("Block found!\n");
// Set the spot to in-use
current->Used = true;
// split the block
//printf("Split block.\n");
uint32_t oldSize = current->Size;
current->Size = size;
heap_block* new_block = current + sizeof(heap_block) + current->Size;
new_block->Size = oldSize - ( sizeof(heap_block) + size);
new_block->Used = false;
// return the free address
// NOTE: added an offset from the initial address to accomodate for
// meta-data.
return current + sizeof(heap_block);
}
current += current->Size + sizeof(heap_block);
}
// If we are here we need more memory so we should
// probably ask the VMM for more
// TODO: ask for more memory | Extend kernel heap
printf("ERROR: OUT OF HEAP MEMORY CONDITION IS NOT IMPLEMENTED. HEAP NEEDS TO BE EXTENDED!\n");
}
void free(void* addr)
{
// clear the free boolean that corresponds to this adddress
// This should be fairly simple
heap_block* allocatedBlock = (heap_block*)((uint32_t)addr - sizeof(heap_block));
allocatedBlock->Used = false;
}
void initHeap()
{
void* HEAP_ADDRESS = allocate_block();
printf("0x%x HEAP Paddr\n", HEAP_ADDRESS);
Immediate_Map((uint32_t)HEAP_ADDRESS + 0xC0000000, (uint32_t)HEAP_ADDRESS );
start = (heap_block*) ((uint32_t)HEAP_ADDRESS + 0xC0000000);
heap_size = 4096;
printf("Clear heap\n");
// Clear the heap
printf("set at 0x%x %d bytes to zero\n", start , heap_size);
memset((void*)start, 0x00, heap_size /4);
printf("Init first heap block\n");
// initialzie
start->Size = heap_size - sizeof(heap_block);
start->Used = false;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "../terminal/kterm.h"
void initHeap();
void* malloc (size_t size );
void free(void* addr);

View File

@ -0,0 +1,43 @@
#include "PageDirectory.h"
void PageDirectory::enable()
{
// https://wiki.osdev.org/Setting_Up_Paging
//set each entry to not present
// int i;
// for(i = 0; i < 1024; i++)
// {
// // This sets the following flags to the pages:
// // Supervisor: Only kernel-mode can access them
// // Write Enabled: It can be both read from and written to
// // Not Present: The page table is not present
// this->page_directory[i] = 0x00000002;
// }
// // holds the physical address where we want to start mapping these pages to.
// // in this case, we want to map these pages to the very beginning of memory.
// //we will fill all 1024 entries in the table, mapping 4 megabytes
// for(unsigned int i = 0; i < 1024; i++)
// {
// // As the address is page aligned, it will always leave 12 bits zeroed.
// // Those bits are used by the attributes ;)
// first_page_table[i] = (i * 0x1000) | 3; // attributes: supervisor level, read/write, present.
// }
// // attributes: supervisor level, read/write, present
// this->page_directory[0] = ((unsigned int)first_page_table) | 3;
printf("Enable Paging!\n");
loadPageDirectory(this->page_directory);
enablePaging();
}
void PageDirectory::MapPhysicalToVirtualAddress ( address_t PAddress , address_t VAddress, uint32_t size )
{
}

View File

@ -1,17 +1,18 @@
#pragma once
#include <stdint.h>
extern "C" void loadPageDirectory (uint32_t* addr );
extern "C" void enablePaging();
typedef uintptr_t address_t;
#include "./memory.h"
#include "./../terminal/kterm.h"
#define KB 1024
typedef uintptr_t address_t;
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
extern "C" void loadPageDirectory (uint32_t* addr );
extern "C" void enablePaging();
struct page_directory_entry {};
struct page_table_entry{};
@ -21,8 +22,10 @@ struct page_table_entry{};
class PageDirectory {
public:
void enable ();
void MapPhysicalToVirtualAddress ( address_t PAddress , address_t VAddress, uint32_t size );
private:
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
uint32_t page_directory[1024] __attribute__((aligned(4096))); // align on 4 kiloByte pages
uint32_t first_page_table[1024] __attribute__((aligned(4096))); // align on 4 kiloByte pages
};

View File

@ -0,0 +1,115 @@
#include "./PhysicalMemoryManager.h"
#define IS_ALIGNED(addr, align) !((addr) & ~((align) - 1))
#define ALIGN(addr, align) (((addr) & ~((align) - 1 )) + (align))
const uint32_t KERNEL_OFFSET = 0xC0000000;
uint32_t* memoryBitMap;
uint32_t pmmap_size;
uint32_t max_blocks;
int used_blocks;
void SetupPhysicalMemoryManager(uint32_t mapAddress, uint32_t memorySize )
{
/*
Every byte contains 8 pages
A page is 4096 kib
Every block (1 bit) represent an page
*/
// Set the maximum number of blocks
max_blocks = (uint32_t)memorySize / BLOCK_SIZE ;
printf("Max Blocks: %d\n", max_blocks);
// Set size of the bitmap
uint32_t bitmap_size = max_blocks / 32;
printf("Bitmap size: %d bytes\n",bitmap_size);
// Set blocks used to zero
used_blocks = max_blocks;
// set the address of the memory bitmap
memoryBitMap = (uint32_t*) mapAddress;
// Set all places in memory as free
memset(memoryBitMap, 0xFFFFFFFF, max_blocks / 32 );
}
// NOTE: This can only give blocks of 4kb at a time!
// We might at some point want to allocate multiple blocks at once.
void* allocate_block() {
uint8_t blocks_available = max_blocks - used_blocks;
// Are there any blocks available?
if( blocks_available <= 0)
{
printf("No blocks available. Blocks Delta: 0x%x\n", blocks_available);
return 0;
}
// Find 1 free block somewhere
int free_block_index = bitmap_first_unset(memoryBitMap, max_blocks / 8 );
if(free_block_index == -1)
{
printf("Could not find a good block!\n");
// Could not find a block
return (void*)0xFFFF;
}
if(free_block_index == 0)
printf("Somethings wrong!!!\n");
// Set the block to be used!
bitmap_unset(memoryBitMap, free_block_index);
// Increase the used_block count!
used_blocks++;
printf("used blocks: 0x%x\n", used_blocks);
// return the pointer to the physical address
return (void*) (BLOCK_SIZE * free_block_index);
}
void free_block(void* p) {
// If it is a null pointer we don't need to do anything.
if(p==0) {
return;
}
// calculate the index into the bitmap
int index = ((uint32_t) p) / BLOCK_SIZE;
// set the block to be free
bitmap_set(memoryBitMap, index);
used_blocks--;
printf("used blocks: 0x%x, after free\n", used_blocks);
}
void allocate_region(uint32_t startAddress, uint32_t size) {
// every bit should be 4KiB
// every byte is 8*4KiB = 32KiB
int NumberOfBlocksToAllocate = ( size / 1024) / 4 / 8 + 1;
int startBlock = (startAddress / 1024) / 4 / 8 ;
for( int i = 0; i < NumberOfBlocksToAllocate; i++)
{
bitmap_unset(memoryBitMap, startBlock + i);// allocate region causes #PF Exception
used_blocks++;
}
}
void deallocate_region(uint32_t StartAddress , uint32_t size ) {
// reverse of what happened in allocate_region
int NumberOfBlocks = (size / 1024) / 4 / 8 + 1;
int startBlock = (StartAddress / 1024) / 4 / 8;
for(int i = 0; i < NumberOfBlocks; i++)
{
bitmap_set(memoryBitMap, startBlock + i);
used_blocks --;
}
}
int GetUsedBlocks (){
return used_blocks;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <stddef.h>
#include <CoreLib/Memory.h>
#include "../prekernel/bootstructure.h"
#include "../terminal/kterm.h"
#include "../bitmap.h"
#define BLOCK_SIZE 4092
void SetupPhysicalMemoryManager(uint32_t mapAddress, uint32_t memorySize);
void* allocate_block();
void free_block(void* ptr);
void allocate_region(uint32_t address, uint32_t size);
void deallocate_region(uint32_t address, uint32_t size);
int GetUsedBlocks();

View File

@ -0,0 +1,60 @@
#pragma once
#include "gdt/gdtc.h"
#include <CoreLib/Memory.h>
struct TaskStateSegment {
uint32_t prev_tss;
uint32_t esp0;
uint32_t ss0;
// everythinge else is unused
uint32_t esp1;
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap_base;
}__attribute__((packed));
TaskStateSegment tss0 ={};
inline void flush_tss()
{
asm volatile("mov $0x2B, %ax ; ltr %ax");
}
void setup_tss(){
// ensure the tss is zero'd
memset((void*)&tss0, 0, sizeof(tss0));
tss0.ss0 = (uint32_t) &GlobalDescriptorTable[KERNEL_DATA_SEGMENT];
extern uint32_t stack_top;
tss0.esp0 = (unsigned long)&stack_top;
// Task Segment Descriptor
uint32_t address = (unsigned long) &tss0;
uint32_t size = sizeof(tss0);
uint32_t limit = (address + size );
add_descriptor(TASK_STATE_SEGMENT, address, limit- 1, 0xE9, 0x0);
}

View File

@ -0,0 +1,130 @@
#include "VirtualMemoryManager.h"
#include "../../CoreLib/Memory.h"
#define ALIGN(addr, align) (((addr) & ~((align) - 1 )) + (align))
extern uint32_t boot_page_directory[1024] ; // points to the wrong location
extern uint32_t boot_page_table[1024];
void flush_cr3(){
asm volatile("movl %cr3, %ecx;"
"movl %ecx, %cr3");
}
void AllocatePage(uint32_t vaddr)
{
//uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
printf("Allocation happening at PDE: %d PTE: %d\n", PageDirectoryEntryIndex, PageTableEntryIndex);
// check if the page directory entry is marked as present
if (boot_page_directory[PageDirectoryEntryIndex] & 0x1 )
{
printf("Directory entry is marked as present\n");
uint32_t* page_table = (uint32_t*)((boot_page_directory[PageDirectoryEntryIndex]) & 0xFFFFE000) ;
//page_table = (uint32_t*) ((uint32_t)page_table + 0xC0000000); // Add kernel offset
printf("Page table address: 0x%x\n", (uint32_t)&page_table);
// check if the page table entry is marked as present
if ( page_table[PageTableEntryIndex] & 0x1 )
{
printf("page already present!\n");
} else{
printf("Mapping a physical page.\n");
// Map the entry to a physical page
page_table[PageTableEntryIndex] = (uint32_t)allocate_block() | 0x3;
}
} else {
printf("Mapping a new page directory entry with a page table\n");
// mark the page table as present and allocate a physical block for it
boot_page_directory[PageDirectoryEntryIndex] = (uint32_t)allocate_block() | 0x3;
}
asm ("cli; invlpg (%0); sti" :: "r" (vaddr) : "memory" );
}
void FreePage(uint32_t vaddr )
{
// uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
uint32_t* pageTable = (uint32_t*)(boot_page_directory[PageDirectoryEntryIndex] & (0xFFFFE000 + 0xC0000000));
void* physicalAddressToFree = (void*)(pageTable[PageTableEntryIndex] & (0xFFFFE000 + 0xC0000000));
free_block(physicalAddressToFree);
pageTable[PageTableEntryIndex] = 0x0;
}
void Immediate_Map ( uint32_t vaddr, uint32_t paddr)
{
printf("map 0x%x to 0x%x\n", paddr, vaddr);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
printf("Map address at PDE 0x%x PTE 0x%x\n", PageDirectoryEntryIndex, PageTableEntryIndex);
printf("boot pagedirectoy address: 0x%x\n", &boot_page_directory);
printf("PDE : 0x%x\n", boot_page_directory[PageTableEntryIndex]);
if (boot_page_directory[PageDirectoryEntryIndex] & 0x1 ) {
printf("Directory entry is marked as present\n");
} else {
printf("Mapping a new page directory entry with a page table\n");
// mark the page table as present and allocate a physical block for it
void* new_page_dir = allocate_block();
memset(new_page_dir, 0 , 1024 * sizeof (uint32_t));
printf("New page directory address 0x%x\n", &new_page_dir);
boot_page_directory[PageDirectoryEntryIndex] = (uint32_t)new_page_dir | 0x3;
}
printf("PDE found at : 0x%x\n", (uint32_t) &boot_page_directory[PageDirectoryEntryIndex]);
uint32_t* page_table = (uint32_t*)(boot_page_directory[PageDirectoryEntryIndex] & 0xFFFFE000) ;
printf("Page table address: 0x%x\n", (uint32_t)page_table);
// check if the page table entry is marked as present
if ( page_table[PageTableEntryIndex] & 0x1 )
{
printf("page already present!\n");
printf("Entry found at addr: 0x%x\n", &(page_table[PageTableEntryIndex]));
} else{
printf("Mapping a physical page.\n");
// Map the entry to a physical page
page_table[PageTableEntryIndex] = (uint32_t)(paddr | 0x3);
}
asm ("invlpg (%0)" :: "r" (vaddr) : "memory" );
}
// NOT IMPLEMENTED
void Immediate_Unmap(uint32_t vaddr)
{
// NOTE: I will implement lazy unmapping for now
//uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
//int PageDirectoryEntryIndex = vaddr >> 22;
//int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "../terminal/kterm.h"
#include "../i386/processor.h"
#include "PhysicalMemoryManager.h"
void SetupVMM();
void AllocatePage(uint32_t v_addr );
void FreePage(uint32_t v_addr);
void Immediate_Map(uint32_t vaddr, uint32_t paddr);
void Immediate_Unmap (uint32_t v_addr);
// void Demand_map(uint32_t p_addr, uint32_t v_addr);
// void Demand_Unmap (uint32_t v_addr);

View File

@ -1,15 +1,11 @@
#include "gdtc.h"
#include "../tty/kterm.h"
#include "../../terminal/kterm.h"
#define NULL_SEGMENT 0
#define KERNEL_CODE_SEGMENT 1
#define KERNEL_DATA_SEGMENT 2
#define USER_CODE_SEGMENT 3
#define USER_DATA_SEGMENT 4
SegmentDescriptor GlobalDescriptorTable[5];
SegmentDescriptor GlobalDescriptorTable[6];
GlobalDescriptorTableDescriptor gdtDescriptor;
void add_descriptor(int which , unsigned long base, unsigned long limit, unsigned char access, unsigned char granularity ){
GlobalDescriptorTable[which].base_low = (base & 0xFFFF );
GlobalDescriptorTable[which].base_middle = (base >> 6) & 0xFF;
@ -21,7 +17,6 @@ void add_descriptor(int which , unsigned long base, unsigned long limit, unsigne
GlobalDescriptorTable[which].granularity |= (granularity & 0xF0);
GlobalDescriptorTable[which].access = access;
}
@ -39,23 +34,13 @@ void initGDT(){
add_descriptor(KERNEL_DATA_SEGMENT, 0, 0xFFFFFFFF, 0x92, 0xCF);
// User Code Segment
// TODO:
add_descriptor(USER_CODE_SEGMENT, 0, 0xFFFFFFFF, 0xFA, 0xCF);
// User Data Segement
// TODO:
add_descriptor(USER_DATA_SEGMENT, 0, 0xFFFFFFFF, 0xF2, 0xCF);
// init Gdt Descriptor
gdtDescriptor.limit = ((sizeof(SegmentDescriptor ) * 5 ) - 1);
gdtDescriptor.base = (unsigned int) &GlobalDescriptorTable;
LoadGlobalDescriptorTable();
while (true)
asm volatile("hlt");
gdtDescriptor.limit = ((sizeof(SegmentDescriptor ) * 6 ) - 1);
gdtDescriptor.base = (unsigned int) (&GlobalDescriptorTable);
}

View File

@ -1,6 +1,16 @@
#pragma once
#include <stdint.h>
#define NULL_SEGMENT 0
#define KERNEL_CODE_SEGMENT 1
#define KERNEL_DATA_SEGMENT 2
#define USER_CODE_SEGMENT 3
#define USER_DATA_SEGMENT 4
#define TASK_STATE_SEGMENT 5
struct SegmentDescriptor {
unsigned short limit_low;
unsigned short base_low;
@ -10,18 +20,16 @@ struct SegmentDescriptor {
unsigned char base_high;
}__attribute__((packed));
extern SegmentDescriptor GlobalDescriptorTable[6];
struct GlobalDescriptorTableDescriptor{
unsigned short limit;
unsigned int base;
}__attribute__((packed));
}__attribute__((packed)) ;
extern SegmentDescriptor GlobalDescriptorTable[];
extern GlobalDescriptorTableDescriptor gdtDescriptor;
void add_descriptor(int which , unsigned long base, unsigned long limit, unsigned char access, unsigned char granularity );
extern "C" void LoadGlobalDescriptorTable();
void initGDT();

142
kernel/memory/memory.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "./memory.h"
uint32_t* memoryBitMap;
/*
*/
void PhysicalMemory::setup( MemoryInfo* memory) {
// calculate the maximum number of blocks
max_blocks = KB_TO_BLOCKS(memory->TotalMemory);
used_blocks = 0;
memoryBitMap = (uint32_t*) 0x00a00000;
printf("Maximum Number of blocks: 0x%x, Number of bytes for memMap: 0x%x\n", max_blocks , (max_blocks/8));
//Size of memory map
uint32_t memMap_size = (max_blocks / 8 ) ;
printf("Memory Map size: 0x%x\n", memMap_size );
printf("size of int in bytes: 0x%x \n" , sizeof(int));
// Set all places in memory as free
memset(memoryBitMap, 0xFF, memMap_size );
}
// NOTE: this can only give blocks of 4kb at a time!
void* PhysicalMemory::allocate_block() {
uint8_t blocks_available = max_blocks - used_blocks;
// Are there any blocks available?
if( blocks_available <= 0)
{
printf("No blocks available. Blocks Delta: 0x%x\n", blocks_available);
return 0;
}
// Find 1 free block somewhere
int free_block_index = bitmap_first_unset(memoryBitMap, (max_blocks /8) /*memMap Size*/ );
if(free_block_index == -1)
{
printf("Could not find a good block!\n");
// Could not find a block
return (void*)0xFFFF;
}
if(free_block_index == 0)
printf("Somethings wrong!!!\n");
// Set the block to be used!
bitmap_unset(memoryBitMap, free_block_index);
// Increase the used_block count!
used_blocks++;
printf("used blocks: 0x%x\n", used_blocks);
// return the pointer to the physical address
return (void*) (BLOCK_SIZE * free_block_index);
}
void PhysicalMemory::free_block(void* p) {
// If it is a null pointer we don't need to do anything.
if(p==0) {
return;
}
// calculate the index into the bitmap
int index = ((uint32_t) p) / BLOCK_SIZE;
// set the block to be free
bitmap_set(memoryBitMap, index);
used_blocks--;
printf("used blocks: 0x%x, after free\n", used_blocks);
}
void PhysicalMemory::allocate_region(uint32_t startAddress, uint32_t size) {
// every bit should be 4KiB
// every byte is 8*4KiB = 32KiB
int NumberOfBlocksToAllocate = ( size / 1024) / 4 / 8 + 1;
int startBlock = (startAddress / 1024) / 4 / 8 ;
// printf("NumberOfBlocksToAllocate: 0x%x\n", NumberOfBlocksToAllocate);
//printf( "start block: 0x%x\n" , startBlock);
for( int i = 0; i < NumberOfBlocksToAllocate; i++)
{
//printf("ALLOCATE BLOCK: 0x%x\n" , startBlock + i );
bitmap_unset(memoryBitMap, startBlock+ i);
used_blocks++;
}
}
void PhysicalMemory::deallocate_region(uint32_t StartAddress , uint32_t size ) {
// NOT IMPLEMENTED YET
}
void mapMultibootMemoryMap( MemoryInfo* memInfo , multiboot_info_t *mbt) {
printf("mmap_addr = 0x%x, mmap_length = 0x%x\n",
(unsigned) mbt->mmap_addr, (unsigned) mbt->mmap_length);
multiboot_memory_map_t *mmap = (multiboot_memory_map_t*) mbt->mmap_addr;
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){
memInfo->TotalMemory += mmap->len;
} else {
memInfo->ReservedMemory += mmap->len;
}
print_Multiboot_memory_Map(mmap);
}
}
/**
* @brief Debug Verbose functions
*
* @param mmap
*/
void print_Multiboot_memory_Map(multiboot_memory_map_t* mmap) {
printf(
"size = 0x%x, base_addr = 0x%x%08x, length = 0x%x%08x, type = 0x%x\n",
(unsigned) mmap->size,
(unsigned) (mmap->addr >> 32),
(unsigned) (mmap->addr & 0xffffffff),
(unsigned) (mmap->len >> 32),
(unsigned) (mmap->len & 0xffffffff),
(unsigned) mmap->type
);
}

46
kernel/memory/memory.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "memoryinfo.h"
#include "../prekernel/multiboot.h"
#include "../terminal/kterm.h"
#include <CoreLib/Memory.h>
#include "../bitmap.h"
#define BLOCK_SIZE 4092
#define BLOCKS_PER_WORD 32 // A word is 16 bit in x86 machines according to my google search results!
#define KB_TO_BLOCKS(x) (x / BLOCK_SIZE)
#define IS_ALIGNED(addr, align) !((addr) & ~((align) - 1))
#define ALIGN(addr, align) (((addr) & ~((align) - 1 )) + (align))
void initialise_available_regions(uint32_t memoryMapAddr, uint32_t memoryMapLastAddr, uint32_t* memoryBitMap, int* used_blocks);
extern uint32_t* memoryBitMap;
class PhysicalMemory
{
public:
void setup(MemoryInfo* memory);
void destroy();
void free_block(void* ptr);
void* allocate_block();
void allocate_region(uint32_t, uint32_t);
void deallocate_region(uint32_t , uint32_t );
private:
size_t pmmap_size;
size_t max_blocks;
int used_blocks;
};
void mapMultibootMemoryMap( MemoryInfo* memInfo , multiboot_info_t *mbt);
/**
* @brief Debug Verbose Functions
*
* @param mmap
*/
void print_Multiboot_memory_Map(multiboot_memory_map_t* mmap);

View File

@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
struct MemoryArea{
void* StartAddress;
size_t Size;
unsigned int type;
MemoryArea* Next;
}__attribute__((packed));
struct MemoryInfo {
uint32_t TotalMemory;
uint32_t ReservedMemory;
MemoryArea* MemoryRegionList;
}__attribute__((packed));

164
kernel/pci/pci.cpp Normal file
View File

@ -0,0 +1,164 @@
#include "pci.h"
void PCI::Scan(){
int devicesFound = 0;
printf("Start finding devices, Found: %d devices");
// loop through all possible busses, devices and their functions;
for( int bus = 0 ; bus < 256 ; bus++)
{
for(int device = 0; device < 32 ; device ++)
{
int function = 0;
uint64_t DeviceIdentify = PCI::ConfigReadWord(bus, device, function,0x0);
uint32_t DeviceID = GetDevice(bus, device, function) >> 16;
if( DeviceID != 0xFFFF){
PCIBusAddress busAddress =
PCIBusAddress{bus, device, function };
PrintPCIDevice(busAddress);
// iterate over the functions if it is a multi function device!
if( PCI::IsMultiFunctionDevice(busAddress) ){
printf("Multi function device! \n");
printf("Check remaining Functions\n");
for ( function = 1 ; function < 8; function++)
{
uint32_t DeviceID = GetDevice(bus, device, function) >> 16;
if( DeviceID != 0xFFFF){
PCIBusAddress busAddress2 = PCIBusAddress{bus, device, function};
PrintPCIDevice(busAddress2);
devicesFound++;
}
}
}
devicesFound++;
}
}
}
printf("Found %d PCI devices!\n", devicesFound);
}
const char* PCI::getClassName (uint8_t ClassCode){
bool isKnown = (ClassCode < PCI::KnownClassCodes);
return isKnown ? PCI::ClassCodeNames[ClassCode].name : "Unknown ClassCode";
}
const char* PCI::getVendor( uint32_t VendorID){
switch (VendorID)
{
case 0x8086:
return "Intel Corporation";
break;
case 0x10DE:
return "NVIDIA Corporation";
break;
case 0x1022:
return "Advanced Micro Devices, Inc.[AMD]";
break;
case 0x1002:
return "Advanced Micor Devices, Inc.[AMD/ATI]";
break;
case 0xbeef:
return "VirtualBox Graphics Adapter";
break;
case 0xcafe:
return "VirtualBox Guest Service";
break;
default:
return "Vendor Unkown";
break;
}
}
uint64_t PCI::GetDevice (int bus, int device, int function ){
return PCI::ConfigReadWord(bus, device, function,0x0);
}
bool PCI::IsMultiFunctionDevice(PCIBusAddress& PCIDeviceAddress)
{
uint32_t header_information = ConfigReadWord(PCIDeviceAddress, 0xC);
return (((header_information>>16)
& 0x80)
>> 7 );
}
uint16_t PCI::GetClassCodes( PCIBusAddress& PCIDeviceAddress ){
return (uint16_t)(ConfigReadWord(PCIDeviceAddress, 0x8) >> 16);
}
uint8_t PCI::GetHeaderType( PCIBusAddress& PCIDeviceAddress ){
uint32_t header_information = ConfigReadWord(PCIDeviceAddress , 0xC);
return (uint8_t) (
((header_information >> 16) //Get higher half
& 0x00FF) // Select the last two bytes
& 0x7F ); // Mask bit 7 as it indicates if the device is a mulit function device!
}
uint32_t PCI::ConfigReadWord (uint8_t bus, uint8_t device, uint8_t func, uint8_t offset){
uint32_t address;
address = (uint32_t) (
((uint32_t) 1 << PCI_ENABLE_ADDR_SHIFT) |
((uint32_t)bus << PCI_BUS_ADDR_SHIFT) |
((uint32_t)device << PCI_DEVICE_ADDR_SHIFT) |
((uint32_t)func << PCI_FUNCTION_ADDR_SHIFT) |
offset );
outl(CONFIG_ADDRESS, address);
return inl(CONFIG_DATA);
}
uint8_t PCI::GetProgIF (PCIBusAddress& PCIDeviceAddress){
uint32_t data = ConfigReadWord(PCIDeviceAddress, 0x8);
return ((data >> 8) & 0xFF);
}
uint32_t PCI::ConfigReadWord ( PCIBusAddress& PCIDeviceAddress , uint8_t offset){
outl(CONFIG_ADDRESS , PCIDeviceAddress.getAddress() | offset );
return inl(CONFIG_DATA);
}
uint32_t PCI::ReadBAR ( PCIBusAddress& PCIDeviceAddress, int bar_number){
int offsetToBar = 0x10 + (bar_number* 0x4);
return ConfigReadWord(PCIDeviceAddress, offsetToBar);
}
void PCI::PrintPCIDevice (PCIBusAddress& PCIDeviceAddress)
{
uint32_t DeviceID = (PCI::GetDevice(PCIDeviceAddress.bus, PCIDeviceAddress.device, PCIDeviceAddress.function) >> 16);
uint32_t VendorID = PCI::GetDevice(PCIDeviceAddress.bus, PCIDeviceAddress.device, PCIDeviceAddress.function) & 0xFFFF;
printf("Device found!\n");
printf("Bus: %d, Device: %d, function: %d \n", PCIDeviceAddress.bus, PCIDeviceAddress.device, PCIDeviceAddress.function);
printf("DeviceID: 0x%x, Vendor: %s\n",
DeviceID
, PCI::getVendor(VendorID) );
uint8_t header_type = PCI::GetHeaderType(PCIDeviceAddress);
printf( "Header type: 0x%x\n", header_type);
uint16_t deviceClasses = PCI::GetClassCodes(PCIDeviceAddress);
printf("class: %s, subClass: %d\n\n", PCI::getClassName((deviceClasses >> 8)), deviceClasses & 0xFF);
}

61
kernel/pci/pci.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <stdint.h>
#include "../io/io.h"
#include "../terminal/kterm.h"
#include "pciDevice.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
#define PCI_BUS_ADDR_SHIFT 16
#define PCI_DEVICE_ADDR_SHIFT 11
#define PCI_FUNCTION_ADDR_SHIFT 8
#define PCI_ENABLE_ADDR_SHIFT 31
class PCI {
public:
static void Scan();
static uint32_t ConfigReadWord ( PCIBusAddress& PCIDeviceAddress , uint8_t offset);
static uint8_t GetProgIF (PCIBusAddress& PCIDeviceAddress);
static uint32_t ReadBAR ( PCIBusAddress& PCIDeviceAddress, int bar_number);
static uint32_t ConfigReadWord (uint8_t bus, uint8_t device, uint8_t func, uint8_t offset);
static uint8_t GetHeaderType( PCIBusAddress& PCIDeviceAddress );
static uint16_t GetClassCodes( PCIBusAddress& PCIDeviceAddress );
static bool IsMultiFunctionDevice(PCIBusAddress& PCIDeviceAddress);
static uint64_t GetDevice (int bus, int device, int function );
static const char* getClassName (uint8_t ClassCode);
static const char* getVendor( uint32_t VendorID);
static void PrintPCIDevice(PCIBusAddress& PCIDevice);
private:
struct ClassCode {
const char* name;
uint8_t code;
};
static constexpr ClassCode ClassCodeNames []= {
{"Unclassified", 0x0},
{"MassStorage Controller", 0x1},
{"Network Controller", 0x2},
{"Display Controller", 0x3},
{"Multimedia Controller", 0x4},
{"Memory Controller", 0x5},
{"Bridge", 0x6},
{"Simple Communication Controller", 0x7},
{"Base System Peripheral", 0x8},
{"Input Device Controller", 0x9},
{"Docking Station", 0xA},
{"Processor", 0xB},
{"Serial Bus Controller", 0xC},
{ "Wireless Controller", 0xD},
{"Intelligent Controller", 0xE},
{"Satellite Communication Controller", 0xF},
{"Encryption Controller", 0x10},
{"Signal Processing Controller", 0x11},
{ "Processing Accelerator", 0x12},
{ "Non-Essential Instrumentation", 0x13}
};
static const uint8_t KnownClassCodes = sizeof(ClassCodeNames) / sizeof(ClassCode);
};

7
kernel/pci/pciDevice.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "pciDevice.h"
// NOTE: we would really like to return a pointer
// to the newly created PCIBusAddress struct;
PCIBusAddress const PCIDevice::PCIAddress(){
return PCIBusAddress{bus ,device, function};
}

54
kernel/pci/pciDevice.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
/*
* PCI devices API
*/
struct PCIBusAddress{
int bus ;
int device ;
int function;
uint32_t getAddress( ){
return ((uint32_t) 1 << 31) |
((uint32_t) bus << 16) |
((uint32_t) device << 11)|
((uint32_t) function << 8) |
0x0000;
};
};
class PCIDevice {
public :
PCIDevice (PCIBusAddress* , int );
~PCIDevice();
PCIBusAddress const PCIAddress();
inline const char* getDeviceString(){
return "Not implemented"; //GetClassCodeName(deviceclass);
}
inline const char* getVendorString(){
return "Not implemented"; // getVendor(VendorID);
}
inline void setVendorID (uint16_t id) {
this->VendorID = id;
}
private:
int bus;
int device;
int function;
uint16_t VendorID;
uint16_t DeviceID;
uint8_t deviceclass;
uint8_t devicesubclass;
int headerType;
};

View File

@ -0,0 +1,30 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
extern "C" const uint32_t kernel_begin;
extern "C" const uint32_t kernel_end;
#define IS_AVAILABLE_MEM(MEM_TYPE) MEM_TYPE & 0x1
#define IS_ACPI_MEM(MEM_TYPE) MEM_TYPE & 0x2
#define IS_RESERVED_MEM(MEM_TYPE) MEM_TYPE & 0x4
#define IS_NVS_MEMORY(MEM_TYPE) MEM_TYPE & 0x8
#define IS_BADRAM_MEMORY(MEM_TYPE) MEM_TYPE & 0x10
struct BootInfoBlock {
bool MapIsInvalid;
uint32_t bootDeviceID ;
uint32_t GrubModuleCount;
bool ValidSymbolTable;
uint32_t SymbolTableAddr;
uint32_t SymbolTabSize;
uint32_t SymbolStrSize;
bool ValidELFHeader;
bool EnabledVBE;
};

View File

@ -0,0 +1,136 @@
#include <stdint.h>
#include <stddef.h>
#include "multiboot.h"
#include "../memory/PhysicalMemoryManager.h"
#include "../memory/VirtualMemoryManager.h"
#include "../acpi/acpi.h"
#define CHECK_FLAG(flags, bit) ((flags) & (1 <<(bit)))
#define VADDR_TO_PADDR(vaddr) (vaddr - 0xC0000000)
#define PADDR_TO_VADDR(paddr) (paddr + 0xC0000000)
BootInfoBlock* BIB;
extern "C" void prekernelSetup ( unsigned long magic, multiboot_info_t* mbi)
{
/*
* Check Multiboot magic number
*/
if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
{
// PANIC!!
return;
}
mbi = PADDR_TO_VADDR(mbi);
/*
If we got a memory map from our bootloader we
should be parsing it to find out the memory regions available.
*/
if (CHECK_FLAG(mbi->flags, 6))
{
// Calculate total memory size
uint32_t RAM_size = 0;
for(
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mbi->mmap_addr;
(unsigned long)mmap < mbi->mmap_addr + mbi->mmap_length;
mmap += mmap->size +sizeof(mmap->size)
){
RAM_size += mmap->len;
}
// Call SetupPhysicalMemoryManager at its physical address
SetupPhysicalMemoryManager ( (uint32_t)VADDR_TO_PADDR(&kernel_end), RAM_size);
for(
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mbi->mmap_addr;
(unsigned long)mmap < mbi->mmap_addr + mbi->mmap_length;
mmap += mmap->size +sizeof(mmap->size)
){
if(mmap->type == MULTIBOOT_MEMORY_AVAILABLE)
deallocate_region(mmap->addr, mmap->len);
if(mmap->type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE)
allocate_region(mmap->addr, mmap->len);
// memory map
Immediate_Map(mmap->addr , mmap->addr);
if(mmap->type == MULTIBOOT_MEMORY_RESERVED)
allocate_region(mmap->addr, mmap->len);
if(mmap->type == MULTIBOOT_MEMORY_NVS)
allocate_region(mmap->addr, mmap->len);
if(mmap->type == MULTIBOOT_MEMORY_BADRAM)
allocate_region(mmap->addr, mmap->len);
}
// Allocate the kernel
allocate_region( (uint32_t)&kernel_begin, ( (uint32_t)&kernel_end - (uint32_t)&kernel_begin)- 0xC0000000 );
// Allocate the memory region below 1MB
allocate_region(0x0000000, 0x00100000);
}
else
{
// We didn't get a memory map from our bootloader.
// PANIC!!!!
return;
}
// allocate a full block for the other boot info!
BIB = (BootInfoBlock*) allocate_block();
/* is boot device valid ? */
if (CHECK_FLAG (mbi->flags, 1))
{
BIB->bootDeviceID = mbi->boot_device;
} else{
BIB->bootDeviceID = 0x11111111;
}
/* Are mods_* valid? */
if(CHECK_FLAG ( mbi->flags, 3)){
multiboot_module_t *mod;
uint32_t i;
BIB->GrubModuleCount = mbi->mods_count;
for(i = 0, mod = (multiboot_module_t *) mbi->mods_addr; i < mbi->mods_count; i++ , mod++){
}
}
/* Is the symbol table of a.out valid? */
if (CHECK_FLAG(mbi->flags, 4))
{
// NOTE: Do something with it.. (Store it , process it etc...)
// printf("- Valid Symbol Table available at 0x%x.\n Tab Size: %d, str Size: %d\n", BootInfo->SymbolTableAddr, BootInfo->SymbolTabSize, BootInfo->SymbolStrSize);
BIB->ValidSymbolTable = true;
multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym);
} else{
BIB->ValidSymbolTable = false;
}
/* Is the section header table of ELF valid? */
if (CHECK_FLAG(mbi->flags, 5))
{
// NOTE: Do something with it.. (Store it , process it etc...)
BIB->ValidELFHeader = true;
multiboot_elf_section_header_table_t *multiboot_elf_sec = &(mbi->u.elf_sec);
}else{
BIB->ValidELFHeader = false;
}
/* Draw diagonal blue line */
if (CHECK_FLAG (mbi->flags, 12)){
BIB->EnabledVBE = true;
// NOTE: Do something with it.. (Store it , process it etc...)
} else{
BIB->EnabledVBE = false;
}
}

View File

@ -1,9 +1,14 @@
#pragma once
#include "tty/kterm.h"
#include "io.h"
#include "terminal/kterm.h"
#include "io/io.h"
#define PORT 0x3f8
static int init_serial() {
#ifdef __VERBOSE__
printf("Init Serial\n");
#endif
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
@ -25,46 +30,29 @@ static int init_serial() {
return 0;
}
int is_transmit_empty() {
inline int is_transmit_empty() {
return inb(PORT + 5) & 0x20;
}
void write_serial(char a) {
inline void write_serial(char a) {
while (is_transmit_empty() == 0);
outb(PORT,a);
}
int serial_received() {
inline int serial_received() {
return inb(PORT + 5) & 1;
}
char read_serial() {
inline char read_serial() {
while (serial_received() == 0);
return inb(PORT);
}
void print_serial(const char* string ){
inline void print_serial(const char* string ){
for(size_t i = 0; i < strlen(string); i ++){
write_serial(string[i]);
}
}
void test_serial(){
/** Serial test **/
kterm_writestring("Writing to COM1 serial port:");
init_serial();
write_serial('A');
write_serial('B');
write_serial('C');
write_serial('D');
write_serial('E');
char Character_received = read_serial();
kterm_writestring("\n");
kterm_writestring("received from COM 1: \n");
kterm_put(Character_received);
kterm_writestring("\n");
}

View File

@ -0,0 +1,199 @@
#include "ATAPIO.h"
#include "../../io/io.h"
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
void ATAPIO::Read(uint16_t DEVICE_CHANNEL, DEVICE_DRIVE drive, uint32_t LBA, uint16_t* buffer) {
/*
Assume you have a sectorcount byte and a 28 bit LBA value. A sectorcount of 0 means 256 sectors = 128K.
Notes: - When you send a command byte and the RDY bit of the Status Registers is clear, you may have to wait (technically up to 30 seconds) for the drive to spin up, before DRQ sets. You may also need to ignore ERR and DF the first four times that you read the Status, if you are polling.
- for polling PIO drivers: After transferring the last uint16_t of a PIO data block to the data IO port, give the drive a 400ns delay to reset its DRQ bit (and possibly set BSY again, while emptying/filling its buffer to/from the drive).
- on the "magic bits" sent to port 0x1f6: Bit 6 (value = 0x40) is the LBA bit. This must be set for either LBA28 or LBA48 transfers. It must be clear for CHS transfers. Bits 7 and 5 are obsolete for current ATA drives, but must be set for backwards compatibility with very old (ATA1) drives.
An example of a 28 bit LBA PIO mode read on the Primary bus:
*/
const int sectorCount = 1;
// Floating bus check
uint8_t floatingBus = inb(DEVICE_CHANNEL | 7);
if (floatingBus == 0xFF){
printf("Floating bus!!");
return ;
}
//printf("Read LBA: 0x%x\n", LBA);
// Send 0xE0 for the "master" or 0xF0 for the "slave", ORed with the highest 4 bits of the LBA to port 0x1F6: outb(0x1F6, 0xE0 | (slavebit << 4) | ((LBA >> 24) & 0x0F))
outb(DEVICE_CHANNEL | 6 , ( 0xE0 | (LBA >>28) ) );
// Send a NULL byte to port 0x1F1, if you like (it is ignored and wastes lots of CPU time): outb(0x1F1, 0x00)
outb(DEVICE_CHANNEL | 1, 0x0000 );
//Send the sectorcount to port 0x1F2: outb(0x1F2, (unsigned char) count)
outb(DEVICE_CHANNEL | 2, sectorCount);
//Send the low 8 bits of the LBA to port 0x1F3: outb(0x1F3, (unsigned char) LBA))
outb(DEVICE_CHANNEL | 3, LBA);
//Send the next 8 bits of the LBA to port 0x1F4: outb(0x1F4, (unsigned char)(LBA >> 8))
outb(DEVICE_CHANNEL | 4, (LBA >> 8));
//Send the next 8 bits of the LBA to port 0x1F5: outb(0x1F5, (unsigned char)(LBA >> 16))
outb(DEVICE_CHANNEL | 5, (LBA >> 16));
//Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20)
outb(DEVICE_CHANNEL | 7, 0x20);
volatile int i,j;
for(i=0;i<2000;i++)
for(j=0;j<25000;j++)
asm("NOP");
//Wait for an IRQ or poll.
uint8_t status = inb(DEVICE_CHANNEL | 7);
if( status == 0x00){
printf("No drive\n");
return;
}
//printf("Status: %x\n", status);
// Check if busy!
while((status & 0x80) == 0x80){
printf("Reading....\r");
status = inb(DEVICE_CHANNEL | 7);
}
if ((status & 0x01) == 0x01){
printf("Error occured during read!\n");
return;
}
//Transfer 256 16-bit values, a uint16_t at a time, into your buffer from I/O port 0x1F0.
if( status & 0x01){
printf("Error!\n");
printf("Status: 0x%x\n", status);
uint16_t error_register = inb(DEVICE_CHANNEL | 1);
printf("Error register 0x%x\n",error_register );
return ;
}
for ( int i = 0; i < 256; i++){
uint16_t data;
asm volatile ("inw %1, %0" : "=a"(data): "Nd"(DEVICE_CHANNEL));
// printf (" %x ", data);
buffer[i] = data;
}
//Then loop back to waiting for the next IRQ (or poll again -- see next note) for each successive sector.
}
void ATAPIO::Write(uint16_t data, DEVICE_DRIVE dev){
printf("Not implemented\n");
}
bool ATAPIO::Identify(ATAPIO_PORT DEVICE_CHANNEL, DEVICE_DRIVE drive ){
// lets ignore which port we actually want to check for now !
/*
THE STEPS INVOLVED
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
drive select IO port
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
3. Send the identify command (0xEC) to the command IO port
4. Read the status port
4.2 If the value is 0x0 the drive does not exist
4.3 If it has any other value continue
5. poll the status port until bit 7 is clear.
6. Check if the LBAmid and LBAhi ports are non-zero
6.2. If non-zero stop polling this is not an ATA device
6.3 If zero continue
7. poll status port until bit 3 is set or bit 0 is set
8. if err is clear, read the data from the data port
*/
//printf("channel selected: 0x%x", DEVICE_CHANNEL);
// Assuming Master here
// Select the target drive
outb(DEVICE_CHANNEL | 6, drive); // on the primary bus select the master drive
outb(DEVICE_CHANNEL | 6 , 0x0); // write 0 to the controlport for some reason
outb(DEVICE_CHANNEL | 6, drive);
uint8_t status = inb(DEVICE_CHANNEL | 7 );
if(status == 0x00){
printf("No drive\n");
return false;
}
// send the identify command;
outb(DEVICE_CHANNEL | 7, 0xEC);
// set the sectorCount, LBAlo, LBAmid, LBA,hi IO ports to 0
outb(DEVICE_CHANNEL | 2, 0);
outb(DEVICE_CHANNEL | 3, 0);
outb(DEVICE_CHANNEL | 4, 0);
outb(DEVICE_CHANNEL | 5, 0);
// send the identify command ;
//printf("command sent!\n");
outb(DEVICE_CHANNEL | 7 , 0xEC);
// read the status port
uint8_t status2 = inb(DEVICE_CHANNEL | 7);
if( status2 == 0x00){
printf("No drive\n");
return false;
}
//printf("Waiting until ready...\n");
while(((status2 & 0x80 == 0x80)
&& (status2 & 0x01) != 0x01)
) status2 = inb(DEVICE_CHANNEL | 7);
if( status2 & 0x01){
printf("Error!\n");
return false;
}
uint16_t deviceIdentify [256] = {0};
for ( int i = 0; i < 256; i++){
uint16_t data;
asm volatile ("inw %1, %0" : "=a"(data): "Nd"(DEVICE_CHANNEL));
deviceIdentify[i] = data;
}
printf("Model-label (ASCII hex): ");
for(int i = 27; i < 47; i++){
kterm_put((char)(deviceIdentify[i] >> 8));
kterm_put((char)(deviceIdentify[i] & 0x00FF));
}
kterm_put('\n');
return true;
}
void ATAPIO::Soft_Reset(ATAPIO_PORT DEVICE_CHANNEL, DEVICE_DRIVE drive){
printf("Soft reseting drive...\n");
outb(DEVICE_CHANNEL + 7 , 0x4);
// wait a bit..
for(int i = 0 ; i < 1000000; i++){
asm volatile("NOP");
}
outb(DEVICE_CHANNEL + 7 , 0x0);
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <stdint-gcc.h>
#include "../ide/ideCommands.h"
#include "../ide/sampleIDE.definitions.h"
#include "../../devices/BlockDevice.h"
#include "../../terminal/kterm.h"
/*
* This first driver wil make use of IO ports.
* Doing so means reading or writing from disk is going
* to be very cpu intensive.
*/
enum DEVICE_DRIVE{
MASTER = 0xA0,
SLAVE = 0xB0
};
enum ATAPIO_PORT {
Primary = 0x1f0,
Secondary = 0x170
};
class ATAPIO
{
public:
static bool Identify(ATAPIO_PORT, DEVICE_DRIVE);
static void Read (uint16_t, DEVICE_DRIVE, uint32_t, uint16_t*);
static void Write(uint16_t, DEVICE_DRIVE);
static void Soft_Reset(ATAPIO_PORT , DEVICE_DRIVE );
};

View File

@ -0,0 +1,145 @@
#include "atapiDevice.h"
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
bool isPacketDevice(){
uint8_t LBAmid = inb(0x174);
uint8_t LBAhi = inb(0x175);
printf(" LBAmid: 0x%x, LBAhi: 0x%x");
return LBAmid == 0x14 && LBAhi == 0xEB;
}
void ATAPI_DEVICE::Identify(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive ){
// lets ignore which port we actually want to check for now !
/* THE STEPS INVOLVED
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
drive select IO port
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
3. Send the identify command (0xEC) to the command IO port
4. Read the status port
4.2 If the value is 0x0 the drive does not exist
4.3 If it has any other value continue
5. poll the status port until bit 7 is clear.
6. Check if the LBAmid and LBAhi ports are non-zero
6.2. If non-zero stop polling this is not an ATA device
6.3 If zero continue
7. poll status port until bit 3 is set or bit 0 is set
8. if err is clear, read the data from the data port
*/
// Select the target drive
outb(0x176, 0xA0); // on the secondary bus select the master drive
outb(0x170 + 0x206 , 0x0); // write 0 to the controlport for some reason
outb(0x176, 0xA0);
// read the status port
uint8_t status = inb(0x177);
printf("status after drive select: 0x%x\n",status);
if( status == 0x00){
printf("No drive\n");
return;
}
outb(0x176, 0xA0);
// Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
outb(0x172, 0);
outb(0x173, 0);
outb(0x174, 0);
outb(0x175, 0);
// send the identify command;
printf("command sent!\n");
outb(0x177, 0xA1);
// read the status port
uint8_t status2 = inb(0x177);
if( status2 == 0x00){
printf("No drive\n");
return;
}
printf("Waiting until ready...\n");
while(((status2 & 0x80 == 0x80)
&& (status2 & 0x01) != 0x01)
) status2 = inb(0x177);
if(status2 & 0x01){
printf("Error!");
return;
}
// READ DATA
uint16_t deviceIdentify [256] ={0};
for (int i= 0; i < 256; i++){
uint16_t data;
asm volatile ( "in %1, %0"
: "=a"(data)
: "Nd"(0x170) );
deviceIdentify[i] = data ;
}
printf("Model-label (ASCII hex):\n");
for(int i = 27; i < 47; i++){
printf(" %x ",deviceIdentify[i]);
}
printf("\nSerial number (ASCII hex):\n");
for (int i = 10; i < 19; i++){
printf(" %x ", deviceIdentify[i]);
}
printf("\nFirmware revision (ASCII hex):\n");
for (int i = 23; i < 26; i++){
printf(" %x ", deviceIdentify[i]);
}
printf("\nConfiguration: %x\n", deviceIdentify[0]);
printf("\nData received!\n");
}
void ATAPI_DEVICE::Read(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}
void ATAPI_DEVICE::Write(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
#include "../../io/io.h"
#include "../ide/ideCommands.h"
#include "../ide/sampleIDE.definitions.h"
#include "../../terminal/kterm.h"
/*
* This first driver wil make use of IO ports.
* Doing so means reading or writing from disk is going
* to be very cpu intensive.
*
*/
enum DEVICE_DRIVE{
MASTER = 0xA0,
SLAVE = 0xB0
};
namespace ATAPI_DEVICE
{
bool isPacketDevice();
void Identify ( uint8_t, DEVICE_DRIVE );
void Read ( uint8_t, DEVICE_DRIVE );
void Write ( uint8_t, DEVICE_DRIVE );
};

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
struct SuperBlock {
uint32_t NumberOfInodes;
uint32_t NumberOfBlocks;
uint32_t NumberOfReservedBlocks;
uint32_t NumberOfUnallocatedBlocks;
uint32_t NumberOfUnallocatedInodes;
uint32_t BlockNumberOfSuperBlock;
uint32_t BlockSize;// Something about a shift left
uint32_t FragmentSize;
uint32_t NumberOfBlocksInGroup;
uint32_t NumberOfFragmentsInBlockGroup;
uint32_t NumberOfInodesInBlockGroup;
uint32_t LastMountTime; // POSIX
uint32_t LastWrittenTime; // POSIX
uint16_t TimesMountedSinceCheck;
uint16_t TimesMountedUntilCheck;
uint16_t EXT_SIG ; // 0xef53
uint16_t FS_STATE;
uint16_t ON_ERR;
uint16_t VERSION_MINOR;
uint32_t TimeLastCheck; // POSIX
uint32_t CheckInterval; //POSIX
uint32_t OS_ID; // OS the FS was created with
uint32_t VERSION_MAJOR;
uint16_t UIDReservedBlocks;
uint16_t GIDReservedBlocks;
}__attribute__((packed));

View File

@ -0,0 +1,404 @@
//
// Created by nigel on 21/02/23.
//
#include "FAT.h"
#include "../../ata pio/ATAPIO.h"
#include "../../../memory/KernelHeap.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
#include "../../../../CoreLib/ctype.h"
#include "../../../../CoreLib/Memory.h"
#include <CoreLib/Memory.h>
#include <CoreLib/ctype.h>
// exposed driver API
FS_SUPER* FAT::Mount(filesystem *fs, const char* name , vfsmount *mnt)
{
if( strncmp (fs->name, "fat", 3 ) != 0 )
{
printf("Can't mount filesystem with none fat type!\n");
return nullptr;
}
auto* bpb = GetBiosParameterBlock();
auto fat_type = DetermineFATType(bpb);
if(fat_type != FAT_TYPE::FAT16)
return nullptr;
FS_SUPER* sb = (FS_SUPER*) malloc(sizeof(FS_SUPER));
DirectoryNode* root = (DirectoryNode*) malloc(sizeof (DirectoryNode));
inode* node = (inode*) malloc(sizeof(inode));
root->children = nullptr;
node->internal = (void*)FAT::GetSectorOfRootDirectory(bpb); //sector number;
node->lookup = FAT::Lookup;
root->name = (char*) name;
root->node = node;
root->parent = nullptr;
root->compare = FAT::Compare;
mnt->mnt_count =1;
mnt->mnt_devname = "QEMU HDD";
mnt->mnt_flags = 0;
mnt->mnt_parent = nullptr;
mnt->root = root;
mnt->sb = sb;
sb->type = fs;
sb->root = root;
sb->fs_info = bpb;
return sb;
}
FILE FAT::Open(char* filename){
return (FILE){nullptr, 0, nullptr, nullptr, 1} ;
}
int FAT::Read(FILE* file, void* buffer , unsigned int length)
{
if(file == nullptr)
{
printf("NO FILE!!\n");
return -1;
}
inode* node = file->root;
if(node== nullptr)
{
printf("No INODE!\n");
return -1;
}
int cluster = (int)node->internal;
auto* bpb = FAT::GetBiosParameterBlock();
unsigned int FAT_entry = FAT::GetFATEntry(bpb, cluster);
unsigned int root_dir_sector = FAT::RootDirSize(bpb);
unsigned int fat_size = bpb->FATSz16;
unsigned int first_data_sector = bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sector;
unsigned int file_data_sector = ((cluster - 2) * bpb->SecPerClus) + first_data_sector;
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, file_data_sector, (uint16_t*)buffer);
return 0;
}
int FAT::Write(FILE* file, const void* buffer, unsigned int length)
{
return 0;
}
int FAT::Compare (DirectoryNode*, char* filename, char* filename2)
{
//TODO Implement proper compare method for 8.3 filenames
// printf("COMPARE: %s with %s\n", filename, filename2);
return memcmp(filename, filename2, 11);
}
int FAT::Create(inode* dir_node, inode** target, const char* component_name){}
DirectoryNode* FAT::Lookup (inode* currentDir , DirectoryNode* dir)
{
uint16_t data[256];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, (int)currentDir->internal , data);
List* lastAdded = nullptr;
auto* directory = (DIR*)data;
for(int i = 0; i < sizeof(data) / sizeof (DIR); i++)
{
DIR* entry = (DIR*)((uint32_t)directory + (i * sizeof(DIR)));
if(
entry->Name[0] == FAT::FREE_DIR ||
entry->ATTR & FAT::ATTRIBUTES::ATTR_VOLUME_ID ||
entry->ATTR & FAT::ATTRIBUTES::ATTR_SYSTEM ||
entry->ATTR & FAT::ATTRIBUTES::ATTR_HIDDEN
){
continue;
}
if( entry->ATTR & FAT::ATTRIBUTES::ATTR_DIRECTORY){
printf("entry in directory\n");
for(int i = 0; i < 11 ;i ++)
kterm_put(entry->Name[i]);
kterm_put('\n');
}
if( entry->Name[0] == FAT::FREE_DIR_2 )
break;
auto* dirNode = (DirectoryNode*) malloc(sizeof (DirectoryNode));
char* name = (char*)malloc(sizeof(char[11]));
memcpy(name, entry->Name, 11 );
dirNode->name = name;
dirNode->compare = dir->compare;
dirNode->parent = dir;
dirNode->node= (inode*) malloc(sizeof (inode));
dirNode->node->internal = (void*)entry->FstClusLo;
dirNode->node->read = currentDir->read;
dirNode->node->lookup = currentDir->lookup;
dirNode->node->sb = currentDir->sb;
dirNode->node->size = entry->FileSize;
List* dirlist = (List*) malloc(sizeof (List));
dirlist->data = dirNode;
dirlist->next = nullptr;
lastAdded = dirlist;
auto* temp = dir->children;
dir->children = lastAdded;
lastAdded->next = temp;
}
return (DirectoryNode*)dir;
}
// internal functions
FAT_TYPE FAT::DetermineFATType(BiosParameterBlock* bpb){
int RootDirSector = ((bpb->RootEntCnt * 32) + (bpb->BytsPerSec -1)) / bpb->BytsPerSec;
int FATSz = 0;
if(bpb->FATSz16 != 0){
FATSz = bpb->FATSz16;
} else{
// FATSz = bpb->FATSz32;
}
int TotSec = 0;
if(bpb->TotSec16 != 0){
TotSec= bpb->TotSec16;
}else{
TotSec = bpb->TotSec32;
}
int DataSec = TotSec - (bpb->RsvdSecCnt + (bpb->NumFATs * FATSz) + RootDirSector);
int CountofClusters = DataSec / bpb->SecPerClus;
if(CountofClusters < 4085){
return FAT_TYPE::FAT12;
} else if (CountofClusters < 65525) {
return FAT_TYPE::FAT16;
} else{
return FAT_TYPE::FAT32;
}
};
BiosParameterBlock* FAT::GetBiosParameterBlock(bool DEBUG ){
BiosParameterBlock* bpb = (BiosParameterBlock*) malloc(sizeof(BiosParameterBlock));
uint16_t StartAddress = 0x00 ;
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, StartAddress, (uint16_t*) bpb);
if(DEBUG)
{
printf("OEM ID: %s\n", bpb->OEMName);
printf("Bytes per sector: %d\n", bpb->BytsPerSec);
printf("Sectors per cluster: %d\n", bpb->SecPerClus);
printf("Reserved sectors: %d\n", bpb->RsvdSecCnt);
printf("Number of FAT: %d\n", bpb->NumFATs);
printf("Number of Dir entries: %d\n", bpb->RootEntCnt);
printf("Total Sectors in volume: %d\n", bpb->TotSec16 == 0 ? bpb->TotSec32 : bpb->TotSec16);
printf("Sectors per FAT: %d\n", bpb->FATSz16 );
}
return bpb;
}
uint16_t FAT::GetFATEntry (BiosParameterBlock* bpb, unsigned int cluster){
int FATSz = bpb->FATSz16;
int FATOffset = 0;
FAT_TYPE type = FAT::DetermineFATType(bpb);
if( type == FAT_TYPE::FAT16){
FATOffset = cluster *2;
} else if( type == FAT_TYPE::FAT32){
FATOffset = cluster * 4;
}
int thisFATSecNum = bpb->RsvdSecCnt + (FATOffset / bpb->BytsPerSec); // Sector number containing the entry for the cluster
// For any other FAT other than the default
// SectorNumber = (FATNumber * FATSz) + ThisFATSecNum
uint16_t buff[bpb->BytsPerSec];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, thisFATSecNum, buff );
int thisFATEntOffset = FATOffset % bpb->BytsPerSec; // offset for the entry in the sector containing the entry for the cluster
uint16_t ClusterEntryValue = 0;
// Get the FATEntry
if(type == FAT_TYPE::FAT16){
return *((uint16_t*) &buff[thisFATEntOffset]);
}
else{
// FAT32 logic
return 0;
}
}
uint16_t FAT::DetermineFreeSpace()
{
// Loop through all FAT entries in all FAT's
// to construct a list of free/available clusters
// Free clusters are recorded with all 0's except on FAT32 where
// the highest order 4 bits should be ignored.
/*
* The number of sectors reserved for each FAT (count of sectors in the BPB_FATSz16 or
BPB_FATSz32 fields) may be bigger than the actual number of sectors required for
containing the entire FAT. Therefore, there may be totally unused FAT sectors at the end of
each FAT in the FAT region of the volume. Each implementation must determine the value
for the last valid sector in the FAT using CountOfClusters (the last valid sector in the FAT
is the one containing the FAT entry numbered CountOfClusters + 1).
All sectors reserved for the FAT beyond the last valid sector (defined as the one containing
the FAT entry for the last cluster) must be set to 0x0 during volume initialization/format.
*/
}
int FAT::GetSectorOfRootDirectory (BiosParameterBlock* bpb)
{
return (bpb->RsvdSecCnt + (bpb->NumFATs * bpb->FATSz16));
}
unsigned int FAT::RootDirSize(BiosParameterBlock* bpb)
{
return ((bpb->RootEntCnt * 32) + (bpb->BytsPerSec -1)) /bpb->BytsPerSec;
}
void FAT::OpenSubdir(DIR* directory, BiosParameterBlock* bpb ){
unsigned int cluster = directory->FstClusLo;
printf("Listing contents of " );
for(unsigned char n : directory->Name){
if(n == 0x20)
continue;
kterm_put(n);
}
kterm_put('\n');
printf("FsCluHi: 0x%x , FsCluLo: 0x%x\n", directory->FstClusHi, directory->FstClusLo);
printf("Cluster: 0x%x\n", cluster);
unsigned int FATEntry = FAT::GetFATEntry(bpb, cluster);
printf("FAT_Entry: 0x%x\n", FATEntry);
unsigned int root_dir_sectors = FAT::RootDirSize(bpb);
unsigned int fat_size = bpb->FATSz16;
unsigned int first_data_sector = bpb->RsvdSecCnt + ( bpb->NumFATs * fat_size) + root_dir_sectors;
unsigned int first_directory_sector = ((cluster - 2) * bpb->SecPerClus) + first_data_sector;
printf("Directory first sector 0x%x\n" , first_directory_sector);
uint16_t data[256];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, first_directory_sector, data);
auto* directoryContents = (DIR*) data;
for(int i = 0; i < sizeof(data) / sizeof(DIR); i++){
DIR* entry = (DIR*)((uint32_t)directoryContents + (i * sizeof(DIR)));
if(entry->Name[0] == FAT::FREE_DIR || entry->Name[0] == FAT::FREE_DIR_2 || entry->Name[0] == 0xE5)
continue;
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_HIDDEN){
continue;
}
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_SYSTEM)
continue;
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_VOLUME_ID){
continue;
}
if (!(entry->ATTR & FAT::ATTRIBUTES::ATTR_LONG_NAME)){
for(char n : entry->Name){
if(n == 0x20)
continue;
kterm_put(n);
}
kterm_put('\n');
}else{
printf("LFN\n");
}
}
}
void FAT::ReadFileContents(DIR* fileEntry , BiosParameterBlock* bpb){
unsigned int cluster = fileEntry->FstClusLo;
printf("cluster NR: %x\n", cluster);
unsigned int FATEntry = FAT::GetFATEntry(bpb, cluster);
unsigned int root_dir_sectors = FAT::RootDirSize(bpb);
unsigned int fat_size = bpb->FATSz16;
unsigned int first_data_sector = bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sectors;
unsigned int file_data_sector = ((cluster -2) * bpb->SecPerClus) + first_data_sector;
printf("FAT entry = %x\n", FATEntry);
uint16_t data[256];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, file_data_sector, data);
for (unsigned short n : data)
{
kterm_put(n & 0x00ff);
kterm_put(n >> 8);
}
kterm_put('\n');
}
void FAT::ListRootDirectoryContents(BiosParameterBlock* bpb){
int total_sectors = bpb->TotSec32;
int fat_size = bpb->FATSz16;
int root_dir_sectors = FAT::RootDirSize(bpb);
int first_data_sector = bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sectors ;
int data_sectors = bpb->TotSec32 - (bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sectors);
int total_clusters = data_sectors / bpb->SecPerClus;
int first_root_dir_sector = first_data_sector - root_dir_sectors;
//int first_sector_of_cluster = ((cluster - 2) * bpb->SecPerClus) + first_data_sector;
uint16_t data[256];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, first_root_dir_sector, data);
auto* RootDirectory = (DIR*)data;
for(int i = 0; i < sizeof(data) / sizeof (DIR); i++)
{
DIR* entry = (DIR*)((uint32_t)RootDirectory + (i * sizeof(DIR)));
if(entry->Name[0] == FAT::FREE_DIR || entry->Name[0] == FAT::FREE_DIR_2 || entry->Name[0] == 0xE5){
continue;
}
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_HIDDEN){
continue;
}
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_SYSTEM)
continue;
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_VOLUME_ID){
continue;
}
if (!(entry->ATTR & FAT::ATTRIBUTES::ATTR_LONG_NAME)){
for(char n : entry->Name){
if(n == 0x20)
continue;
kterm_put(n);
}
}else{
printf("Long file name detected!");
}
printf(" [Size: %d bytes, Attributes: %d]\n", entry->ATTR, entry->FileSize);
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_DIRECTORY ){
FAT::OpenSubdir(entry, bpb);
} else {
FAT::ReadFileContents(entry, bpb);
}
}
}

View File

@ -0,0 +1,119 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
#include "../../vfs/vfs_types.h"
#include "../../vfs/vfs_types.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
struct ExtendedBootRecord_FAT16{
uint8_t DrvNum;
uint8_t Reserved1;
uint8_t BootSig;
const uint32_t VolID;
uint8_t VolLab [11];
uint8_t FilSysType [8];
uint8_t bootCode [448];
uint16_t Signature_word;
uint8_t SecRmndr[512];
}__attribute__((packed));
struct BiosParameterBlock {
uint8_t jmpBoot[3];
uint8_t OEMName [8];
uint16_t BytsPerSec ; // I suspect would be 512
uint8_t SecPerClus ;
uint16_t RsvdSecCnt;
uint8_t NumFATs; // Probably equals 2
uint16_t RootEntCnt; // Root directory must contain entire sectors
uint16_t TotSec16 ; // 0 means >65535 sectors in volume , actual count can be found in LargeSectorCount
uint8_t Media ; // Indication the media descriptor type
uint16_t FATSz16;// only in FAT12 / FAT 16
uint16_t SecPerTrk;
uint16_t NumHeads;
uint32_t HiddSec;
uint32_t TotSec32;
ExtendedBootRecord_FAT16 ebpb;
}__attribute__((packed));
struct DIR {
uint8_t Name [11];
uint8_t ATTR ;
uint8_t NTRes;
uint8_t CrtTimeTenth; // File Creation time component - count of tenths of a second (between 0 and 199)
uint16_t CrtTime; // Creation time. Granularity is 2 seconds
uint16_t CrtDate; // Creation date.
uint16_t LstAccDate; // Last Access Date (Last read or write date)
uint16_t FstClusHi; // High Word of first data cluster for file/directory described
uint16_t WrtTime; // Last Modification time | Must equal CrtTime
uint16_t WrtDate; // Last Modification date | Must equal CrtDate
uint16_t FstClusLo; // Low word of first data cluster for file/directory described
uint32_t FileSize; // size in bytes of file/directory described
}__attribute__((packed));
enum struct FAT_TYPE{
FAT12,
FAT16,
FAT32,
VFAT,
UNKOWN
};
class FAT {
public:
// Wanted API for vfs
static FILE Open(char* filename);
static int close(FILE* file);
static int Read(FILE* file, void* buffer , unsigned int length);
static int Write(FILE* file, const void* buffer, unsigned int length);
static int Create(inode* dir_node, inode** target, const char* component_name);
static DirectoryNode* Lookup(inode* , DirectoryNode*);
static int Compare(DirectoryNode* , char *filename, char *filename2);
static FS_SUPER* Mount(filesystem* fs, const char* name , vfsmount* mount);
static const int FREE = 0x0000;
static const int ALLOCATED = 0x0002;
static const int BAD = 0xFFF7;
static const int EOF = 0xFFFF;
static const int ClnShutBitMask = 0x8000;
static const int HrdErrBitMask = 0x4000;
static const char DOS_TRAILING_SPACE = 0x20;
static const char FREE_DIR = 0xE5; // If KANJI charset 0x05
static const char FREE_DIR_2 = 0x00; // All directories after this are free including this one
static void ListRootDirectoryContents(BiosParameterBlock* bpb );
static BiosParameterBlock* GetBiosParameterBlock(bool DEBUG =false );
enum ATTRIBUTES {
ATTR_READ_ONLY = 0x01,
ATTR_HIDDEN = 0x02,
ATTR_SYSTEM = 0x04,
ATTR_VOLUME_ID = 0x08,
ATTR_DIRECTORY = 0x10,
ATTR_ARCHIVE = 0x20,
ATTR_LONG_NAME = (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
};
private:
static FAT_TYPE DetermineFATType(BiosParameterBlock* bpb);
static uint16_t GetFATEntry(BiosParameterBlock*, unsigned int);
static uint16_t DetermineFreeSpace();
static int GetSectorOfRootDirectory(BiosParameterBlock*);
static unsigned int RootDirSize(BiosParameterBlock*);
static void OpenSubdir (DIR*, BiosParameterBlock*);
static void ReadFileContents(DIR *fileEntry, BiosParameterBlock *bpb);
enum ENTRY_SIZE {
FAT12 = 12,
FAT16 = 16,
FAT32 = 32
};
};

View File

@ -0,0 +1,42 @@
//
// Created by nigel on 23/02/23.
//
#pragma once
#include "../../../terminal/kterm.h"
#include "../../../memory/KernelHeap.h"
#include "../../../../CoreLib/Memory.h"
// Date Format
// [0..4] Day
// [5..8] Month
// [9..15] Year
class MSDOSDATE {
static void ParseDate(unsigned int date){
printf("Date (hex) 0x%x\n", date);
unsigned int year = (date >> 9 )+ 1980;
unsigned int month = (date & 0xf0 ) >> 4;
unsigned int day = date & 0xf ;
printf("Date: (D,M,Y) %d, %d ,%d\n", day , month, year );
}
};
// Time Format
// [0..4] Seconds
// [5..10] Minute
// [11..15] Hour
class MSDOSTIME {
static void ParseTime(unsigned int time)
{
printf("Time (hex) 0x%x\n", time);
unsigned int seconds = ( time & 0x0f) * 2;
unsigned int minutes = (time & 0xf0);
unsigned int hours = (time & 0xf00);
printf("Time (H:M:S) %d:%d:%d\n", hours, minutes, seconds);
}
};

98
kernel/storage/ide/ide.h Normal file
View File

@ -0,0 +1,98 @@
#pragma once
#include <stdint-gcc.h>
#include "../../terminal/kterm.h"
#include "ideCommands.h"
#include "sampleIDE.h"
#include "../../pci/pciDevice.h"
#include "../../pci/pci.h"
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
IDEChannelRegisters channels[2];
IDE_DEVICE ide_devices[4];
inline void CheckProgIF(uint8_t ProgIF){
if( IS_BIT_SET(ProgIF, 0) ) // Is the 0th bit set
{
printf ("Primary Channel is in PCI native mode\n");
} else{
printf("Primary Channel is in Compatibility mode\n");
}
if( IS_BIT_SET(ProgIF, 1)){
printf("Bit 0 can be modified\n");
}else{
printf("Bit 0 cannot be modified\n");
}
if( IS_BIT_SET(ProgIF, 2)){
printf("Secondary channel is in PCI native mode\n");
}else{
printf("Secondary channel is in Compatibility mode\n");
}
if( IS_BIT_SET(ProgIF, 3)){
printf("Bit 2 can be modified\n");
}else{
printf("Bit 2 cannot be modified\n");
}
if( IS_BIT_SET(ProgIF , 7)){
printf("This is a bus master IDE Controller\n");
} else{
printf("This controller doesn't support DMA!\n");
}
}
inline void TestIDEController(){
// Do stuff
printf("Testing IDE controllers\n");
// NOTE: Testing done with a hard coded known PCI addres
// Of an intel PIIX3 IDE Controller
int bus = 0;
int device =1 , function = 1;
PCIBusAddress IDEControllerPCIAddress = PCIBusAddress{bus,device, function};
uint8_t ProgIF = PCI::GetProgIF(IDEControllerPCIAddress);
printf( "ProgIF: 0x%x\n" ,ProgIF);
//CheckProgIF(ProgIF);
// For this test will just assume all bits are set
// the CheckProgIF can check but on the test machine all bits are set anyways
uint32_t BAR0,BAR1,BAR2,BAR3, BAR4;
BAR0 = PCI::ReadBAR(IDEControllerPCIAddress, 0);
BAR1 = PCI::ReadBAR(IDEControllerPCIAddress, 1);
BAR2 = PCI::ReadBAR(IDEControllerPCIAddress, 2);
BAR3 = PCI::ReadBAR(IDEControllerPCIAddress, 3);
BAR4 = PCI::ReadBAR(IDEControllerPCIAddress, 4);
// All bars are return 0xffffff for some as of yet mysterious reason!
printf( "BAR 0: 0x%x\n", BAR0);
printf( "BAR 1: 0x%x\n", BAR1);
printf( "BAR 2: 0x%x\n", BAR2);
printf( "BAR 3: 0x%x\n", BAR3);
printf( "BAR 4: 0x%x\n", BAR4);
init_IDE(BAR0, BAR1, BAR2, BAR3, BAR4);
// Read Something from disc
unsigned int maxByteCount = 20 ;
void* MDA_buffer = (void*)0xC0000000;
}

View File

@ -0,0 +1,86 @@
#pragma once
// Commands
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_READ_PIO_EXT 0x24
#define ATA_CMD_READ_DMA 0xC8
#define ATA_CMD_READ_DMA_EXT 0x25
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_CMD_WRITE_PIO_EXT 0x34
#define ATA_CMD_WRITE_DMA 0xCA
#define ATA_CMD_WRITE_DMA_EXT 0x35
#define ATA_CMD_CACHE_FLUSH 0xE7
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
#define ATA_CMD_PACKET 0xA0
#define ATA_CMD_IDENTIFY_PACKET 0xA1
#define ATA_CMD_IDENTIFY 0xEC
#define ATAPI_CMD_READ 0xA8
#define ATAPI_CMD_EJECT 0x1B
#define ATA_IDENT_DEVICETYPE 0
#define ATA_IDENT_CYLINDERS 2
#define ATA_IDENT_HEADS 6
#define ATA_IDENT_SECTORS 12
#define ATA_IDENT_SERIAL 20
#define ATA_IDENT_MODEL 54
#define ATA_IDENT_CAPABILITIES 98
#define ATA_IDENT_FIELDVALID 106
#define ATA_IDENT_MAX_LBA 120
#define ATA_IDENT_COMMANDSETS 164
#define ATA_IDENT_MAX_LBA_EXT 200
#define IDE_ATA 0x00
#define IDE_ATAPI 0x01
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x01
#define ATA_REG_DATA 0x00
#define ATA_REG_ERROR 0x01
#define ATA_REG_FEATURES 0x01
#define ATA_REG_SECCOUNT0 0x02
#define ATA_REG_LBA0 0x03
#define ATA_REG_LBA1 0x04
#define ATA_REG_LBA2 0x05
#define ATA_REG_HDDEVSEL 0x06
#define ATA_REG_COMMAND 0x07
#define ATA_REG_STATUS 0x07
#define ATA_REG_SECCOUNT1 0x08
#define ATA_REG_LBA3 0x09
#define ATA_REG_LBA4 0x0A
#define ATA_REG_LBA5 0x0B
#define ATA_REG_CONTROL 0x0C
#define ATA_REG_ALTSTATUS 0x0C
#define ATA_REG_DEVADDRESS 0x0D
// Channels:
#define ATA_PRIMARY 0x00
#define ATA_SECONDARY 0x01
// Directions:
#define ATA_READ 0x00
#define ATA_WRITE 0x01
// Status
#define ATA_SR_BSY 0x80 // Busy
#define ATA_SR_DRDY 0x40 // Drive ready
#define ATA_SR_DF 0x20 // Drive write fault
#define ATA_SR_DSC 0x10 // Drive seek complete
#define ATA_SR_DRQ 0x08 // Data request ready
#define ATA_SR_CORR 0x04 // Corrected data
#define ATA_SR_IDX 0x02 // Index
#define ATA_SR_ERR 0x01 // Error
// Errors
#define ATA_ER_BBK 0x80 // Bad block
#define ATA_ER_UNC 0x40 // Uncorrectable data
#define ATA_ER_MC 0x20 // Media changed
#define ATA_ER_IDNF 0x10 // ID mark not found
#define ATA_ER_MCR 0x08 // Media change request
#define ATA_ER_ABRT 0x04 // Command aborted
#define ATA_ER_TK0NF 0x02 // Track 0 not found
#define ATA_ER_AMNF 0x01 // No address mark

View File

@ -0,0 +1,29 @@
#pragma once
struct IDEChannelRegisters{
unsigned short base; // I/O Base.
unsigned short ctrl; // Control Base
unsigned short bmide; // Bus Master IDE
unsigned char nIEN; // IEN (no interrupt)
};
struct IDE_DEVICE {
unsigned char Reserved; // 0 (Empty) or 1 (This device exists).
unsigned char Channel; // 0 (Primary Channel) or 1 (Secondary Channel).
unsigned char Drive; // 0 (Master Drive) or 1 (Slave Drive).
unsigned short Type; // 0 ATA, 1:ATAPI
unsigned short Signature; // Drive Signature
unsigned short Capabilities; // Features.
unsigned int CommandSets; // Command Sets Supported.
unsigned int Size; // Size in Sectors (NOTE: Seems unused nowadays as i've only seen the value be zero
unsigned char Model[41]; // Model in string.
} ;
extern IDEChannelRegisters channels[2];
extern IDE_DEVICE ide_devices[4];
extern unsigned char ide_buf[2048];
extern unsigned char ide_irq_invoked;
extern unsigned char atapi_packet[12];

View File

@ -0,0 +1,258 @@
#pragma once
#include <stdint-gcc.h>
#include "../../terminal/kterm.h"
#include "sampleIDE.definitions.h"
#include "ideCommands.h"
void Detect_IO_Ports(uint32_t BAR0, uint32_t BAR1,uint32_t BAR2, uint32_t BAR3, uint32_t BAR4);
void DetectDevices();
unsigned char ide_buf[2048] = {0};
unsigned char ide_irq_invoked = 0;
unsigned char atapi_packet[12] = {0xA8,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void wait(int t){
volatile int i,j;
for(i=0;i<t;i++)
for(j=0;j<25000;j++)
asm("NOP");
}
void ide_write(unsigned char channel, unsigned char reg, unsigned char data){
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
if (reg < 0x08)
outb(channels[channel].base + reg - 0x00, data);
else if (reg < 0x0C)
outb(channels[channel].base + reg - 0x06, data);
else if (reg < 0x0E)
outb(channels[channel].ctrl + reg - 0x0A, data);
else if (reg < 0x16)
outb(channels[channel].bmide + reg - 0x0E, data);
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
}
unsigned char ide_read(unsigned char channel, unsigned char reg){
unsigned char result;
if( reg > 0x07 && reg < 0x0C)
ide_write(channel,ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
if( reg < 0x08)
result = inb(channels[channel].base + reg - 0x00);
else if (reg < 0x0C)
result = inb(channels[channel].base + reg - 0x06);
else if (reg < 0x0E)
result = inb(channels[channel].ctrl + reg - 0x0A);
else if (reg < 0x16)
result = inb(channels[channel].bmide + reg - 0x0E);
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
return result;
}
void ide_read_buffer(unsigned char channel, unsigned char reg, unsigned int buffer, unsigned int quads){
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
if (reg < 0x08)
insl(channels[channel].base + reg - 0x00, (void *)buffer, quads);
else if (reg < 0x0C)
insl(channels[channel].base + reg - 0x06, (void *)buffer, quads);
else if (reg < 0x0E)
insl(channels[channel].ctrl + reg - 0x0A, (void *)buffer, quads);
else if (reg < 0x16)
insl(channels[channel].bmide + reg - 0x0E, (void *)buffer, quads);
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
}
unsigned char ide_polling(unsigned char channel, unsigned int advanced_check) {
// (I) Delay 400 nanosecond for BSY to be set:
// -------------------------------------------------
for(int i = 0; i < 4; i++)
ide_read(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times.
// (II) Wait for BSY to be cleared:
// -------------------------------------------------
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY)
; // Wait for BSY to be zero.
if (advanced_check) {
unsigned char state = ide_read(channel, ATA_REG_STATUS); // Read Status Register.
// (III) Check For Errors:
// -------------------------------------------------
if (state & ATA_SR_ERR)
return 2; // Error.
// (IV) Check If Device fault:
// -------------------------------------------------
if (state & ATA_SR_DF)
return 1; // Device Fault.
// (V) Check DRQ:
// -------------------------------------------------
// BSY = 0; DF = 0; ERR = 0 so we should check for DRQ now.
if ((state & ATA_SR_DRQ) == 0)
return 3; // DRQ should be set
}
return 0; // No Error.
}
unsigned char ide_print_error(unsigned int drive, unsigned char err) {
if (err == 0)
return err;
printf("IDE:");
if (err == 1) {printf("- Device Fault\n "); err = 19;}
else if (err == 2) {
unsigned char st = ide_read(ide_devices[drive].Channel, ATA_REG_ERROR);
if (st & ATA_ER_AMNF) {printf("- No Address Mark Found\n "); err = 7;}
if (st & ATA_ER_TK0NF) {printf("- No Media or Media Error\n "); err = 3;}
if (st & ATA_ER_ABRT) {printf("- Command Aborted\n "); err = 20;}
if (st & ATA_ER_MCR) {printf("- No Media or Media Error\n "); err = 3;}
if (st & ATA_ER_IDNF) {printf("- ID mark not Found\n "); err = 21;}
if (st & ATA_ER_MC) {printf("- No Media or Media Error\n "); err = 3;}
if (st & ATA_ER_UNC) {printf("- Uncorrectable Data Error\n "); err = 22;}
if (st & ATA_ER_BBK) {printf("- Bad Sectors\n "); err = 13;}
} else if (err == 3) {printf("- Reads Nothing\n "); err = 23;}
else if (err == 4) {printf("- Write Protected\n "); err = 8;}
printf("- [%s %s] %s\n",
(const char *[]){"Primary", "Secondary"}[ide_devices[drive].Channel], // Use the channel as an index into the array
(const char *[]){"Master", "Slave"}[ide_devices[drive].Drive], // Same as above, using the drive
ide_devices[drive].Model);
return err;
}
inline void init_IDE( uint32_t BAR0, uint32_t BAR1,uint32_t BAR2, uint32_t BAR3, uint32_t BAR4)
{
Detect_IO_Ports( BAR0, BAR1, BAR2, BAR3, BAR4);
printf("ATA Primary port, base: 0x%x, ctrl: 0x%x\n", channels[ATA_PRIMARY].base , channels[ATA_PRIMARY].ctrl);
printf("ATA Secondary port, base: 0x%x, ctrl: 0x%x\n", channels[ATA_SECONDARY].base , channels[ATA_SECONDARY].ctrl);
// 2- Disable IRQs:
ide_write(ATA_PRIMARY , ATA_REG_CONTROL, 2);
ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2);
DetectDevices();
return;
// 4- Print Summary:
for (int i = 0; i < 4; i++)
if (ide_devices[i].Reserved == 1) {
printf(" Found %s Drive %d bytes - %x\n",
(const char *[]){"ATA", "ATAPI"}[ide_devices[i].Type], /* Type */
ide_devices[i].Size / 2, /* Size */
ide_devices[i].Model);
}
}
// 3- Detect ATA-ATAPI Devices:
inline void DetectDevices(){
int i, j, k, count = 0;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
unsigned char err = 0, type = IDE_ATA, status;
ide_devices[count].Reserved = 0; // Assuming that no drive here.
// (I) Select Drive:
ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive.
wait(1000); // Wait 1ms for drive select to work.
// (II) Send ATA Identify Command:
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
wait(1000);
// (III) Polling:
if (ide_read(i, ATA_REG_STATUS) == 0) continue; // If Status = 0, No Device.
while(1) {
status = ide_read(i, ATA_REG_STATUS);
if ((status & ATA_SR_ERR)) {err = 1; break;} // If Err, Device is not ATA.
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; // Everything is right.
}
// (IV) Probe for ATAPI Devices:
if (err != 0) {
unsigned char cl = ide_read(i, ATA_REG_LBA1);
unsigned char ch = ide_read(i, ATA_REG_LBA2);
if (cl == 0x14 && ch ==0xEB)
type = IDE_ATAPI;
else if (cl == 0x69 && ch == 0x96)
type = IDE_ATAPI;
else
continue; // Unknown Type (may not be a device).
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
wait(1000);
}
// (V) Read Identification Space of the Device:
ide_read_buffer(i, ATA_REG_DATA, (unsigned int) ide_buf, 128);
// (VI) Read Device Parameters:
ide_devices[count].Reserved = 1;
ide_devices[count].Type = type;
ide_devices[count].Channel = i;
ide_devices[count].Drive = j;
ide_devices[count].Signature = *((unsigned short *)(ide_buf + ATA_IDENT_DEVICETYPE));
ide_devices[count].Capabilities = *((unsigned short *)(ide_buf + ATA_IDENT_CAPABILITIES));
ide_devices[count].CommandSets = *((unsigned int *)(ide_buf + ATA_IDENT_COMMANDSETS));
// (VII) Get Size:
if (ide_devices[count].CommandSets & (1 << 26))
// Device uses 48-Bit Addressing:
ide_devices[count].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA_EXT));
else
// Device uses CHS or 28-bit Addressing:
ide_devices[count].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA));
// (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...):
for(k = 0; k < 40; k += 2) {
ide_devices[count].Model[k] = ide_buf[ATA_IDENT_MODEL + k + 1];
ide_devices[count].Model[k + 1] = ide_buf[ATA_IDENT_MODEL + k];}
ide_devices[count].Model[40] = 0; // Terminate String.
count++;
}
}
inline void Detect_IO_Ports(uint32_t BAR0, uint32_t BAR1,uint32_t BAR2, uint32_t BAR3, uint32_t BAR4){
// 1 Detect I/O Ports which interface an IDE Controller
// Based on the implementation within serenity
channels[ATA_PRIMARY].base = (BAR0 == 0x1 || BAR0 == 0x0) ? 0x1F0 : BAR0 & (~1);
channels[ATA_PRIMARY ].ctrl = (BAR1 == 0x1 || BAR1 == 0x0) ? 0x3F6 : BAR1 & (~1);
channels[ATA_SECONDARY].base = (BAR2 == 0x1 || BAR2 == 0x0) ? 0x170 : BAR2 & (~1);
channels[ATA_SECONDARY].ctrl = (BAR3 == 0x1 || BAR3 == 0x0) ? 0x376 : BAR3 & (~1);
channels[ATA_PRIMARY ].bmide = (BAR4 & (~1)) + 0; // Bus Master IDE
channels[ATA_SECONDARY].bmide = (BAR4 & (~1)) + 8; // Bus Master IDE
}
bool driveAvailable(){
int devNumber = 0;
for ( auto device : ide_devices){
if(!device.Reserved)
continue;
devNumber++;
}
// FIXME: If no drive is connected we continue trying to read from
// a not connected drive!
//ATAPIO::Identify((uint16_t) BUS_PORT::Primary, DEVICE_DRIVE::MASTER);
return true;
}

View File

@ -0,0 +1,18 @@
//
// Created by nigel on 23/02/23.
//
#include "partitionManager.h"
bool partitionManager::Validate( )
{
//auto* bootParams = getBPB(this, true);
//if(bootParams->OEM_id) {
// return true;
//}
return true;
}

Some files were not shown because too many files have changed in this diff Show More