Moving components modules to a more proper directory

This commit is contained in:
2023-03-30 22:40:08 -07:00
parent 044d5a75b5
commit cc1bb63e27
26 changed files with 11 additions and 148 deletions

View File

@@ -0,0 +1,48 @@
// Driver implementation for Jank's text frame buffer
// Buffer can display 80 columns by 25 Rows
// Start of buffer is at (real)address 0x000B8000
// Memory at this section is divided into 16-bit cells
// | 15-8 | 7-4 | 0-3
// | Asci | FG | BG
#include "types.h"
#include "framebuffer.h"
// State trackers from header
static u8* Frame_Buffer = (u8*)FRAME_BUFFER_ADDR;
s32 Frame_Buffer_Cursor = 0x0000;
void frame_buffer_newline() {
while(Frame_Buffer_Cursor != (AREA*8)) {
if((Frame_Buffer_Cursor % 160) == 0) {
break;
Frame_Buffer_Cursor+=160;
}
else {
Frame_Buffer_Cursor+=2;
}
}
}
// Writes character to a given cell in the framebuffer
// @cell parameter is the logical (linear)index into the buffer
void write_cell_fb(u8 c, u8 fg, u8 bg) {
Frame_Buffer[Frame_Buffer_Cursor] = c;
Frame_Buffer[Frame_Buffer_Cursor+1] = (fg & 0x0f << 4) | (bg & 0x0f);
Frame_Buffer_Cursor += 2;
}
void clear_fb(void) {
for(unsigned cell=0;cell<AREA; cell+=2) {
write_cell_fb(' ', 0x00, 0x00);
}
Frame_Buffer_Cursor = 0x0000;
}
// Takes the linear indexed position to move the cursos, if there is nothing at that position we should still have something there
void fb_move_cursor(u16 position) {
serialport_write_byte(FB_CMD, FB_HIGH_CMD);
serialport_write_byte(FB_DATA, ((position >> 8) & 0x00ff) );
serialport_write_byte(FB_CMD, FB_LOW_CMD);
serialport_write_byte(FB_DATA, position & 0x00ff);
}

View File

@@ -0,0 +1,52 @@
#include "types.h"
#include "serial.h"
#include "ports.h"
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#define COLUMNS 80
#define ROWS 25
#define AREA ( COLUMNS * ROWS )
// frame buffer port commansd
#define FB_CMD 0x3d4
#define FB_DATA 0x3d5
#define FB_HIGH_CMD 14
#define FB_LOW_CMD 15
// address of our frame buffer
#define FRAME_BUFFER_ADDR 0x000B8000
// Logical index of a cell in the frame buffer
#define FRAME_CELL(cell_) (cell_ * 2)
// Colors available in text framebuffer
#define Black 0x01
#define Blue 0x02
#define Green 0x03
#define Cyan 0x04
#define Red 0x05
#define Magenta 0x05
#define Brown 0x06
#define LightGrey 0x07
#define DarkGrey 0x08
#define LightBlue 0x09
#define LightGreen 0x0a
#define LightCyan 0x0b
#define LightRed 0x0c
#define LightMagenta 0x0d
#define LightBrown 0x0e
#define White 0x0f
extern s32 Frame_Buffer_Cursor;
void frame_buffer_newline();
void write_cell_fb(u8, u8, u8);
void clear_fb(void);
void fb_move_cursor(u16);
#endif

43
components/gdt/gdt.c Normal file
View File

