Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 103 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@

![License](https://img.shields.io/badge/License-GPLv2-orange)

![Version](https://img.shields.io/badge/Current%20Version-v0.0.1%20beta6-blue)
![Version](https://img.shields.io/badge/Current%20Version-v0.0.1%20beta6.1-blue)

![Build](https://img.shields.io/badge/GCC-faliling-red)

![Build](https://img.shields.io/badge/Clang-passing-brightgreen)
![Build](https://img.shields.io/badge/Build-passing-brightgreen)

## About

VoidFrame is a 64-bit syscall-less **monolithic** kernel designed for the x86_64 architecture written in C and assembly (nasm).
VoidFrame is a 64-bit syscall-less **monolithic** kernel (sounds weird and contradicting right?) designed for the x86_64 architecture written in C and assembly (nasm).
This kernel was intended and targeted for people who want to learn about operating systems and want to make a piece of their own.
As the designer of this kernel, I wanted to make something that is simple, fast, secure and easy to understand.
Which obviously means that it is not a perfect kernel. And it breaks all the time.
Expand All @@ -36,7 +34,7 @@ It would be amazing if you could contribute to this project!
- ninja >= 1.11
- clang >= 18.0.0 (or any C-compliant compiler)
- nasm >= 2.16
- qemu >= 7.0.0
- qemu >= 7.0.0 (minimum, failed to run on Limbo emulator (v5.x))
- mkfs.fat (dosfstools)
- mkfs.ext2
- grub-mkrescue
Expand All @@ -63,4 +61,102 @@ meson setup build -Dexclude_extra_objects=true
cd build
ninja
ninja runmin
```
```

## Features
### Architecture
- [x] x86_64
- [ ] AArch64
- [ ] MIPS
- [ ] SPARC
- [ ] RISC-V (RV64)
- [ ] Power (modern)
### Boot
- [x] Multiboot2
- [x] GRUB (BIOS)
- [ ] GRUB (UEFI)
- [ ] GRUB (Hybrid)
- [x] Vesa (VBE)
- [x] Multiboot2 Info parsing
### Core
- [x] Multi-tasking (MLFQ)
- [x] Per-process authentication check (Astra)
- [x] Dynamic ML-inspired PIT frequency scaling (DynamoX)
- [x] Virtual Memory (canonical)
- [x] Physical Memory
- [x] Memory Pool
- [x] AVX2/SSE2 accelerated memory operations
- [x] Memory & user protection
- [x] Memory canaries, guard pages
- [x] Per-process memory checks (Cerberus)
- [x] Stack guard
- [x] Stack trace
- [x] Heap (Class-based)
- [x] Paging
- [x] Interrupts
- [x] Process Management
- [x] Locks (MCS/RW/norm)
- [x] Atomics
- [x] IPC
- [x] Compositor
- [x] Embedded shell
- [x] Builtin Editor
- [x] ELF64 loader
- [ ] PE32+/COFF loader
- [ ] a.out loader
### Filesystems
- FAT1x
- [x] Read
- [x] Write
- [x] Create
- [x] Delete
- [x] List
- EXT2
- [x] Read
- [x] Write
- [x] Create
- [x] Delete
- [x] List
- VFRFS (VoidFrame RAMFS)
- [x] Read
- [x] Write
- [x] Create
- [x] Delete
- [x] List
- ISO9660 (RO)
- [x] Read
- [x] List
- VFS (Virtual File System)
- [x] Full abstraction
- [x] EXT2
- [x] FAT1x
- [x] VFRFS
- [ ] ISO9660
### Drivers
- Network
- [x] RTL8139 (PCI)
- Sound
- [x] SB16 (PCI)
- USB
- [x] xHCI
- VirtIO
- [x] Block
- Graphics
- [x] Vesa (VBE)
- [x] VMWare SVGA II
- [x] VGA text mode
- Timer
- [x] PIT
- [x] PIC
- [x] APIC (not working)
- [x] RTC
- Generic
- [x] PCI
- [x] ISA
- [x] xHCI
- [x] Serial
- [x] PS/2
- [x] LPT
- Storage
- [x] PATA (IDE)
- [x] VirtIO Block
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# The VoidFrame monolithic kernel 💫 v0.0.1-beta6
# The VoidFrame monolithic kernel 💫 v0.0.1-beta6.1

## Table of Contents

Expand Down
214 changes: 120 additions & 94 deletions drivers/RTC/Rtc.c
Original file line number Diff line number Diff line change
@@ -1,105 +1,131 @@
#include "Rtc.h"
#include "RTC/Rtc.h"
#include "Io.h"
#include "stdbool.h"

#define CMOS_ADDRESS 0x70
#define CMOS_DATA 0x71

// CMOS Register numbers
#define CMOS_REG_SECONDS 0x00
#define CMOS_REG_MINUTES 0x02
#define CMOS_REG_HOURS 0x04
#define CMOS_REG_DAY 0x07
#define CMOS_REG_MONTH 0x08
#define CMOS_REG_YEAR 0x09
#define CMOS_REG_CENTURY 0x32 // Common on newer systems

#define CMOS_REG_STATUS_A 0x0A
#define CMOS_REG_STATUS_B 0x0B

static uint8_t cmos_read(uint8_t reg) {
// Select the register, making sure NMI is disabled
outb(CMOS_ADDRESS, (1 << 7) | reg);
// Read the data
return inb(CMOS_DATA);
#define RTC_CMOS_ADDRESS 0x70
#define RTC_CMOS_DATA 0x71

#define RTC_SECONDS 0x00
#define RTC_MINUTES 0x02
#define RTC_HOURS 0x04
#define RTC_DAY_OF_WEEK 0x06
#define RTC_DAY_OF_MONTH 0x07
#define RTC_MONTH 0x08
#define RTC_YEAR 0x09
#define RTC_CENTURY 0x32 // Most common century register
#define RTC_STATUS_A 0x0A
#define RTC_STATUS_B 0x0B
#define RTC_STATUS_C 0x0C

typedef rtc_time_t RtcDateTime;

static uint8_t Rtc_ReadRegister(uint8_t reg) {
outb(RTC_CMOS_ADDRESS, reg);
return inb(RTC_CMOS_DATA);
}

static int get_update_in_progress_flag() {
return cmos_read(CMOS_REG_STATUS_A) & 0x80;
static void Rtc_WriteRegister(uint8_t reg, uint8_t value) {
outb(RTC_CMOS_ADDRESS, reg);
outb(RTC_CMOS_DATA, value);
}

static uint8_t bcd_to_bin(uint8_t bcd) {
return (bcd & 0x0F) + ((bcd >> 4) * 10);
int Rtc_BcdToBinary(uint8_t bcd) {
return (bcd & 0x0F) + ((bcd / 16) * 10);
}

void RtcReadTime(rtc_time_t* rtc_time) {
rtc_time_t last_time;
uint8_t status_b;

// The robust way to read the RTC is to read it twice and see if the
// values match. This ensures an update didn't happen in the middle of our read.
do {
// Wait until no update is in progress
while (get_update_in_progress_flag()) {}

rtc_time->second = cmos_read(CMOS_REG_SECONDS);
rtc_time->minute = cmos_read(CMOS_REG_MINUTES);
rtc_time->hour = cmos_read(CMOS_REG_HOURS);
rtc_time->day = cmos_read(CMOS_REG_DAY);
rtc_time->month = cmos_read(CMOS_REG_MONTH);
rtc_time->year = cmos_read(CMOS_REG_YEAR);
rtc_time->century = cmos_read(CMOS_REG_CENTURY);
// Make a copy of the values we just read
last_time = *rtc_time;

// Wait again to ensure we are past the update
while (get_update_in_progress_flag()){}

// Read a second time
last_time.second = cmos_read(CMOS_REG_SECONDS);
last_time.minute = cmos_read(CMOS_REG_MINUTES);
last_time.hour = cmos_read(CMOS_REG_HOURS);
last_time.day = cmos_read(CMOS_REG_DAY);
last_time.month = cmos_read(CMOS_REG_MONTH);
last_time.year = cmos_read(CMOS_REG_YEAR);
#ifdef VF_CONFIG_RTC_CENTURY
last_time.century = cmos_read(CMOS_REG_CENTURY);
#endif

} while ( (last_time.second != rtc_time->second) ||
(last_time.minute != rtc_time->minute) ||
(last_time.hour != rtc_time->hour) ||
(last_time.day != rtc_time->day) ||
(last_time.month != rtc_time->month) ||
(last_time.year != rtc_time->year)
#ifdef VF_CONFIG_RTC_CENTURY
|| (last_time.century != rtc_time->century)
#endif
);


// Now that we have a stable read, convert from BCD if necessary
status_b = cmos_read(CMOS_REG_STATUS_B);

if (!(status_b & 0x04)) { // Bit 2 clear means BCD mode
rtc_time->second = bcd_to_bin(rtc_time->second);
rtc_time->minute = bcd_to_bin(rtc_time->minute);
// Handle 12/24 hour clock for the hour value
rtc_time->hour = ((rtc_time->hour & 0x7F) + 12 * ((rtc_time->hour & 0x80) != 0)) % 24;
rtc_time->day = bcd_to_bin(rtc_time->day);
rtc_time->month = bcd_to_bin(rtc_time->month);
rtc_time->year = bcd_to_bin(rtc_time->year);
uint8_t Rtc_BinaryToBcd(uint8_t binary) {
return ((binary / 10) << 4) | (binary % 10);
}

static bool Rtc_IsUpdating() {
outb(RTC_CMOS_ADDRESS, 0x80 | RTC_STATUS_A); // select reg A, NMI masked
return (inb(RTC_CMOS_DATA) & 0x80) != 0; // UIP bit
}

void RtcReadTime(RtcDateTime *dateTime) {
uint8_t second, minute, hour, day, month, year, century;
uint8_t statusB;

// Wait until the update in progress bit is 0
while (Rtc_IsUpdating());

// Read RTC registers
second = Rtc_ReadRegister(RTC_SECONDS);
minute = Rtc_ReadRegister(RTC_MINUTES);
hour = Rtc_ReadRegister(RTC_HOURS);
day = Rtc_ReadRegister(RTC_DAY_OF_MONTH);
month = Rtc_ReadRegister(RTC_MONTH);
year = Rtc_ReadRegister(RTC_YEAR);
century = Rtc_ReadRegister(RTC_CENTURY); // Read century byte

statusB = Rtc_ReadRegister(RTC_STATUS_B);

if (!(statusB & 0x04)) { // If BCD mode
dateTime->second = Rtc_BcdToBinary(second);
dateTime->minute = Rtc_BcdToBinary(minute);
dateTime->hour = Rtc_BcdToBinary(hour);
dateTime->day = Rtc_BcdToBinary(day);
dateTime->month = Rtc_BcdToBinary(month);
dateTime->year = Rtc_BcdToBinary(year);
dateTime->century = Rtc_BcdToBinary(century);
} else { // Binary mode
dateTime->second = second;
dateTime->minute = minute;
dateTime->hour = hour;
dateTime->day = day;
dateTime->month = month;
dateTime->year = year;
dateTime->century = century;
}
#ifdef VF_CONFIG_RTC_CENTURY
{
uint16_t cval = (uint16_t)rtc_time->century;
if (cval != 0) {
cval = bcd_to_bin((uint8_t)cval);
rtc_time->year += (uint16_t)(cval * 100);
} else {
rtc_time->year += 2000;
}

if (!(statusB & 0x02) && (dateTime->hour & 0x80)) { // 12-hour format and PM
dateTime->hour = ((dateTime->hour & 0x7F) + 12) % 24;
}

// Calculate full year
dateTime->year += dateTime->century * 100;
}

void RtcSetTime(const RtcDateTime *dateTime) {
uint8_t statusB;
uint8_t second, minute, hour, day, month, year, century;

// Read current status B to preserve settings
statusB = Rtc_ReadRegister(RTC_STATUS_B);

// Disable NMI and updates while setting time
Rtc_WriteRegister(RTC_CMOS_ADDRESS, RTC_STATUS_B | 0x80); // Disable NMI
Rtc_WriteRegister(RTC_STATUS_B, statusB | 0x80); // Disable updates

// Convert to BCD if necessary
if (!(statusB & 0x04)) { // If BCD mode
second = Rtc_BinaryToBcd(dateTime->second);
minute = Rtc_BinaryToBcd(dateTime->minute);
hour = Rtc_BinaryToBcd(dateTime->hour);
day = Rtc_BinaryToBcd(dateTime->day);
month = Rtc_BinaryToBcd(dateTime->month);
year = Rtc_BinaryToBcd(dateTime->year % 100);
century = Rtc_BinaryToBcd(dateTime->year / 100);
} else { // Binary mode
second = dateTime->second;
minute = dateTime->minute;
hour = dateTime->hour;
day = dateTime->day;
month = dateTime->month;
year = dateTime->year % 100;
century = dateTime->year / 100;
}
#else
rtc_time->year += 2000;
#endif

// Write to RTC registers
Rtc_WriteRegister(RTC_SECONDS, second);
Rtc_WriteRegister(RTC_MINUTES, minute);
Rtc_WriteRegister(RTC_HOURS, hour);
Rtc_WriteRegister(RTC_DAY_OF_MONTH, day);
Rtc_WriteRegister(RTC_MONTH, month);
Rtc_WriteRegister(RTC_YEAR, year);
Rtc_WriteRegister(RTC_CENTURY, century);

// Re-enable updates and NMI
Rtc_WriteRegister(RTC_STATUS_B, statusB);
Rtc_WriteRegister(RTC_CMOS_ADDRESS, RTC_STATUS_B); // Re-enable NMI
}
5 changes: 4 additions & 1 deletion drivers/RTC/Rtc.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef VOIDFRAME_RTC_H
#define VOIDFRAME_RTC_H

#include <stdint.h>
#include "stdint.h"

// A structure to hold the date and time.
typedef struct {
Expand All @@ -16,5 +16,8 @@ typedef struct {

// Reads the current date and time from the RTC into the provided struct.
void RtcReadTime(rtc_time_t* rtc_time);
void RtcSetTime(const rtc_time_t *dateTime);
uint8_t Rtc_BinaryToBcd(uint8_t binary);
int Rtc_BcdToBinary(uint8_t bcd);

#endif // VOIDFRAME_RTC_H
Loading
Loading