initial razzle

This commit is contained in:
Nicholas Orlowsky 2024-10-03 02:55:54 -05:00
commit cd3d8871df
29 changed files with 1986 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.cache/
build/
iso/boot/kernel.elf

46
CMakeLists.txt Normal file
View file

@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.10)
project(razzle C ASM)
# Check architecture is passed and is supported
set(ALLOWED_ARCHS "i386")
if(NOT DEFINED ARCH)
message(FATAL_ERROR "Architecture not set s not defined. Supported architectures are: ${ALLOWED_ARCHS}")
endif()
list(FIND ALLOWED_ARCHS "${ARCH}" ARCH_INDEX)
if(ARCH_INDEX EQUAL -1)
message(FATAL_ERROR "Unsupported architecture: ${ARCH}. Supported architectures are: ${ALLOWED_ARCHS}.")
endif()
message(STATUS "Building RAZZLE for ${ARCH}.")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-ffreestanding -g -Wall -Wextra -mgeneral-regs-only -DARCH_I386")
set(CMAKE_ASM_FLAGS "-g")
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/linker.ld)
# Common source files
FILE(GLOB SOURCES kernel/kernel.c)
# Architecture Specific Files
if (ARCH STREQUAL "i386")
set(CMAKE_C_COMPILER i386-elf-gcc)
set(CMAKE_ASM_COMPILER i386-elf-as)
set(LD i386-elf-gcc)
FILE(GLOB ASM_SOURCES arch/i386/*.s)
SET(ARCH_FLAG "-DARCH_I386")
endif()
add_executable(kernel.elf ${SOURCES} ${ASM_SOURCES})
set_target_properties(kernel.elf PROPERTIES LINK_FLAGS "-T ${LINKER_SCRIPT} -ffreestanding -O2 -nostdlib -lgcc -g ${ARCH_FLAG}")
add_custom_command(OUTPUT os.iso
COMMAND cp kernel.elf ../iso/boot/kernel.elf
COMMAND genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -A os -input-charset utf8 -quiet -boot-info-table -o os.iso ../iso
DEPENDS kernel.elf
COMMENT "Generating OS ISO"
)
# Run & Debug targets
add_custom_target(run COMMAND qemu-system-i386 -boot d -cdrom os.iso -m 512 -machine type=pc-i440fx-3.1 -monitor stdio DEPENDS os.iso)
add_custom_target(debug COMMAND ./debug.sh DEPENDS os.iso)

135
LICENSE.md Normal file
View file

@ -0,0 +1,135 @@
# THE RAZZLE ULTRA-EXCLUSIVE "LOOK BUT DON'T TOUCH" PUBLIC LICENSE (Version 1.0.0)
**Effective Date:** October 2nd, 2024
**Copyright Holder:** Nicholas Orlowsky
**Project Name:** RAZZLE Operating System ("RAZZLE" or "the Software")
**IMPORTANT LEGAL NOTICE: READ THIS LICENSE CAREFULLY BEFORE USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE. FAILURE TO COMPLY WITH THE TERMS AND CONDITIONS HEREIN WILL RESULT IN IMMEDIATE TERMINATION OF YOUR RIGHTS UNDER THIS LICENSE, AND MAY SUBJECT YOU TO LEGAL ACTION AND LIABILITY FOR DAMAGES.**
1. **Definitions**
1.1. "License" refers to this legal agreement governing the use, modification, and distribution of the Software.
1.2. "Software" refers to RAZZLE, in whole or in part, including but not limited to source code, object code, executables, documentation, and any associated files or components.
1.3. "You" refers to any individual or entity that uses, modifies, distributes, or attempts to use, modify, or distribute the Software.
1.4. "Use" refers to downloading, copying, accessing, installing, executing, or otherwise interacting with the Software in any manner.
1.5. "ICBM" refers to an Intercontinental Ballistic Missile, a type of missile designed for long-range delivery of payloads, with a minimum range of 5,500 kilometers, utilizing a high-arcing trajectory for targeting, and encompassing all associated systems and technologies.
1.5. "December" refers to the twelfth month of the Gregorian calendar, consisting of 31 days, typically associated with the winter season in the Northern Hemisphere and the summer season in the Southern Hemisphere, and encompassing all cultural and holiday observances during this period.
1.6. "SEPTA" refers to the Southeastern Pennsylvania Transportation Authority, the regional public transportation agency providing bus, subway, and commuter rail services in the Greater Philadelphia area, encompassing all associated transit systems, operations, and facilities, including but not limited to the Market-Frankford Line, Broad Street Line, Regional Rail Lines (such as the Paoli/Thorndale Line, Trenton Line, and others), and various bus routes.
2. **Restrictions on Use**
2.1. The Software is provided to You strictly on a "for viewing purposes only" basis. You are prohibited from using the Software in any productive, experimental, educational, personal, commercial, non-commercial, or any other environment.
2.2. Any attempt to modify, reverse engineer, decompile, disassemble, or tamper with the Software in any way is strictly prohibited and will result in the automatic termination of this License.
2.3. You may not distribute, share, sublicense, or otherwise provide the Software to any third party, whether or not in exchange for compensation, without prior written permission from the Copyright Holder.
2.4. The Software may not be used for any purpose, including but not limited to:
a. Any form of computing, data processing, or algorithmic calculation;
b. Any educational purpose, whether academic or otherwise, including but not limited to any current University of Texas computer science students viewing the code;
c. Any experimentation, research, or study;
d. Any personal, recreational, or hobbyist activity;
e. Any commercial, business, or governmental application;
f. Launching ICBM missiles with a range exceeding 7500 kilometers during the month of December;
g. Conducting any activities that may encourage, endorse, or facilitate evil schemes or nefarious plots;
h. For circumventing rule 3 subsection A of the Bowling Analysis & Research Tool rules;
i. For causing delays on a SEPTA service, including but not limited to the Market-Frankford Line, Broad Street Line, or any Regional Rail Line, that exceed 100 nanoseconds in duration.
3. **Fees and Compensation**
3.1. Use of the Software in any capacity is subject to a mandatory fee structure to be determined solely by the Copyright Holder, at their sole discretion, without prior notice.
3.2. Payment of fees does not grant any rights under this License beyond those explicitly outlined herein. Non-payment or late payment shall result in immediate termination of this License.
4. **No Warranty**
4.1. THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT ANY WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR THAT THE SOFTWARE WILL FUNCTION AS INTENDED OR WITHOUT ERROR.
4.2. The Copyright Holder assumes no liability for any damages, direct or indirect, incidental or consequential, arising from the use or inability to use the Software, even if the Copyright Holder has been advised of the possibility of such damages.
5. **Liability and Indemnification**
5.1. You assume full responsibility for any use of the Software, regardless of its legality or suitability for your intended purpose.
5.2. You agree to indemnify, defend, and hold harmless the Copyright Holder from any and all claims, damages, liabilities, losses, costs, or expenses (including attorneys' fees) arising from or related to your use of the Software, whether authorized or unauthorized.
5.3. The Copyright Holder reserves the right to seek punitive damages for any unauthorized use of the Software, in addition to any other remedies available under law.
5.4. The Copyright Holder is not liable if your use of the Software causes the occurrence (certified by the United States Centers for Disease Control or successor body) of a widespread viral infection transmitted via bites or contact with bodily fluids that causes human corpses to reanimate and seek to consume living human flesh, blood, brain, or nerve tissue and is likely to result in the fall of organized civilization.
6. **Termination**
6.1. This License is effective until terminated.
6.2. Any breach of this License, including but not limited to any unauthorized use, modification, or distribution of the Software, shall result in immediate termination of your rights under this License.
6.3. Upon termination, you must cease all use of the Software and destroy all copies in your possession or control, including any derivatives or modifications, whether or not previously authorized.
7. **Governing Law and Jurisdiction**
7.1. This License shall be governed by and construed in accordance with the laws of the Commonwealth of Pennsylvania, without regard to its conflict of law principles.
7.2. Any legal action or proceeding arising under or in connection with this License shall be brought exclusively in the courts of the Commonwealth of Pennsylvania. You hereby consent to the exclusive jurisdiction and venue of such courts.
8. **Severability**
8.1. If any provision of this License is found to be invalid or unenforceable, the remaining provisions shall continue to be valid and enforceable in accordance with their terms.
9. **Amendments**
9.1. The Copyright Holder reserves the right to amend, modify, or revoke this License at any time, with or without notice. Your continued use of the Software constitutes acceptance of any such amendments or modifications.
---
**YOU ACKNOWLEDGE THAT YOU HAVE READ THIS LICENSE AND AGREE TO BE BOUND BY ITS TERMS AND CONDITIONS.**

26
README.md Normal file
View file

@ -0,0 +1,26 @@
# RAZZLE
Yet another monolithic kernel
## Roadmap
Things that are done and will be done, roughly in the order I'd like to do them.
- [x] i386
- [x] Basic display with BIOS VGA
- [x] Basic input with PS/2 keyboards
- [x] System calls w/ software interrupts
- [x] Multitasking w/ round-robin scheduler
- [ ] FAT Filesystem support
- [ ] Interactive shell
- [ ] Milestone: Simplistic editing of RAZZLE source on RAZZLE
- [ ] Virtual memory
- [ ] Audio driver
- [ ] Milestone: Listen to "Hey, St. Peter" by Flash and the Pan on RAZZLE
- [ ] Network driver
- [ ] Milestone: Simple HTTP server running on RAZZLE
- [ ] Higher-resolution graphics driver
- [ ] (Maybe) Milestone: Run [Anthracite](https://github.com/nickorlow/anthracite) unmodified on Razzle
- [ ] Multicore support
- [ ] x86_64
- [ ] aarch64

32
arch/i386/asm.c Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <stdint.h>
struct regs {
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
};
void __sl_acquire(uint32_t *lock_id) {
__asm__("retry_lock: lock bts $0,(%0); pause; jc retry_lock" : "+g"(lock_id));
}
void __sl_release(uint32_t *lock_id) {
__asm__("lock btr $0, (%0)" : "+g"(lock_id));
}
static inline void outb(int port, int val) {
__asm__ volatile("outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory");
}
static inline unsigned char inb(int port) {
unsigned char val;
__asm__ volatile("inb %w1, %b0" : "=a"(val) : "Nd"(port) : "memory");
return val;
}
static inline void interrupt_disable() { __asm__ volatile("cli"); }
static inline void interrupt_enable() { __asm__ volatile("sti"); }

121
arch/i386/gdt.c Normal file
View file

@ -0,0 +1,121 @@
#pragma once
#include "../../kernel/memory.c"
#include <stdint.h>
struct gdt_row_t {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity_limit_high;
uint8_t base_high;
} __attribute__((packed));
struct gdt_ptr_t {
uint16_t size;
uint32_t address;
} __attribute__((packed));
struct tss_row_t {
uint32_t prev_tss;
uint32_t esp_ring0;
uint32_t ss_ring0;
uint32_t padding[23]; // Extra options RAZZLE doesn't use
} __attribute__((packed));
enum gdt_access_t {
GDT_ACCESS_PRESENT = 0b10000000,
GDT_ACCESS_DPL_KERNEL = 0b00000000,
GDT_ACCESS_DPL_USER = 0b01100000,
GDT_ACCESS_CODEDATA = 0b00010000,
GDT_ACCESS_EXECUTABLE = 0b00001000,
GDT_ACCESS_GROW_DOWN = 0b00000100,
GDT_ACCESS_RW = 0b00000010,
GDT_ACCESS_ACCESSED = 0b00000001,
};
enum gdt_granularity_t {
GDT_GRANULARITY_4K = 0b10001111,
GDT_GRANULARITY_MODE_32BIT = 0b01001111,
};
struct tss_row_t tss_entry;
#define GDT_SIZE (6)
struct gdt_row_t gdt[GDT_SIZE];
void load_gdt(struct gdt_ptr_t *gp) {
asm volatile("lgdt (%0)\n\t"
"mov $0x10, %%ax\n\t"
"mov %%ax, %%ds\n\t"
"mov %%ax, %%es\n\t"
"mov %%ax, %%fs\n\t"
"mov %%ax, %%gs\n\t"
"mov %%ax, %%ss\n\t"
:
: "r"(gp)
: "%ax");
}
void set_gdt_row(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
uint8_t granularity) {
gdt[num].base_low = base & 0xFFFF;
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
gdt[num].limit_low = limit & 0xFFFF;
gdt[num].granularity_limit_high = (limit >> 16) & 0x0F;
gdt[num].granularity_limit_high |= granularity & 0xF0;
gdt[num].access = access;
}
void load_tss(uint16_t gdt_row_num) {
gdt_row_num *= 8;
__asm__ volatile("mov %0, %%ax; ltr %%ax" : : "r"(gdt_row_num) : "ax");
}
#define KERNEL_CODE_SEL (0x08)
#define KERNEL_DATA_SEL (0x10)
void init_gdt() {
struct gdt_ptr_t gp;
gp.size = (sizeof(struct gdt_row_t) * GDT_SIZE) - 1;
gp.address = (uint32_t)&gdt;
set_gdt_row(0, 0, 0, 0, 0);
// Kernelmode code/data degments
set_gdt_row(1, 0, 0xFFFFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_KERNEL | GDT_ACCESS_CODEDATA |
GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
set_gdt_row(2, 0, 0xFFFFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_KERNEL | GDT_ACCESS_CODEDATA |
GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
// Usermode code/data segments
set_gdt_row(3, 0x0000000, 0xFFFFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_USER | GDT_ACCESS_CODEDATA |
GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
set_gdt_row(4, 0x0000000, 0xFFFFFFFF,
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_USER | GDT_ACCESS_CODEDATA |
GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
// TSS row
set_gdt_row(5, (uint32_t)&tss_entry, sizeof(tss_entry),
GDT_ACCESS_PRESENT | GDT_ACCESS_EXECUTABLE | GDT_ACCESS_ACCESSED,
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
// Setup TSS
int kstack = 0;
memset((char *)&tss_entry, 0, sizeof(tss_entry));
tss_entry.ss_ring0 = 0x10;
tss_entry.esp_ring0 = (uint32_t)&kstack;
// Load GDT and TSS
load_gdt(&gp);
load_tss(5);
}

52
arch/i386/handlers.h Normal file
View file

@ -0,0 +1,52 @@
#pragma once
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
extern void irq128();
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();

86
arch/i386/idt.c Normal file
View file

@ -0,0 +1,86 @@
#pragma once
#include "../../kernel/memory.c"
#include "./handlers.h"
#include "gdt.c"
struct idt_row_t {
uint16_t base_lo;
uint16_t sel;
uint8_t unset;
uint8_t flags;
uint16_t base_hi;
} __attribute__((packed));
struct idt_ptr_t {
uint16_t size;
uint32_t address;
} __attribute__((packed));
// TODO: double check this?
enum idt_flag_t {
IDTFLAG_PRESENT = 0b10000000,
IDTFLAG_DPL_KERNEL = 0b00000000,
IDTFLAG_DPL_USER = 0b01100000,
IDTFLAG_TRAP = 0b00001111,
IDTFLAG_INTERRUPT = 0b00001110,
};
#define KERNEL_INTERRUPT_FLAG (IDTFLAG_PRESENT | IDTFLAG_DPL_KERNEL | IDTFLAG_INTERRUPT)
#define USER_TRAP_FLAG (IDTFLAG_PRESENT | IDTFLAG_DPL_USER | IDTFLAG_INTERRUPT)
#define IDT_SIZE (256)
struct idt_row_t idt[IDT_SIZE];
struct idt_ptr_t idtp;
void load_idt(struct idt_ptr_t *pt) { asm volatile("lidt (%0)" ::"r"(pt)); }
void set_idt_row(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
idt[num].base_hi = (base >> 16) & 0x0000FFFF;
idt[num].base_lo = base & 0x0000FFFF;
idt[num].sel = sel;
idt[num].flags = flags;
idt[num].unset = 0;
}
void init_idt() {
idtp.size = (sizeof(struct idt_row_t) * IDT_SIZE) - 1;
idtp.address = (uint32_t)&idt;
memset((char *)&idt, 0, sizeof(struct idt_row_t) * IDT_SIZE);
set_idt_row(0, (uint32_t)isr0, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(1, (uint32_t)isr1, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(2, (uint32_t)isr2, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(3, (uint32_t)isr3, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(4, (uint32_t)isr4, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(5, (uint32_t)isr5, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(6, (uint32_t)isr6, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(7, (uint32_t)isr7, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(8, (uint32_t)isr8, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(9, (uint32_t)isr9, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(10, (uint32_t)isr10, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(11, (uint32_t)isr11, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(12, (uint32_t)isr12, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(13, (uint32_t)isr13, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(14, (uint32_t)isr14, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(15, (uint32_t)isr15, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(16, (uint32_t)isr16, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(17, (uint32_t)isr17, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(18, (uint32_t)isr18, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(19, (uint32_t)isr19, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(20, (uint32_t)isr20, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(21, (uint32_t)isr21, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(22, (uint32_t)isr22, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(23, (uint32_t)isr23, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(24, (uint32_t)isr24, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(25, (uint32_t)isr25, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(26, (uint32_t)isr26, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(27, (uint32_t)isr27, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(28, (uint32_t)isr28, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(29, (uint32_t)isr29, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(30, (uint32_t)isr30, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(31, (uint32_t)isr31, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
load_idt(&idtp);
}

11
arch/i386/init.c Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "./gdt.c"
#include "./idt.c"
#include "./irq.c"
void arch_init() {
init_gdt();
init_idt();
init_irq();
}

81
arch/i386/irq.c Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include "../../kernel/ps2.c"
#include "../../kernel/syscall.c"
#include "./asm.c"
#include "./idt.c"
#include "handlers.h"
enum irq_code_t {
IRQCODE_PIT = 32,
IRQCODE_PS2 = 33,
IRQCODE_SYSCALL = 128,
};
void kb_handler() {
uint8_t char_code = inb(0x60);
handle_keypress(char_code);
}
void remap_irq(void) {
outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
}
void init_irq() {
remap_irq();
set_idt_row(32, (uint32_t)irq0, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(33, (uint32_t)irq1, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(34, (uint32_t)irq2, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(35, (uint32_t)irq3, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(36, (uint32_t)irq4, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(37, (uint32_t)irq5, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(38, (uint32_t)irq6, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(39, (uint32_t)irq7, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(40, (uint32_t)irq8, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(41, (uint32_t)irq9, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(42, (uint32_t)irq10, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(43, (uint32_t)irq11, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(44, (uint32_t)irq12, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(45, (uint32_t)irq13, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(46, (uint32_t)irq14, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(47, (uint32_t)irq15, KERNEL_CODE_SEL, KERNEL_INTERRUPT_FLAG);
set_idt_row(128, (uint32_t)irq128, KERNEL_CODE_SEL, USER_TRAP_FLAG);
}
void irq_handler(struct regs *r) {
switch (r->int_no) {
case IRQCODE_SYSCALL: {
syscall(r);
break;
};
case IRQCODE_PIT: {
schedule(r);
break;
};
case IRQCODE_PS2: {
kb_handler();
break;
};
}
// Send EOI to follower controller
if (r->int_no >= 40 && r->int_no < 48) {
outb(0xA0, 0x20);
}
// Send EOI to leader controller
outb(0x20, 0x20);
}

143
arch/i386/irq.s Normal file
View file

@ -0,0 +1,143 @@
.global irq0
.global irq1
.global irq2
.global irq3
.global irq4
.global irq5
.global irq6
.global irq7
.global irq8
.global irq9
.global irq10
.global irq11
.global irq12
.global irq13
.global irq14
.global irq15
.global irq128
irq0:
cli
push $0
push $32
jmp irq_handle
irq1:
cli
push $1
push $33
jmp irq_handle
irq2:
cli
push $2
push $34
jmp irq_handle
irq3:
cli
push $3
push $35
jmp irq_handle
irq4:
cli
push $4
push $36
jmp irq_handle
irq5:
cli
push $5
push $37
jmp irq_handle
irq6:
cli
push $6
push $38
jmp irq_handle
irq7:
cli
push $7
push $39
jmp irq_handle
irq8:
cli
push $8
push $40
jmp irq_handle
irq9:
cli
push $9
push $41
jmp irq_handle
irq10:
cli
push $10
push $42
jmp irq_handle
irq11:
cli
push $11
push $43
jmp irq_handle
irq12:
cli
push $12
push $44
jmp irq_handle
irq13:
cli
push $13
push $45
jmp irq_handle
irq14:
cli
push $14
push $46
jmp irq_handle
irq15:
cli
push $15
push $47
jmp irq_handle
irq128:
cli
push $0x80
push $0x80
jmp irq_handle
irq_handle:
pusha
push %ds
push %es
push %fs
push %gs
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
movl %esp, %eax
push %eax
movl $irq_handler, %eax
call *%eax
pop %eax
pop %gs
pop %fs
pop %es
pop %ds
popal
addl $8, %esp
iret

243
arch/i386/isr.s Normal file
View file

@ -0,0 +1,243 @@
.global isr0
.global isr1
.global isr2
.global isr3
.global isr4
.global isr5
.global isr6
.global isr7
.global isr8
.global isr9
.global isr10
.global isr11
.global isr12
.global isr13
.global isr14
.global isr15
.global isr16
.global isr17
.global isr18
.global isr19
.global isr20
.global isr21
.global isr22
.global isr23
.global isr24
.global isr25
.global isr26
.global isr27
.global isr28
.global isr29
.global isr30
.global isr31
isr0:
cli
push $0
push $0
jmp isr_handle
isr1:
cli
push $0
push $1
jmp isr_handle
isr2:
cli
push $0
push $2
jmp isr_handle
isr3:
cli
push $0
push $3
jmp isr_handle
isr4:
cli
push $0
push $4
jmp isr_handle
isr5:
cli
push $0
push $5
jmp isr_handle
isr6:
cli
push $0
push $6
jmp isr_handle
isr7:
cli
push $0
push $7
jmp isr_handle
isr8:
cli
push $0
push $8
jmp isr_handle
isr9:
cli
push $0
push $9
jmp isr_handle
isr10:
cli
push $10
jmp isr_handle
isr11:
cli
push $11
jmp isr_handle
isr12:
cli
push $12
jmp isr_handle
isr13:
cli
push $13
jmp isr_handle
isr14:
cli
push $14
jmp isr_handle
isr15:
cli
push $0
push $15
jmp isr_handle
isr16:
cli
push $0
push $16
jmp isr_handle
isr17:
cli
push $0
push $17
jmp isr_handle
isr18:
cli
push $0
push $18
jmp isr_handle
isr19:
cli
push $0
push $19
jmp isr_handle
isr20:
cli
push $0
push $20
jmp isr_handle
isr21:
cli
push $0
push $21
jmp isr_handle
isr22:
cli
push $0
push $22
jmp isr_handle
isr23:
cli
push $0
push $23
jmp isr_handle
isr24:
cli
push $0
push $24
jmp isr_handle
isr25:
cli
push $0
push $25
jmp isr_handle
isr26:
cli
push $0
push $26
jmp isr_handle
isr27:
cli
push $0
push $27
jmp isr_handle
isr28:
cli
push $0
push $28
jmp isr_handle
isr29:
cli
push $0
push $29
jmp isr_handle
isr30:
cli
push $0
push $30
jmp isr_handle
isr31:
cli
push $0
push $31
jmp isr_handle
isr_handle:
pushal
push %ds
push %es
push %fs
push %gs
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
movl %esp, %eax
push %eax
movl $fault_handler, %eax
call *%eax
pop %eax
pop %gs
pop %fs
pop %es
pop %ds
popal
addl $8, %esp
iret

26
arch/i386/loader.s Normal file
View file

@ -0,0 +1,26 @@
.set ALIGN, 1<<0
.set MEMINFO, 1<<1
.set FLAGS, ALIGN | MEMINFO
.set MAGIC, 0x1BADB002
.set CHECKSUM, -(MAGIC + FLAGS)
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 16384
stack_top:
.section .text
.global _start
.type _start, @function
_start:
mov $stack_top, %esp
call kernel_main
.size _start, . - _start

66
arch/i386/scheduler.c Normal file
View file

@ -0,0 +1,66 @@
#pragma once
#include "asm.c"
enum eflags_t {
EFLAG_CARRY = 0x0001,
EFLAG_RES = 0x0002,
EFLAG_PARITY = 0x0004,
EFLAG_INTERRUPT = 0x0200
};
void initialize_registers(struct regs *new_regs, char *entrypoint,
uint32_t address_base, uint32_t address_space_size) {
new_regs->eip = (unsigned int)entrypoint;
new_regs->edi = 0;
new_regs->esi = 0;
new_regs->ebx = 0;
new_regs->edx = 0;
new_regs->ecx = 0;
new_regs->eax = 0;
new_regs->eflags = EFLAG_INTERRUPT;
new_regs->useresp = (unsigned int)address_base + address_space_size - 1;
new_regs->ebp = new_regs->useresp;
new_regs->ds = 35;
new_regs->es = 35;
new_regs->fs = 35;
new_regs->gs = 35;
new_regs->ss = 27;
}
void store_registers(struct regs *machine_regs, struct regs *current_regs) {
current_regs->edi = machine_regs->edi;
current_regs->esi = machine_regs->esi;
current_regs->ebx = machine_regs->ebx;
current_regs->edx = machine_regs->edx;
current_regs->ecx = machine_regs->ecx;
current_regs->eax = machine_regs->eax;
current_regs->eip = machine_regs->eip;
current_regs->eflags = machine_regs->eflags;
current_regs->useresp = machine_regs->useresp;
current_regs->ebp = machine_regs->ebp;
}
void switch_context(struct regs *machine_regs, struct regs *new_regs) {
machine_regs->edi = new_regs->edi;
machine_regs->esi = new_regs->esi;
machine_regs->ebx = new_regs->ebx;
machine_regs->edx = new_regs->edx;
machine_regs->ecx = new_regs->ecx;
machine_regs->eax = new_regs->eax;
machine_regs->eip = new_regs->eip;
machine_regs->eflags = new_regs->eflags;
machine_regs->esp = machine_regs->esp;
machine_regs->useresp = new_regs->useresp;
machine_regs->ebp = new_regs->ebp;
machine_regs->ds = 35;
machine_regs->es = 35;
machine_regs->fs = 35;
machine_regs->gs = 35;
machine_regs->ss = 35;
machine_regs->cs = 27;
}

8
arch/i386/syscall.c Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#define INVOKE_SYSCALL(syscall_num) \
__asm__ volatile("movl %0, %%eax;" \
"int $0x80;" \
: \
: "r"(syscall_num) \
: "%eax")

7
clang-format Normal file
View file

@ -0,0 +1,7 @@
---
BasedOnStyle: LLVM
AlignAfterOpenBracket: Align
AlignConsecutiveDeclarations: 'true'
AlignTrailingComments: 'true'
...

38
compile_commands.json Normal file
View file

@ -0,0 +1,38 @@
[
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-gcc -ffreestanding -g -Wall -Wextra -mgeneral-regs-only -DARCH_I386 -std=gnu99 -o CMakeFiles/kernel.elf.dir/kernel/kernel.c.o -c /home/nickorlow/programming/personal/razzle/kernel/kernel.c",
"file": "/home/nickorlow/programming/personal/razzle/kernel/kernel.c",
"output": "CMakeFiles/kernel.elf.dir/kernel/kernel.c.o"
},
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-as -g -o CMakeFiles/kernel.elf.dir/arch/i386/idt.s.o -c /home/nickorlow/programming/personal/razzle/arch/i386/idt.s",
"file": "/home/nickorlow/programming/personal/razzle/arch/i386/idt.s",
"output": "CMakeFiles/kernel.elf.dir/arch/i386/idt.s.o"
},
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-as -g -o CMakeFiles/kernel.elf.dir/arch/i386/irq.s.o -c /home/nickorlow/programming/personal/razzle/arch/i386/irq.s",
"file": "/home/nickorlow/programming/personal/razzle/arch/i386/irq.s",
"output": "CMakeFiles/kernel.elf.dir/arch/i386/irq.s.o"
},
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-as -g -o CMakeFiles/kernel.elf.dir/arch/i386/isr.s.o -c /home/nickorlow/programming/personal/razzle/arch/i386/isr.s",
"file": "/home/nickorlow/programming/personal/razzle/arch/i386/isr.s",
"output": "CMakeFiles/kernel.elf.dir/arch/i386/isr.s.o"
},
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-as -g -o CMakeFiles/kernel.elf.dir/arch/i386/loader.s.o -c /home/nickorlow/programming/personal/razzle/arch/i386/loader.s",
"file": "/home/nickorlow/programming/personal/razzle/arch/i386/loader.s",
"output": "CMakeFiles/kernel.elf.dir/arch/i386/loader.s.o"
},
{
"directory": "/home/nickorlow/programming/personal/razzle/build",
"command": "i386-elf-as -g -o CMakeFiles/kernel.elf.dir/arch/i386/tss.s.o -c /home/nickorlow/programming/personal/razzle/arch/i386/tss.s",
"file": "/home/nickorlow/programming/personal/razzle/arch/i386/tss.s",
"output": "CMakeFiles/kernel.elf.dir/arch/i386/tss.s.o"
}
]

8
debug.sh Executable file
View file

@ -0,0 +1,8 @@
tmux new-window
tmux send 'qemu-system-i386 -boot d -cdrom os.iso -m 512 -machine type=pc-i440fx-3.1 -monitor stdio -s -S' ENTER
tmux split-window -h
tmux send 'gdb kernel.elf' ENTER
tmux send 'target remote localhost:1234' ENTER
tmux send 'layout split' ENTER
#vncviewer 127.0.0.1:5900 -Scaling=100%
#killall qemu-system-i386

5
iso/boot/grub/menu.lst Normal file
View file

@ -0,0 +1,5 @@
default=0
timeout=0
title RAZZLE
kernel /boot/kernel.elf

Binary file not shown.

74
kernel/kernel.c Normal file
View file

@ -0,0 +1,74 @@
#include "./scheduler.c"
#include "./vga.c"
#include <stdint.h>
#include "./test_processes.c"
#ifdef ARCH_I386
#include "../arch/i386/init.c"
#endif
int kernel_main() {
lock = 0;
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
clear_screen();
interrupt_disable();
arch_init();
init_process_table();
start_process("razzle", (char *) &test_razzle);
start_process("dazzle", (char *) &test_dazzle);
interrupt_enable();
for (;;) {
}
}
void fault_handler(struct regs *r) {
clear_screen();
printf("!!! Kernel Panic !!!\n");
switch (r->int_no) {
case 0: {
printf("Error: Divide by Zero\n");
break;
};
case 6: {
printf("Error: Illegal instruction\n");
break;
};
case 8: {
printf("Error: Double Fault (Ignoring)\n");
break;
};
case 13: {
printf("Error: General Protection Fault at\n");
break;
};
default: {
printf("Error: Unknown (no: %d)\n", r->int_no);
break;
};
}
printf("EIP: %x\n", r->eip);
printf("ESPv: %x\n", *(((unsigned int *)r->esp) + 2));
printf("ESP : %x\n", r->esp);
printf("\n");
process_debug();
for (;;) {
}
}

24
kernel/memory.c Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
void memset(char *ptr, char data, uint32_t len) {
for (uint32_t i = 0; i < len; i++) {
ptr[i] = data;
}
}
void memcpy(char *src, char *dst, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
dst[i] = src[i];
}
}
void strncpy(char *src, char *dst, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
dst[i] = src[i];
if (src[i] == '\0') {
return;
}
}
}

302
kernel/ps2.c Normal file
View file

@ -0,0 +1,302 @@
#pragma once
#include "./scheduler.c"
#include "./vga.c"
#include <stdint.h>
enum key_code_t {
backtick_tilde = 1,
one_bang = 2,
two_at = 3,
three_crunch = 4,
four_dollar = 5,
five_percent = 6,
six_carat = 7,
seven_amp = 8,
eight_star = 9,
nine_lparen = 10,
zero_rparen = 11,
minus_underscore = 12,
equal_plus = 13,
backspace = 14,
tab = 15,
lbracket_lbrace = 26,
rbracket_rbrace = 27,
backslash_pipe = 43,
caps_lock = 58,
semicolon_colon = 39,
quote_dquote = 40,
a = 30,
b = 48,
c = 46,
d = 32,
e = 18,
f = 33,
g = 34,
h = 35,
i = 23,
j = 36,
k = 37,
l = 38,
m = 50,
n = 49,
o = 24,
p = 25,
q = 16,
r = 19,
s = 31,
t = 20,
u = 22,
v = 47,
w = 17,
x = 45,
y = 21,
z = 44,
space = 57,
l_shift = 42,
r_shift = 54,
period_rarr = 52,
enter = 28,
comma_larr = 51,
slash_question = 53
};
struct key_event_t {
enum key_code_t key;
uint8_t is_down;
};
struct kb_state {
uint8_t l_shift;
uint8_t r_shift;
uint8_t l_ctrl;
uint8_t r_ctrl;
uint8_t caps;
};
static struct kb_state kstate;
uint8_t is_shifted() { return kstate.caps | kstate.r_shift | kstate.l_shift; }
char keycode_to_char(enum key_code_t key_code) {
switch (key_code) {
case a:
return is_shifted() ? 'A' : 'a';
break;
case b:
return is_shifted() ? 'B' : 'b';
break;
case c:
return is_shifted() ? 'C' : 'c';
break;
case d:
return is_shifted() ? 'D' : 'd';
break;
case e:
return is_shifted() ? 'E' : 'e';
break;
case f:
return is_shifted() ? 'F' : 'f';
break;
case g:
return is_shifted() ? 'G' : 'g';
break;
case h:
return is_shifted() ? 'H' : 'h';
break;
case i:
return is_shifted() ? 'I' : 'i';
break;
case j:
return is_shifted() ? 'J' : 'j';
break;
case k:
return is_shifted() ? 'K' : 'k';
break;
case l:
return is_shifted() ? 'L' : 'l';
break;
case m:
return is_shifted() ? 'M' : 'm';
break;
case n:
return is_shifted() ? 'N' : 'n';
break;
case o:
return is_shifted() ? 'O' : 'o';
break;
case p:
return is_shifted() ? 'P' : 'p';
break;
case q:
return is_shifted() ? 'Q' : 'q';
break;
case r:
return is_shifted() ? 'R' : 'r';
break;
case s:
return is_shifted() ? 'S' : 's';
break;
case t:
return is_shifted() ? 'T' : 't';
break;
case u:
return is_shifted() ? 'U' : 'u';
break;
case v:
return is_shifted() ? 'V' : 'v';
break;
case w:
return is_shifted() ? 'W' : 'w';
break;
case x:
return is_shifted() ? 'X' : 'x';
break;
case y:
return is_shifted() ? 'Y' : 'y';
break;
case z:
return is_shifted() ? 'Z' : 'z';
break;
case space:
return ' ';
break;
case comma_larr:
return is_shifted() ? '<' : ',';
break;
case period_rarr:
return is_shifted() ? '>' : '.';
break;
case enter:
return '\n';
break;
case backspace:
return '\b';
break;
case backtick_tilde:
return is_shifted() ? '~' : '`';
break;
case one_bang:
return is_shifted() ? '!' : '1';
break;
case two_at:
return is_shifted() ? '@' : '2';
break;
case three_crunch:
return is_shifted() ? '#' : '3';
break;
case four_dollar:
return is_shifted() ? '$' : '4';
break;
case five_percent:
return is_shifted() ? '%' : '5';
break;
case six_carat:
return is_shifted() ? '^' : '6';
break;
case seven_amp:
return is_shifted() ? '&' : '7';
break;
case eight_star:
return is_shifted() ? '*' : '8';
break;
case nine_lparen:
return is_shifted() ? '(' : '9';
break;
case zero_rparen:
return is_shifted() ? ')' : '0';
break;
case minus_underscore:
return is_shifted() ? '_' : '-';
break;
case equal_plus:
return is_shifted() ? '+' : '=';
break;
case tab:
return '\t';
break;
case lbracket_lbrace:
return is_shifted() ? '{' : '[';
break;
case rbracket_rbrace:
return is_shifted() ? '}' : ']';
break;
case semicolon_colon:
return is_shifted() ? ':' : ';';
break;
case quote_dquote:
return is_shifted() ? '"' : '\'';
break;
case backslash_pipe:
return is_shifted() ? '|' : '\\';
break;
case slash_question:
return is_shifted() ? '?' : '/';
break;
case caps_lock:
case r_shift:
case l_shift:
break;
// default:
// printf("%d", key_code);
// break;
}
return '\0';
}
struct ps2_waiter_t {
uint8_t alloc;
uint32_t pid;
};
struct ps2_waiter_t ps2_waiters[MAX_PROCESSES];
void init_ps2() {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
ps2_waiters[i].alloc = 0;
}
}
void handle_keypress(uint8_t char_code) {
struct key_event_t event;
if ((char_code & 0b11000000) == 0b10000000) {
event.is_down = 0;
event.key = char_code & 0b00111111;
} else {
event.is_down = 1;
event.key = char_code;
}
switch (event.key) {
case l_shift:
kstate.l_shift = event.is_down;
break;
case r_shift:
kstate.r_shift = event.is_down;
break;
case caps_lock:
if (event.is_down) {
kstate.caps = !kstate.caps;
}
break;
default: {
if (event.is_down) {
char c = keycode_to_char(event.key);
if (c != '\0') {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(ps2_waiters[i].alloc) {
process_table[ps2_waiters[i].pid].registers.eax = c;
ps2_waiters[i].alloc = 0;
process_table[ps2_waiters[i].pid].state = TASKSTATE_ready;
}
}
}
}
break;
}
}
}

95
kernel/scheduler.c Normal file
View file

@ -0,0 +1,95 @@
#pragma once
#ifdef ARCH_I386
#include "../arch/i386/scheduler.c"
#endif
#include "./memory.c"
#include "./vga.c"
#include <stdint.h>
#define ADDRESS_SPACE_SIZE 1000000
#define MAX_PROCESSES 128
enum task_state_t { TASKSTATE_unused, TASKSTATE_ready, TASKSTATE_blocked };
struct task_struct {
enum task_state_t state;
struct regs registers;
unsigned int address_base;
char *allocd_addr;
char *process_name;
};
static struct task_struct process_table[MAX_PROCESSES];
static uint32_t current_pid;
void init_process_table() {
for (uint32_t i = 0; i < MAX_PROCESSES; i++) {
process_table[i].state = TASKSTATE_unused;
}
current_pid = 129;
}
uint32_t get_next_pid(uint32_t start, enum task_state_t state) {
uint32_t i = start % MAX_PROCESSES;
for (; process_table[i].state != state; i = (i + 1) % MAX_PROCESSES) {
}
return i;
}
char *balloc_pid(uint32_t size, uint32_t pid) {
char *addr = process_table[pid].allocd_addr;
process_table[pid].allocd_addr += size;
return addr;
}
char *balloc(uint32_t size) { return balloc_pid(size, current_pid); }
void start_process(char *name, char *entrypoint) {
uint32_t pid = get_next_pid(0, TASKSTATE_unused);
process_table[pid].address_base =
(unsigned int)(ADDRESS_SPACE_SIZE * (pid + 6));
// TODO: Copy code into process' address space
// memcpy(entrypoint, (char*) process_table[pid].address_base, 500000);
// entrypoint = (char*) process_table[pid].address_base;
process_table[pid].allocd_addr = (char *)process_table[pid].address_base;
process_table[pid].state = TASKSTATE_ready;
process_table[pid].process_name = balloc_pid(16, pid);
strncpy(name, process_table[pid].process_name, 16);
initialize_registers(&process_table[pid].registers, entrypoint,
process_table[pid].address_base, ADDRESS_SPACE_SIZE);
}
void single_process_debug(uint32_t pid) {
struct task_struct proc = process_table[pid];
printf_nolock("pid: %u (%s)\n", pid, proc.process_name);
printf_nolock("eip: %x esp: %x (%d)\n", proc.registers.eip,
proc.registers.useresp, proc.registers.useresp);
printf_nolock("ass: %d ase: %d\n\n", proc.address_base, proc.registers.ebp);
}
void process_debug() {
printf_nolock("RAZZLE Debugger: Process Table | current pid: %u\n",
current_pid);
for (int i = 0; i < MAX_PROCESSES; i++) {
if (process_table[i].state != TASKSTATE_unused)
single_process_debug(i);
}
}
void schedule(struct regs *r) {
if (current_pid < MAX_PROCESSES) {
store_registers(r, &process_table[current_pid].registers);
}
current_pid =
get_next_pid((current_pid + 1) % MAX_PROCESSES, TASKSTATE_ready);
switch_context(r, &process_table[current_pid].registers);
}

9
kernel/spin_lock.c Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#ifdef ARCH_I386
#include "../arch/i386/asm.c"
#endif
void sl_acquire(uint32_t *lock) { __sl_acquire(lock); }
void sl_release(uint32_t *lock) { __sl_release(lock); }

64
kernel/syscall.c Normal file
View file

@ -0,0 +1,64 @@
#pragma once
#include "scheduler.c"
#include "ps2.c"
#ifdef ARCH_I386
#include "../arch/i386/syscall.c"
#endif
enum syscall_type_d { SYSCALL_yield, SYSCALL_getc, SYSCALL_exit };
void yield() { INVOKE_SYSCALL(SYSCALL_yield); }
char getc() {
INVOKE_SYSCALL(SYSCALL_getc);
char result;
__asm__ volatile (
"movb %%al, %0"
: "=r"(result)
);
return result;
}
void __syscall_yield(struct regs *r) {
// for now, just reschedule
// TODO: reset PIT timer so
// next process doesn't get an
// unreasonably small quantum
schedule(r);
}
void syscall(struct regs *r) {
int syscall_no = r->eax;
switch (syscall_no) {
case SYSCALL_yield: {
__syscall_yield(r);
break;
};
case SYSCALL_getc: {
process_table[current_pid].state = TASKSTATE_blocked;
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(!ps2_waiters[i].alloc) {
ps2_waiters[i].alloc = 1;
ps2_waiters[i].pid = current_pid;
break;
}
}
__syscall_yield(r);
break;
};
case SYSCALL_exit: {
process_table[current_pid].state = TASKSTATE_unused;
__syscall_yield(r);
break;
};
}
}

96
kernel/test_processes.c Normal file
View file

@ -0,0 +1,96 @@
/*
* Since RAZZLE doesn't have disk support yet, all code for test processes are
* included in this file.
*/
#pragma once
#include "./scheduler.c"
#include "./spin_lock.c"
#include "./syscall.c"
#include "./vga.c"
uint32_t lock2 = 0;
void test_razzle() {
for (uint32_t i = 0;; i++) {
sl_acquire(&lock2);
row = 1;
col = 0;
printf("%s (pid %d): %u \n", process_table[current_pid].process_name,
current_pid, i);
sl_release(&lock2);
yield();
}
}
void cpuid() {
char model[13];
uint32_t res[3];
__asm__ volatile ("mov $0, %%eax; cpuid; mov %%ebx, %0; mov %%edx, %1; mov %%ecx, %2;" : "=r" (res[0]), "=r" (res[1]), "=r" (res[2]) ::"ebx", "ecx", "edx");
for(uint32_t i = 0; i < 3; i++) {
model[(i*4) + 0] = (res[i] >> 0) & 0xFF;
model[(i*4) + 1] = (res[i] >> 8) & 0xFF;
model[(i*4) + 2] = (res[i] >> 16) & 0xFF;
model[(i*4) + 3] = (res[i] >> 24) & 0xFF;
}
model[12] = '\0';
printf("%s", model);
}
void test_dazzle() {
char prompt[] = "you@razzle ~$";
char command[2048];
uint32_t cr = 2;
printf("%s", prompt);
for (uint32_t i = sizeof(prompt);;) {
char c = getc();
sl_acquire(&lock2);
row = cr;
col = i;
switch(c) {
case '\b':
if (i == 0) {
i = 79;
cr--;
} else {
i--;
}
col = i;
row = cr;
printf(" ");
break;
case '\n':
i = 0;
cr++;
row++;
col = 0;
cpuid();
cr++;
col = i;
row = cr;
printf("%s", prompt);
i = sizeof(prompt);
break;
default:
printf("%c", c);
command[((cr-2)*80) + i] = c;
i++;
break;
}
if (i >= 80) {
i = 0;
cr++;
}
sl_release(&lock2);
yield();
}
}

157
kernel/vga.c Normal file
View file

@ -0,0 +1,157 @@
#pragma once
#include "./spin_lock.c"
#include <stdarg.h>
#include <stdint.h>
#define WIDTH 80
#define HEIGHT 25
static uint8_t col = 0;
static uint8_t row = 0;
static uint8_t color_code = 10;
static char *vram = (char *)0xb8000;
void clear_screen() {
for (int i = 0; i < HEIGHT - 1; i++) {
for (int j = 0; j < WIDTH; j++) {
vram[(i * WIDTH * 2) + (j * 2)] = 0;
// vram[(i * WIDTH * 2) + (j*2 + 1)] = 0;
}
}
row = 0;
col = 0;
}
void putc(char c) {
if (col == WIDTH) {
row = (row + 1) % HEIGHT;
col = 0;
}
if (c == '\n') {
for (int i = col; i < WIDTH; i++) {
vram[(row * WIDTH * 2) + (i * 2)] = ' ';
vram[(row * WIDTH * 2) + (i * 2 + 1)] = color_code;
}
row = (row + 1) % HEIGHT;
col = 0;
return;
}
if (c == '\b') {
col--;
vram[(row * WIDTH * 2) + (col * 2)] = ' ';
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
return;
}
vram[(row * WIDTH * 2) + (col * 2)] = c;
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
col++;
}
void print_uint(unsigned int x, uint8_t base) {
if (x == 0) {
if (base)
putc('0');
return;
}
print_uint(x / 10, 0);
putc('0' + (x % 10));
}
void print_int(int x, uint8_t base) {
if (x == 0) {
if (base)
putc('0');
return;
}
if (x < 0) {
putc('-');
print_int(-1 * (x / 10), 0);
putc('0' + (x % 10));
} else {
print_int(x / 10, 0);
putc('0' + (x % 10));
}
}
void print_hex(int x) {
putc('0');
putc('x');
do {
unsigned int digit = (x & 0xF0000000) >> 28;
putc((digit < 10) ? (digit + '0') : (digit - 10 + 'A'));
x <<= 4;
} while (x != 0);
}
void print_string(char *s) {
for (uint32_t i = 0; s[i] != '\0'; i++) {
putc(s[i]);
}
}
uint32_t lock;
void printf_base(char *str, va_list list) {
for (uint32_t i = 0; str[i] != '\0'; i++) {
if (str[i] == '%') {
switch (str[i + 1]) {
case '\0':
return;
case '%': {
putc('%');
break;
}
case 'c': {
putc(va_arg(list, int));
break;
}
case 'd': {
print_int(va_arg(list, int), 1);
break;
}
case 'x': {
print_hex(va_arg(list, int));
break;
}
case 'u': {
print_uint(va_arg(list, unsigned int), 1);
break;
}
case 's': {
print_string(va_arg(list, char *));
break;
}
}
i++;
} else {
putc(str[i]);
}
}
}
void printf_nolock(char *str, ...) {
va_list list;
va_start(list, str);
printf_base(str, list);
}
void printf(char *str, ...) {
va_list list;
va_start(list, str);
sl_acquire(&lock);
printf_base(str, list);
sl_release(&lock);
}

28
linker.ld Normal file
View file

@ -0,0 +1,28 @@
ENTRY(_start)
SECTIONS
{
. = 2M;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}