@@ -0,0 +1,43 @@
#include "gdt.h"
// Congirures a given gdt entry base on the entry index given
void gdt_configure_entry(u32 entry, u32 base, u32 limit, u8 access, u8 gran) {
// base address
gdt_entries[entry].low_base = (base & 0xffff);
gdt_entries[entry].middle_base = (base >> 16) & 0xff;
gdt_entries[entry].high_base = (base >> 24) & 0xff;
// descriptor limits
gdt_entries[entry].low_limit = (limit & 0xffff);
gdt_entries[entry].granular = ((limit >> 16) & 0x0f);
gdt_entries[entry].granular |= (gran & 0xf0);
gdt_entries[entry].access = access;
}
// Configure the gdt pointer desribed in gdt.h as type GDT_PTR
void gdt_configure() {
// gdt_ptr configuration
gdt_ptr.size = (sizeof(struct GDT_Entry) * NO_GDT_ENTRIES) - 1;
// First entry is just the null descriptor and is left along overall
gdt_configure_entry(0, 0, 0, 0, 0);
// Second entry: code segment base adders
// Base address: 0
// limit: 4GB
// Granularity: 4KB
// 32-bit opcodes
// Code segment selector
gdt_configure_entry(1, 0, 0xffffffff, 0x9a, 0xcf); // code segment
// Finally the data segment
// All the same except the desriptor type specifies that its data
gdt_configure_entry(2, 0, 0xffffffff, 0x92, 0xcf); // data segment
// user mode segments
gdt_configure_entry(3, 0, 0xffffffff, 0xfa, 0xcf);
gdt_configure_entry(4, 0, 0xffffffff, 0xf2, 0xcf);
// Load in the new changes to the gdt
load_gdt();
}

32
components/gdt/gdt.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef GDT_H
#define GDT_H
#include "types.h"
#define NO_GDT_ENTRIES 5
struct GDT_Entry {
u16 low_limit;
u16 low_base;
u8 middle_base;
u8 access;
u8 granular;
u8 high_base;
}__attribute__((packed));
// Contains the pointer to the first gdt entry as well as the size(of the whole table(?))
struct GDT_PTR {
u16 size;
u32 address;
}__attribute__((packed));
struct GDT_Entry gdt_entries[NO_GDT_ENTRIES];
struct GDT_PTR gdt_ptr;
// this func is actually taken care of in gdt_seg.s
extern void load_gdt();
void gdt_configure_entry(u32 entry, u32 base, u32 limit, u8 access, u8 gran);
void gdt_configure();
#endif

17
components/gdt/gdt_seg.s Normal file
View File

@@ -0,0 +1,17 @@
global load_gdt
extern gdt_ptr
load_gdt:
mov ax, 0x10 ; offset in the gdt to our data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:flush_cs ; far jump to the code segment
flush_cs:
lgdt [gdt_ptr]
ret

View File

@@ -0,0 +1,170 @@
; Dispatching to our interrupt handler code from assembly because some of this is
; enourmous pain in C
; Save the register state
; call the C handler
; executes iret(expects the stack to look like struct stack_state)
; If the interrupt we need to handle doesn't produce an error code then must provide a 0
; for consistency
extern interrupt_handler
extern cpu_reg_state
extern stack_state
extern idt_ptr
extern irq_handler
global load_idt
load_idt:
lidt [idt_ptr]
ret
%macro irq 2
global irq_handler_%1
irq_handler_%1:
push dword 0
push dword %2
jmp common_irq_handler
%endmacro
%macro no_err_handler 1
global no_err_handler_%1 ; defined in interrupts.h
no_err_handler_%1:
push dword 0
push dword %1
jmp common_int_handler
%endmacro
; deals with the intterrupts that do give us an error code
%macro err_code_handler 1
global err_code_handler_%1
err_code_handler_%1:
push dword %1
jmp common_int_handler
%endmacro
extern interrupt_handler ; external handler (interrupts.c)
common_int_handler:
; save thigns before do our C-call
pushad
;push eax ecx edx ebx
;push esp ebp esi edi
push ds
push es
push fs
push gs
; load the kernel segment descriptor
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp ; pushing the stack into the next call
push eax
mov eax, interrupt_handler
call eax ; preserve the eip register past this call
; segments
pop eax
pop gs
pop fs
pop es
pop ds
popad
add esp, 8
; special instruction which lets us jump back to code
; which was previously interrupted
iret
no_err_handler 0
no_err_handler 1
no_err_handler 2
no_err_handler 3
no_err_handler 4
no_err_handler 5
no_err_handler 6
no_err_handler 7
err_code_handler 8
no_err_handler 9
err_code_handler 10
err_code_handler 11
err_code_handler 12
err_code_handler 13
err_code_handler 14
no_err_handler 15
no_err_handler 16
no_err_handler 17
no_err_handler 18
no_err_handler 19
no_err_handler 20
no_err_handler 21
no_err_handler 22
no_err_handler 23
no_err_handler 24
no_err_handler 25
no_err_handler 26
no_err_handler 27
no_err_handler 28
no_err_handler 29
no_err_handler 30
no_err_handler 31
common_irq_handler:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push eax
mov eax, irq_handler
call eax
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
; Remapped IRQ's for the APIC
; starting from irq 0 -> 15 but remapped to 32 -> 47
irq 0, 32
irq 1, 33
irq 2, 34
irq 3, 35
irq 4, 36
irq 5, 37
irq 6, 38
irq 7, 39
irq 8, 40
irq 9, 41
irq 10, 42
irq 11, 43
irq 12, 44
irq 13, 45
irq 14, 46
irq 15, 47

