mirror of
https://github.com/Tom-on64/kern.git
synced 2026-11-03 18:22:22 +00:00
MAJOR RESTRUCTURE
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
Bootloader
|
||||
============
|
||||
|
||||
Kern uses a two stage bootloader. The first stage is the 512 byte bootsector.
|
||||
This code loads the 2nd stage, which is in the next seven sectors.
|
||||
Together this whole bootloader takes up the first filesystem block (4kiB).
|
||||
|
||||
Bootframe
|
||||
---------
|
||||
When the bootloader runs the kernel, it pushes a 32-bit address that points
|
||||
to the bootframe It follows the following structure:
|
||||
* Memory map
|
||||
* Video memory
|
||||
* ...todo
|
||||
|
||||
It is defined in the libk header 'boot.h'
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
Building & Running
|
||||
==================
|
||||
_If you want to try kern for some reason, you can._
|
||||
|
||||
Tools
|
||||
-----
|
||||
* [NASM](https://www.nasm.us/)
|
||||
* [QEMU](https://www.qemu.org/) (for emulation)
|
||||
|
||||
Unix-Like Systems
|
||||
*****************
|
||||
* [GCC](https://gcc.gnu.org/)
|
||||
|
||||
On MacOS
|
||||
********
|
||||
* A cross compiler: `$ brew tap nativeos/i386-elf-toolchain && brew install i386-elf-binutils i386-elf-gcc`
|
||||
|
||||
Commands
|
||||
--------
|
||||
```sh
|
||||
$ make # Or 'make os'
|
||||
$ make run # Run QEMU
|
||||
```
|
||||
|
||||
_I personally wouldn't recommend running this on real hardware, because it's untested and will just probably break you pc, but if you really want to, you can try it, but don't blame me if something goes wrong._
|
||||
@@ -0,0 +1,188 @@
|
||||
Coding Style
|
||||
============
|
||||
|
||||
Indentation
|
||||
-----------
|
||||
All indents must be a tab character ('\t'). It is recommended to display tabs
|
||||
as eight spaces to avoid extensive indentation. You shouldn't have more than
|
||||
3 levels of indentation.
|
||||
|
||||
Braces
|
||||
------
|
||||
All braces should be placed on the same line as the statement they belong to.
|
||||
```c
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The closing brace should be on it's own line, unless it's being followed by
|
||||
a continuation of the statement (e.g. 'else' after an 'if').
|
||||
```c
|
||||
if (condition) {
|
||||
doSomething();
|
||||
} else {
|
||||
doSomethingElse();
|
||||
}
|
||||
```
|
||||
|
||||
There may be a single statement without braces if it fits on a single line.
|
||||
```c
|
||||
// This is good
|
||||
if (condition) doSomething();
|
||||
|
||||
// This is too long => bad
|
||||
if (condition) doSomethingButLong(someParameter, someNumber * otherNumber, "A literal string");
|
||||
```
|
||||
|
||||
Spaces
|
||||
------
|
||||
Spaces should be after most statements like 'while', 'for', 'if', etc.
|
||||
Spaces should not be placed after 'sizeof' and 'alignof' statements.
|
||||
There should not be spaces around the inside of a parenthesized expression, e.g.:
|
||||
`int x = ( y * x ); // This is bad`
|
||||
|
||||
The '*' in pointer declarations, it is prefered to be appended to the
|
||||
type name, e.g.:
|
||||
```c
|
||||
char* string; // Good
|
||||
char** strings; // Good
|
||||
int *intptr; // Bad
|
||||
int *a, *b; // Allowed, but should be split into multiple declarations
|
||||
```
|
||||
|
||||
Spaces should also be placed between binary and ternary operators, but
|
||||
should not be placed after/before unary operators or member access operators.
|
||||
|
||||
Naming
|
||||
------
|
||||
_The hardest thing in programming_
|
||||
Identifiers should use camelCase (starting with lowercase). In special
|
||||
cases (e.g. syscall handlers) a short prefix separated with an underscore
|
||||
may be used (e.g. 'sys_malloc').
|
||||
|
||||
Global variables (that should be sparse) and global functions need good,
|
||||
descriptive names. A disk reading function shouldn't be called 'dskrd()'.
|
||||
|
||||
Local variables and functions don't need descriptive names, a loop counter
|
||||
should be named 'i' and not loopCounter.
|
||||
|
||||
Some good naming examples:
|
||||
```c
|
||||
// Random good function names
|
||||
int32_t findFreeBlock(uint32_t count);
|
||||
int32_t ttyWrite(const void* buf, size_t len);
|
||||
uint8_t getRtcRegister(uint8_t reg);
|
||||
|
||||
// Serial functions all start with 'serial'
|
||||
int serialSetup();
|
||||
void serialWrite(uint8_t byte);
|
||||
uint8_t serialRead();
|
||||
|
||||
// Syscall handlers are prefixed with 'sys_'
|
||||
int sys_malloc(struct intFrame iframe);
|
||||
int sys_free(struct intFrame iframe);
|
||||
```
|
||||
|
||||
Labels, for 'goto' statements or assembly, should be snake_case.
|
||||
|
||||
Typedefs vs Structs
|
||||
-------------------
|
||||
Typedefs should only be used if:
|
||||
* It's a struct whose members shouldn't be accessed externally, e.g. FILE
|
||||
* It clears confusion, e.g. 'i32' or 'int32_t' is better than just 'int'
|
||||
There may be more, but it's better to not use them.
|
||||
|
||||
Functions
|
||||
---------
|
||||
Functions should be short and do one thing. If a function does multiple things,
|
||||
see if you can split it up into multiple functions. Some indicators
|
||||
of a good function are:
|
||||
* It fits into 1-2 screenfulls (let those be 80x24)
|
||||
* There shouldn't be more than ~10 local variables
|
||||
|
||||
In function prototypes, parameter names should be included. It can give more
|
||||
insight into what it is supposed to be.
|
||||
|
||||
Goto
|
||||
----
|
||||
Using the 'goto' statement is fair in these cases:
|
||||
* Exiting nested code
|
||||
* Easier to read code
|
||||
* Getting rid of redundant code
|
||||
* Exiting from multiple points
|
||||
|
||||
Label names should be descriptive, should specify exactly what the goto
|
||||
does (e.g. 'exit_free_buffer'). Avoid numbering these labels incase of having
|
||||
to renumber the later.
|
||||
|
||||
Comments
|
||||
--------
|
||||
Write comments telling What code does, not How. Comments shouldn't be inside
|
||||
a function body. There may be small comments on some trick or ugly thing in
|
||||
a function, but avoid doing that too much. If you need to comment on how
|
||||
everything in a function works, it's probably a really bad function.
|
||||
|
||||
Multiline comments should be over multiple lines. Don't write `/* Something */`.
|
||||
They should look like this:
|
||||
```c
|
||||
/*
|
||||
* This is a multiline comment
|
||||
* The beggining and ending comment characters have their own lines.
|
||||
* Each row also starts with an asterisk, making a nice column.
|
||||
*/
|
||||
```
|
||||
|
||||
Also it is recommended to comment on data in structs, since members may have
|
||||
more abstract names.
|
||||
|
||||
Macros & Enums
|
||||
--------------
|
||||
_Yeah, we do a little magic_
|
||||
|
||||
Constant define macros must be UPPERCASE.
|
||||
`#define FUNNY_NUM 0x69`
|
||||
|
||||
If there are multiple related constants, please use an enum.
|
||||
CAPITALIZED macro names are appreciated, but function-like macros may have
|
||||
lowercase names. Generally, inline functions are prefered over macros.
|
||||
If a macro uses more than one statement, enclose them in their own scope.
|
||||
```c
|
||||
#define MAGIC(_x)\
|
||||
if (_x > 0) doSomething(_x);
|
||||
```
|
||||
|
||||
Things to look out for:
|
||||
* Macros that affect controll flow. `#define FOO(_x) { if (_x < 0) return 1; }
|
||||
* Macros that depend on local variables
|
||||
* Macros used as l-values
|
||||
* Forgetting about precedence. Just wrap everything in parenthesis
|
||||
* Namespace collision, prefix everything in the macro with underscores
|
||||
|
||||
Other Stuff
|
||||
----------
|
||||
Here are some rules/recommendations that don't deserve their own category.
|
||||
|
||||
Inline Assembly
|
||||
***************
|
||||
If you don't need to, don't. But for architecture specific stuff, you may need
|
||||
to. So just don't jump between functions and don't break anything. Also if you
|
||||
think you can optimize better than the compiler, you're wrong.
|
||||
|
||||
Conditional Compilation
|
||||
***********************
|
||||
Try to avoid preprocessor conditionals inside .c source files. Instead write
|
||||
conditionals inside the header and give a NOP version for the #else case.
|
||||
These functions can be called uncoditionally. Empty inline functions work too.
|
||||
|
||||
Using Bool
|
||||
**********
|
||||
You may use bool, but are not required to. It does improve readability
|
||||
|
||||
Allocating Memory
|
||||
*****************
|
||||
The prefered way of allocating memory for a struct is:
|
||||
`ptr = kmalloc(sizeof(*ptr));`
|
||||
Casting the returned void pointer is redundant since C converts void pointers
|
||||
to any other pointers.
|
||||
|
||||
+47
-38
@@ -1,48 +1,57 @@
|
||||
= fsys =
|
||||
Filesystem
|
||||
============
|
||||
|
||||
Sector = 512 Bytes
|
||||
Block = 4096 Bytes
|
||||
|
||||
Reserved sectors:
|
||||
Sector 0..3 - Bootblock, will be loaded by the Bios into memory and executed (512B)
|
||||
Sector 4..7 - Superblock, contains metadata about the filesystem itself (4KiB)
|
||||
Reserved sectors
|
||||
----------------
|
||||
* Sector 0..7 - Bootblock, constains bootloader code that gets ran by the BIOS (4KiB)
|
||||
* Sector 8..F - Superblock, contains metadata about the filesystem itself (4KiB)
|
||||
|
||||
Superblock structure: (4096B)
|
||||
Device ID
|
||||
Max File Size
|
||||
INode Count
|
||||
INode Bitmap Block
|
||||
INodes Start
|
||||
INode Block Count
|
||||
INodes per sector
|
||||
Data Bitmap Block
|
||||
Data Start
|
||||
Data Block Count
|
||||
Root INode Pointer
|
||||
First Unreserved INode
|
||||
Superblock structure (4096B)
|
||||
--------------------
|
||||
* Device ID
|
||||
* Max File Size
|
||||
* INode Count
|
||||
* INode Bitmap Block
|
||||
* INodes Start
|
||||
* INode Block Count
|
||||
* INodes per sector
|
||||
* Data Bitmap Block
|
||||
* Data Start
|
||||
* Data Block Count
|
||||
* Root INode Pointer
|
||||
* First Unreserved INode
|
||||
|
||||
INode structure: (64B)
|
||||
Type
|
||||
Size (bytes)
|
||||
Sector Count (size in sectors)
|
||||
Mode
|
||||
Extent[4]
|
||||
Single Indirect
|
||||
Double Indirect?
|
||||
INode structure (64B)
|
||||
---------------
|
||||
* Type
|
||||
* Size (bytes)
|
||||
* Sector Count (size in sectors)
|
||||
* Mode
|
||||
* Extent[4]
|
||||
* Single Indirect
|
||||
* Double Indirect?
|
||||
|
||||
Extent: (8B)
|
||||
Block
|
||||
Length
|
||||
Extent (8B)
|
||||
------
|
||||
* Block
|
||||
* Length
|
||||
|
||||
Directory Entry: (64B)
|
||||
INode Number
|
||||
Name (max length 60 Bytes)
|
||||
Directory Entry (64B)
|
||||
---------------
|
||||
* INode Number
|
||||
* Name (max length 60 Bytes)
|
||||
|
||||
Filetypes:
|
||||
File
|
||||
Directory
|
||||
#TODO
|
||||
Link
|
||||
Device
|
||||
Stream?
|
||||
Filetypes
|
||||
---------
|
||||
* File
|
||||
* Directory
|
||||
# TODO
|
||||
* Link
|
||||
* Device
|
||||
* Stream?
|
||||
|
||||
These structs are defined in the libk header 'fs/fs.h'
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
Kern Dev Struct
|
||||
===============
|
||||
|
||||
Independant Modules
|
||||
-------------------
|
||||
* Each MUST have their own directory (eg. 'kernel/', 'boot/')
|
||||
* Each MAY have their own internal independant submodules (eg. userspace programs in 'usr/')
|
||||
* A module MAY be dependant on it's own submodules, but it's submodules MUST be independant of each other
|
||||
* Each MUST have a makefile in their directory (eg. 'libc/makefile')
|
||||
* Each module MUST be listed in the 'make.defaults' directory
|
||||
* Each module MUST be self-contained and independentally compilable
|
||||
|
||||
kern (Root "module", is dependant on all of it's submodules)
|
||||
|- boot
|
||||
| |- bootsect (stage1)
|
||||
| '- bootload (stage2)
|
||||
|- kernel
|
||||
| '- libk
|
||||
|- libc (C Standard Library)
|
||||
'- user !EXCEPTION: Userspace programs are dependant upon libc!
|
||||
|- coreutils
|
||||
|- fdisk
|
||||
|- init
|
||||
|- mkfs
|
||||
|- sh
|
||||
..
|
||||
|
||||
TODO
|
||||
====
|
||||
[ ] boot
|
||||
[ ] kernel
|
||||
[x] libc
|
||||
[ ] user
|
||||
[ ] makefile
|
||||
[ ] make.defaults
|
||||
|
||||
Reference in New Issue
Block a user