View File

@@ -0,0 +1,217 @@
#include "stlio.h"
#include "interrupts.h"
#include "serial.h"
#include "mem.h"
#include "types.h"
#include "ports.h"
#include "pit.h"
#include "kbd.h"
const char* err_msg[] = {
"Divide by zero\n",
"Debug Exception\n",
"Non Maskable Interrupt Exception\n",
"Breakpoint Exception\n",
"Into Detected Overflow Exception\n",
"Out of Bounds Exception\n",
"Invalid Opcode Exception\n",
"No Coprocessor Exception\n",
"Double Fault Exception\n",
"Coprocessor Segment Overrun Exception\n",
"Bad TSS Exception\n",
"Segment Not Present Exception\n",
"Stack Fault Exception\n",
"General Protection Fault Exception\n",
"Page Fault Exception\n",
"Unknown Interrupt Exception\n",
"Coprocessor Fault Exception\n",
"Alignment Check Exception (486+)\n",
"Machine Check Exception (Pentium/586+)\n",
"Reserved Exceptions\n", /* for 19 - 31 */
};
extern void load_idt(); // found in interrupts_entry.s
extern void no_err_handler_0();
extern void no_err_handler_1();
extern void no_err_handler_2();
extern void no_err_handler_3();
extern void no_err_handler_4();
extern void no_err_handler_5();
extern void no_err_handler_6();
extern void no_err_handler_7();
extern void err_code_handler_8();
extern void no_err_handler_9();
extern void err_code_handler_10();
extern void err_code_handler_11();
extern void err_code_handler_12();
extern void err_code_handler_13();
extern void err_code_handler_14();
extern void no_err_handler_15();
extern void no_err_handler_16();
extern void no_err_handler_17();
extern void no_err_handler_18();
extern void no_err_handler_19();
extern void no_err_handler_20();
extern void no_err_handler_21();
extern void no_err_handler_22();
extern void no_err_handler_23();
extern void no_err_handler_24();
extern void no_err_handler_25();
extern void no_err_handler_26();
extern void no_err_handler_27();
extern void no_err_handler_28();
extern void no_err_handler_29();
extern void no_err_handler_30();
extern void no_err_handler_31();
// Remapped IRQ's
extern void irq_handler_0();
extern void irq_handler_1();
extern void irq_handler_2();
extern void irq_handler_3();
extern void irq_handler_4();
extern void irq_handler_5();
extern void irq_handler_6();
extern void irq_handler_7();
extern void irq_handler_8();
extern void irq_handler_9();
extern void irq_handler_10();
extern void irq_handler_11();
extern void irq_handler_12();
extern void irq_handler_13();
extern void irq_handler_14();
extern void irq_handler_15();
void* irq_handlers[16] = {0};
void setup_idt_entry(u32 t_idx, u32 base, u16 sel, u8 type_attrs) {
// Configuring a single given entry in the IDT table
IDT[t_idx].offset_low = (base & 0xffff);
IDT[t_idx].offset_high = ((base >> 16) & 0xffff);
IDT[t_idx].type_attrs = type_attrs;
IDT[t_idx].zero = 0;
IDT[t_idx].selector = sel;
}
// Generic interrupt handler to be used later on
void interrupt_handler(struct cpu_reg_state* cpu) {
// treating things on the stack like it were a cpu_reg_state
// NOTE: dummy stuff to stop gcc from complaining atm
printf("handled exception\n");
if(cpu->int_no < 32) {
printf(err_msg[cpu->int_no]);
}
return;
}
// Pass the index into the table and the handler(strut* cpu_reg_state)
void init_irq_handler(u32 irq, void (*handler)(struct cpu_reg_state* cpu)) {
// install handle
irq_handlers[irq] = handler;
}
void irq_handler(struct cpu_reg_state* cpu) {
void (*handler)(struct cpu_reg_state* cpu);
// Dispatcher for irq's
handler = irq_handlers[cpu->int_no - 0x20];
// Handler the timer by hand because fuck this tbh
if(handler) {
handler(cpu);
}
// pretend like nothing happend for now
if(cpu->int_no >= 40) {
serialport_write_byte(0xa0, 0x20);
}
// notify master pic controller that we're done handling the interrupt
serialport_write_byte(0x20, 0x20);
}
void init_idt() {
// setup special idt pointer
idt_ptr.address = (u32)(&IDT);
idt_ptr.limit = (sizeof(struct IDT_Entry) * IDT_SIZE) - 1;
// clear table
memset((u8*)IDT, 0x00, (sizeof(struct IDT_Entry) * IDT_SIZE));
// add interrupt service routines here
setup_idt_entry(0,(u32)no_err_handler_0,0x08, 0x8e);
setup_idt_entry(1,(u32)no_err_handler_1,0x08, 0x8e);
setup_idt_entry(2,(u32)no_err_handler_2,0x08, 0x8e);
setup_idt_entry(3,(u32)no_err_handler_3,0x08, 0x8e);
setup_idt_entry(4,(u32)no_err_handler_4,0x08, 0x8e);
setup_idt_entry(5,(u32)no_err_handler_5,0x08, 0x8e);
setup_idt_entry(6,(u32)no_err_handler_6,0x08, 0x8e);
setup_idt_entry(7,(u32)no_err_handler_7,0x08, 0x8e);
setup_idt_entry(8,(u32)err_code_handler_8,0x08, 0x8e);
setup_idt_entry(9,(u32)no_err_handler_9,0x08, 0x8e);
setup_idt_entry(10,(u32)err_code_handler_10,0x08, 0x8e);
setup_idt_entry(11,(u32)err_code_handler_11,0x08, 0x8e);
setup_idt_entry(12,(u32)err_code_handler_12,0x08, 0x8e);
setup_idt_entry(13,(u32)err_code_handler_13,0x08, 0x8e);
setup_idt_entry(14,(u32)err_code_handler_14,0x08, 0x8e);
setup_idt_entry(15,(u32)no_err_handler_15,0x08, 0x8e);
setup_idt_entry(16,(u32)no_err_handler_16,0x08, 0x8e);
setup_idt_entry(17,(u32)no_err_handler_17,0x08, 0x8e);
setup_idt_entry(18,(u32)no_err_handler_18,0x08, 0x8e);
setup_idt_entry(19,(u32)no_err_handler_19,0x08, 0x8e);
setup_idt_entry(20,(u32)no_err_handler_20,0x08, 0x8e);
setup_idt_entry(21,(u32)no_err_handler_21,0x08, 0x8e);
setup_idt_entry(22,(u32)no_err_handler_22,0x08, 0x8e);
setup_idt_entry(23,(u32)no_err_handler_23,0x08, 0x8e);
setup_idt_entry(24,(u32)no_err_handler_24,0x08, 0x8e);
setup_idt_entry(25,(u32)no_err_handler_25,0x08, 0x8e);
setup_idt_entry(26,(u32)no_err_handler_26,0x08, 0x8e);
setup_idt_entry(27,(u32)no_err_handler_27,0x08, 0x8e);
setup_idt_entry(28,(u32)no_err_handler_28,0x08, 0x8e);
setup_idt_entry(29,(u32)no_err_handler_29,0x08, 0x8e);
setup_idt_entry(30,(u32)no_err_handler_30,0x08, 0x8e);
setup_idt_entry(31,(u32)no_err_handler_31,0x08, 0x8e);
// Load IDT with all the new information in place, ready to use
load_idt();
// clear table in case there's garbage in there
memset((u8*)irq_handlers, 0, sizeof(void*));
irq_handlers[0] = pit_inc_ticks; // LULW
// Remap irq's to proper location
serialport_write_byte(0x20, 0x11);
serialport_write_byte(0xA0, 0x11);
serialport_write_byte(0x21, 0x20);
serialport_write_byte(0xA1, 0x28);
serialport_write_byte(0x21, 0x04);
serialport_write_byte(0xA1, 0x02);
serialport_write_byte(0x21, 0x01);
serialport_write_byte(0xA1, 0x01);
serialport_write_byte(0x21, 0x0);
serialport_write_byte(0xA1, 0x0);
// Install handlers for irq's
setup_idt_entry(32,(u32)irq_handler_0,0x08, 0x8e);
setup_idt_entry(33,(u32)irq_handler_1,0x08, 0x8e);
setup_idt_entry(34,(u32)irq_handler_2,0x08, 0x8e);
setup_idt_entry(35,(u32)irq_handler_3,0x08, 0x8e);
setup_idt_entry(36,(u32)irq_handler_4,0x08, 0x8e);
setup_idt_entry(37,(u32)irq_handler_5,0x08, 0x8e);
setup_idt_entry(38,(u32)irq_handler_6,0x08, 0x8e);
setup_idt_entry(39,(u32)irq_handler_7,0x08, 0x8e);
setup_idt_entry(40,(u32)irq_handler_8,0x08, 0x8e);
setup_idt_entry(41,(u32)irq_handler_9,0x08, 0x8e);
setup_idt_entry(42,(u32)irq_handler_10,0x08, 0x8e);
setup_idt_entry(43,(u32)irq_handler_11,0x08, 0x8e);
setup_idt_entry(44,(u32)irq_handler_12,0x08, 0x8e);
setup_idt_entry(45,(u32)irq_handler_13,0x08, 0x8e);
setup_idt_entry(46,(u32)irq_handler_14,0x08, 0x8e);
setup_idt_entry(47,(u32)irq_handler_15,0x08, 0x8e);
// Enable interrupt flags
__asm__ __volatile__("sti");
}

View File

@@ -0,0 +1,55 @@
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
#include "types.h"
// There are more interrupts but tbh i doubt we're going to need them
#define i_Timer 0
#define i_Keyboard 1
#define i_PIC2 2
#define i_COM2 3
#define i_COM1 4
#define i_LPT2 5
struct cpu_reg_state {
u32 gs, fs, es, ds; // segment registers
u32 edi, esi, ebp, esp; // generaal purupose via pushad
u32 ebx, edx, ecx, eax;
u32 int_no, err_code; // pushed by each interrupt dispatcher
u32 eip, cs, eflags, useresp, ss; // processor pushes this automatically
}__attribute__((packed)); // we shouldn't need packing since everythign is dwords here
#define IDT_SIZE 256
struct IDT_Entry {
u16 offset_low; // offset bits 0..15
u16 selector; // code segment in either gdt or ldt
u8 zero; // not used always 0
/* 7 0
* +---+---+---+---+---+---+---+---+
* | P | DPL | S | GateType |
* +---+---+---+---+---+---+---+---+
*/
u8 type_attrs; // format specified above
u16 offset_high;// offset bits 16..31
}__attribute__((packed));
struct IDT_PTR {
u16 limit;
u32 address;
}__attribute__((packed));
struct IDT_Entry IDT[IDT_SIZE];
struct IDT_PTR idt_ptr;
void init_idt();
void setup_idt_entry(u32 t_idx, u32 base, u16 sel, u8 type_attrs);
void int_keyboard(struct cpu_reg_state*);
void interrupt_handler(struct cpu_reg_state*);
// IRQ specifi functions
void init_irq_handler(u32 irq, void (*handler)(struct cpu_reg_state* cpu));
void irq_handler(struct cpu_reg_state* cpu);
#endif

73
components/kbd/kbd.c Normal file
View File

@@ -0,0 +1,73 @@
// US Keyboard layout because 'Murrica
#include "kbd.h"
#include "ports.h"
#include "pit.h"
#include "serial.h"
#include "types.h"
#include "stlio.h"
// Courtesy of http://www.osdever.net/bkerndev/Docs/keyboard.htm
unsigned char keymap[128] = {
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
'9', '0', '-', '=', '\b', /* Backspace */
'\t', /* Tab */
'q', 'w', 'e', 'r', /* 19 */
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
0, /* 29 - Control */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
'\'', '`', 0, /* Left shift */
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
'm', ',', '.', '/', 0, /* Right shift */
'*',
0, /* Alt */
' ', /* Space bar */
0, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */
0, /* 69 - Num lock*/
0, /* Scroll Lock */
0, /* Home key */
0, /* Up Arrow */
0, /* Page Up */
'-',
0, /* Left Arrow */
0,
0, /* Right Arrow */
'+',
0, /* 79 - End key*/
0, /* Down Arrow */
0, /* Page Down */
0, /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};
// Reads one key from the keyboard
void kbd_read_key(__attribute__((unused)) struct cpu_reg_state* cpu) {
u8 scancode = serial_read_byte(KBD_PORT);
if(scancode & 0x80) {
// Key released
kbd_key = keymap[scancode & 0x7f]; // clamp to 127 as the max val(gcc is anoying)
kbd_state = KBD_RELEASE;
kbd_time = pit_timer_ticks;
}
else {
// Key pressed
kbd_key = keymap[scancode & 0x7f]; // clamp to 127 as the max val(gcc is anoying)
kbd_state = KBD_PRESS;
kbd_time = pit_timer_ticks;
}
}
void kbd_install_keyboard(void) {
init_irq_handler(1, kbd_read_key);
kbd_key = '\0';
kbd_state = 0;
kbd_time = 0;
}

20
components/kbd/kbd.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef KBD_H
#define KBD_H
#include "types.h"
#include "interrupts.h"
#include "framebuffer.h"
#define KBD_PORT 0x60
#define KBD_PRESS 1
#define KBD_WAITING 2
#define KBD_RELEASE 0x80
char kbd_key;
u8 kbd_state;
u32 kbd_time;
void kbd_install_keyboard(void);
void kbd_read_key(struct cpu_reg_state* cpu);
#endif

18
components/mem/mem.c Normal file
View File

@@ -0,0 +1,18 @@
#include "mem.h"
#include "types.h"
u32 memcpy(u8* src, u8* dest, const u32 size) {
u32 i;
for(i =0; i < size+1;i++) {
dest[i] = src[i];
}
return i;
}
u32 memset(u8* buf, const u8 val, const u32 size) {
u32 i;
for(i=0;i<size;i++) {
buf[i] = val;
}
return i;
}

5
components/mem/mem.h Normal file
View File

@@ -0,0 +1,5 @@
#include "types.h"
u32 memcpy(u8* src, u8* dest, const u32 size);
u32 memset(u8* buf, const u8 val, const u32 size);

19
components/pit/pit.c Normal file
View File

@@ -0,0 +1,19 @@
#include "pit.h"
#include "types.h"
#include "interrupts.h"
#include "serial.h"
#include "stlio.h"
void pit_inc_ticks(__attribute__((unused)) struct cpu_reg_state* cpu) {
pit_timer_ticks++;
}
void pit_timer_wait(u32 time) {
u32 ticks = time + pit_timer_ticks;
while(pit_timer_ticks < ticks);
}
void pit_install_timer(void) {
init_irq_handler(0, pit_inc_ticks); // timer interrupt request falls into irq 0
pit_timer_ticks = 0;
}

19
components/pit/pit.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef PIT_H
#define PIT_H
#include "interrupts.h"
#include "types.h"
// 60hz timer for now
#define PIT_TIMER_INTERVAL 100
#define PIT_TIME_DATA0 0x40
#define PIT_TIME_DATA1 0x41
#define PIT_TIME_DATA2 0x42
volatile u32 pit_timer_ticks;
void pit_inc_ticks(struct cpu_reg_state*);
void pit_timer_wait(u32);
void pit_install_timer(void);
#endif

9
components/ports/ports.h Normal file
View File

@@ -0,0 +1,9 @@
#include "types.h"
#ifndef INCLUDE_IO_H
#define INCLUDE_IO_H
void serialport_write_byte(const u16, const u16);
u8 serial_read_byte(const u16);
#endif /* INCLUDE_IO_H */

21
components/ports/ports.s Normal file
View File

@@ -0,0 +1,21 @@
; Helpers for serial ports which pretty much have to to be
; written in asm
global serialport_write_byte
global serial_read_byte
; write a byte
;serialport_write_byte
serialport_write_byte:
mov al, [esp+8]
mov dx, [esp+4]
out dx, al
ret
; Read byte from serial port
;serialport_read_byte
serial_read_byte:
mov dx, [esp + 4] ; grab the address of the targeted port
in al, dx ; read byte from the port
ret

6
components/readme.md Normal file
View File

@@ -0,0 +1,6 @@
# Components Library
These are the smaller components that give the kernel actual behaviors.
These are pieces that are *practically* required for the OS to function at a
basic level but otherwise are not *technically* required for sheer load-level
operations.

View File

@@ -0,0 +1,89 @@
#include "serial.h"
/*
* SERIAL_LINE_COMMAND_PORT configuration
* Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 |
* Content: | d | b | prty | s | dl |
* d = enable/disable DLAB
* b = enable/disable break control
* prty = # of parity bits to use
* s = # no of stop bits [0 is 1] and [1 is 1.5 or 2]
* dl = length of data
*
*/
void serial_set_baud_rate(const u16 com_port, const u16 divisor) {
// Activate line - ready to send higher 8 bits of data
// send the higher 8 bits first
// send the lower 8 bits next
serialport_write_byte(SERIAL_LINE_COMMAND_PORT(com_port),
SERIAL_LINE_ENABLE);
serialport_write_byte(SERIAL_DATA_PORT(com_port),
(divisor>>8) & 0x00ff);
serialport_write_byte(SERIAL_DATA_PORT(com_port),
divisor & 0x00ff);
}
// Payload described above
void serial_configure_line(const u16 line, const u8 payload) {
serialport_write_byte(SERIAL_LINE_COMMAND_PORT(line), payload);
}
u8 serial_fifo_empty(const u16 com_port) {
// we get back 0x20 if it is empty
return serial_read_byte(SERIAL_LINE_STATUS_PORT(com_port)) &
SERIAL_FIFO_EMPTY_CODE;
}
u64 serial_write(const char* buffer, const u64 size) {
/*
* Writes a given buffer to the com1 serial port for debugging in bochs
*/
serialport_write_byte(SERIAL_DATA_PORT_INT_EN(SERIAL_COM1_BASE),
0x00);
serialport_write_byte(SERIAL_LINE_COMMAND_PORT(SERIAL_COM1_BASE),
SERIAL_LINE_ENABLE);
// quarter speed hopefully the fifo quue wont fill this way
serialport_write_byte(SERIAL_COM1_BASE,
0x01);
serialport_write_byte(SERIAL_DATA_PORT_INT_EN(SERIAL_COM1_BASE),
0x00);
serialport_write_byte(SERIAL_LINE_COMMAND_PORT(SERIAL_COM1_BASE),
SERIAL_DEFAULT_LINE_CFG);
serialport_write_byte(SERIAL_FIFO_COMMAND_PORT(SERIAL_COM1_BASE),
SERIAL_DEFAULT_BUFFER_CFG);
serialport_write_byte(SERIAL_MODEM_COMMAND_PORT(SERIAL_COM1_BASE),
0x0B);
u64 idx;
for(idx =0; idx < size; idx++) {
serialport_write_byte(SERIAL_COM1_BASE, buffer[idx]);
}
return idx;
}
void serial_pic_ack(u32 interrupt) {
// ignore things that are too small and too big
if(interrupt < PIC1_START_INT || interrupt > PIC2_END_INT) {
return;
}
// Send acknoldgement to the pic that we have handled the interrupt
// without this it literally just wait for the ack
if(interrupt < PIC2_START_INT) {
serialport_write_byte(PIC1_PORT, PIC_ACK);
}
else {
serialport_write_byte(PIC2_PORT, PIC_ACK);
}
}

View File

@@ -0,0 +1,43 @@
#include "types.h"
#include "ports.h"
// Serial driver interface
#define SERIAL_COM1_BASE 0x03F8
#define SERIAL_DATA_PORT(base) (base)
#define SERIAL_DATA_PORT_INT_EN(base) (base+1)
#define SERIAL_FIFO_COMMAND_PORT(base) (base+2)
#define SERIAL_LINE_COMMAND_PORT(base) (base+3)
#define SERIAL_MODEM_COMMAND_PORT(base) (base+4)
#define SERIAL_LINE_STATUS_PORT(base) (base+5)
#define SERIAL_LINE_ENABLE 0x80
// Default configurations for serial ports/lines/buffers etc.
// Rational can be found here: https://littleosbook.github.io/#configuring-the-buffers
#define SERIAL_DEFAULT_LINE_CFG 0x03
#define SERIAL_DEFAULT_BUFFER_CFG 0xc7
#define SERIAL_DEFAULT_MODEM_CFG 0x03
#define SERIAL_FIFO_EMPTY_CODE 0x20
#define PIC1_PORT 0x20
#define PIC2_PORT 0xA0
#define PIC1_START_INT 0x20
#define PIC1_END_INT 0x27
#define PIC2_START_INT 0x28
#define PIC2_END_INT 0x2F
#define PIC_ACK 0x20
void serial_set_baud_rate(const u16, const u16);
void serial_configure_line(const u16, const u8);
u8 serial_fifo_empty(const u16);
u64 serial_write(const char* buffer, const u64 size);
void serial_pic_ack(u32 interrupt);

31
components/tests/tests.c Normal file
View File

@@ -0,0 +1,31 @@
// Module for testing drivers and other things
#include "stlio.h"
#include "tests.h"
#include "serial.h"
#include "shell.h"
void test_serial_write() {
char* serial1 = "0123456789abcdef0123456789abcdef";
serial_write(serial1, strlen(serial1));
printf("serial test write finished\n");
}
void test_write(void) {
char* msg1 = "Writing to fbout\n";
printf(msg1);
}
void test_dispatcher(void) {
clear_fb();
}
void test_read(void) {
char buf[5];
u32 bread = read(buf, 5);
printf("Bytes read: "); printhex(bread);
printf("\n");
printf("String read: "); printf(buf);
printf("\n");
for(u32 i = 0;i<5;i++) {
printhex(buf[i]); printf(" ");
}
}

6
components/tests/tests.h Normal file
View File

@@ -0,0 +1,6 @@
#include "types.h"
#include "stlio.h"
void test_write(void);
void test_dispatcher(void);
void test_read(void);

16
components/types/types.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef TYPES_H
#define TYPES_H
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
typedef signed long long s64;
#define false 0
#define true 1
#define NULL 0
#endif