Move to GitHub for flexing
This commit is contained in:
parent
09d1dcf3b1
commit
c0c846cc15
@ -14,4 +14,8 @@ struct GDT_ptr {
|
||||
uint32_t base;
|
||||
} __attribute((packed));
|
||||
|
||||
uint8_t gdt_entries[8 * 3]; // (8 bytes per entry) * (num entries)
|
||||
|
||||
void encodeGDT(uint8_t* gdtEntry, struct GDT source);
|
||||
void initializeGDT();
|
||||
#endif //GDT_H
|
||||
|
56
include/idt.h
Normal file
56
include/idt.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct IDT {
|
||||
uint32_t base;
|
||||
uint16_t selector;
|
||||
uint8_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct IDT_ptr {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8_t idt_entries[8 * 256]; // 8 bytes per entry * 256 entries
|
||||
|
||||
struct IDT createIDT(uint32_t base, uint16_t selector, uint8_t flags);
|
||||
void encodeIDT(uint8_t* idtEntry, struct IDT source);
|
||||
void initializeIDT();
|
||||
|
||||
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();
|
||||
|
||||
#endif // IDT_H
|
13
include/isr.h
Normal file
13
include/isr.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct registers{
|
||||
uint32_t ds;
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
uint32_t int_no, err_code;
|
||||
uint32_t eip, cs, eflags, useresp, ss;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif // ISR_H
|
11
include/port.h
Normal file
11
include/port.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef PORT_H
|
||||
#define PORT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
uint8_t port_byte_in (uint8_t port);
|
||||
void port_byte_out(uint8_t port, uint8_t data);
|
||||
uint16_t port_word_in (uint16_t port);
|
||||
void port_word_out(uint16_t port, uint16_t data);
|
||||
|
||||
#endif // PORT_H
|
@ -11,9 +11,14 @@ typedef struct TextOutput {
|
||||
uint16_t* vid_mem;
|
||||
}__attribute__((packed)) TextOutput;
|
||||
|
||||
TextOutput monitor;
|
||||
|
||||
TextOutput createOutput(const int max_row, const int max_column, uint16_t* vid_mem);
|
||||
void scrollText(TextOutput* textOutput);
|
||||
void putChar(uint8_t character, uint8_t background, uint8_t foreground, TextOutput* textOutput);
|
||||
void print(char* string, uint8_t background, uint8_t foreground, TextOutput* textOutput);
|
||||
char* itoa(int value, char* buffer, int base);
|
||||
void printToMonitor(char* string);
|
||||
void printIntToMonitor(int num, int base);
|
||||
|
||||
#endif // PRINT_H
|
||||
|
2
makefile
2
makefile
@ -3,7 +3,7 @@ CXX = i386-elf-gcc
|
||||
CFLAGS = -std=gnu99 -ffreestanding -O2 -Wall -Wextra -nostdlib -Iinclude
|
||||
ASM = nasm
|
||||
|
||||
OBJECTS = gdt.o boot.o print.o kernel.o
|
||||
OBJECTS = boot.o gdt.o isr.o idt.o port.o print.o kernel.o
|
||||
|
||||
%.o : src/%.c
|
||||
$(CXX) $(CFLAGS) -o $@ -c $<
|
||||
|
108
src/boot.s
108
src/boot.s
@ -38,19 +38,100 @@ stack_top:
|
||||
; Declare _start as a function symbol with the given symbol size.
|
||||
section .text
|
||||
|
||||
global _gdt_flush ; Allows the C code to link to this
|
||||
extern _gp ; Says that '_gp' is in another file
|
||||
_gdt_flush:
|
||||
lgdt [_gp] ; Load the GDT with our '_gp' which is a special pointer
|
||||
mov ax, 0x10 ; 0x10 is the 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:flush2 ; 0x08 is the offset to our code segment: Far jump!
|
||||
flush2:
|
||||
ret ; Returns back to the C code!
|
||||
global reloadSegments ; Flush GDT
|
||||
reloadSegments:
|
||||
; Reload CS register containing code selector:
|
||||
JMP 0x08:reload_CS ; 0x08 points at the new code selector
|
||||
reload_CS:
|
||||
; Reload data segment registers:
|
||||
MOV AX, 0x10 ; 0x10 points at the new data selector
|
||||
MOV DS, AX
|
||||
MOV ES, AX
|
||||
MOV FS, AX
|
||||
MOV GS, AX
|
||||
MOV SS, AX
|
||||
RET
|
||||
|
||||
%macro ISR_NOERRCODE 1 ; define a macro, taking one parameter
|
||||
[GLOBAL isr%1] ; %1 accesses the first parameter.
|
||||
isr%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERRCODE 1
|
||||
[GLOBAL isr%1]
|
||||
isr%1:
|
||||
cli
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
ISR_NOERRCODE 0
|
||||
ISR_NOERRCODE 1
|
||||
ISR_NOERRCODE 2
|
||||
ISR_NOERRCODE 3
|
||||
ISR_NOERRCODE 4
|
||||
ISR_NOERRCODE 5
|
||||
ISR_NOERRCODE 6
|
||||
ISR_NOERRCODE 7
|
||||
ISR_NOERRCODE 8
|
||||
ISR_NOERRCODE 9
|
||||
ISR_NOERRCODE 10
|
||||
ISR_NOERRCODE 11
|
||||
ISR_NOERRCODE 12
|
||||
ISR_NOERRCODE 13
|
||||
ISR_NOERRCODE 14
|
||||
ISR_NOERRCODE 15
|
||||
ISR_NOERRCODE 16
|
||||
ISR_NOERRCODE 17
|
||||
ISR_NOERRCODE 18
|
||||
ISR_NOERRCODE 19
|
||||
ISR_NOERRCODE 20
|
||||
ISR_NOERRCODE 21
|
||||
ISR_NOERRCODE 22
|
||||
ISR_NOERRCODE 23
|
||||
ISR_NOERRCODE 24
|
||||
ISR_NOERRCODE 25
|
||||
ISR_NOERRCODE 26
|
||||
ISR_NOERRCODE 27
|
||||
ISR_NOERRCODE 28
|
||||
ISR_NOERRCODE 29
|
||||
ISR_NOERRCODE 30
|
||||
ISR_NOERRCODE 31
|
||||
|
||||
|
||||
[EXTERN isr_handler]
|
||||
|
||||
; This is our common ISR stub. It saves the processor state, sets
|
||||
; up for kernel mode segments, calls the C-level fault handler,
|
||||
; and finally restores the stack frame.
|
||||
isr_common_stub:
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
|
||||
mov ax, 0x10 ; load the kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
call isr_handler
|
||||
|
||||
pop eax ; reload the original data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
popa ; Pops edi,esi,ebp...
|
||||
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
|
||||
sti
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
|
||||
global _start:function (_start.end - _start)
|
||||
_start:
|
||||
@ -70,6 +151,7 @@ _start:
|
||||
; in assembly as languages such as C cannot function without a stack.
|
||||
mov esp, stack_top
|
||||
|
||||
|
||||
; This is a good place to initialize crucial processor state before the
|
||||
; high-level kernel is entered. It's best to minimize the early
|
||||
; environment where crucial features are offline. Note that the
|
||||
|
31
src/gdt.c
31
src/gdt.c
@ -1,5 +1,7 @@
|
||||
#include "gdt.h"
|
||||
|
||||
extern void reloadSegments();
|
||||
|
||||
void encodeGDT(uint8_t* gdtEntry, struct GDT source) {
|
||||
if ((source.limit > 65536) && ((source.limit & 0xFFF) == 0xFFF)) {
|
||||
// Set the GDT to use paging
|
||||
@ -34,3 +36,32 @@ void encodeGDT(uint8_t* gdtEntry, struct GDT source) {
|
||||
// where most of the ideas for this function are taken from shamelessly
|
||||
gdtEntry[5] = source.type;
|
||||
}
|
||||
|
||||
void initializeGDT() {
|
||||
struct GDT nullEntry;
|
||||
nullEntry.limit = 0;
|
||||
nullEntry.base = 0;
|
||||
nullEntry.type = 0;
|
||||
|
||||
struct GDT codeSection;
|
||||
codeSection.limit = 0xFFFFFFFF;
|
||||
codeSection.base = 0;
|
||||
codeSection.type = 0x9A;
|
||||
|
||||
struct GDT dataSection;
|
||||
dataSection.limit = 0xFFFFFFFF;
|
||||
dataSection.base = 0;
|
||||
dataSection.type = 0x92;
|
||||
|
||||
encodeGDT(gdt_entries , nullEntry );
|
||||
encodeGDT(gdt_entries + 8 , codeSection);
|
||||
encodeGDT(gdt_entries + 16, dataSection);
|
||||
|
||||
struct GDT_ptr gdt_ptr;
|
||||
gdt_ptr.limit = 8*3;
|
||||
gdt_ptr.base = (uint32_t)(&gdt_entries);
|
||||
|
||||
asm("lgdt (%0)" : :"r" ((uint8_t*)(&gdt_ptr)));
|
||||
|
||||
reloadSegments();
|
||||
}
|
||||
|
67
src/idt.c
Normal file
67
src/idt.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include "idt.h"
|
||||
|
||||
struct IDT createIDT(uint32_t base, uint16_t selector, uint8_t flags) {
|
||||
struct IDT result;
|
||||
result.base = base;
|
||||
result.selector = selector;
|
||||
result.flags = flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
void encodeIDT(uint8_t* idtEntry, struct IDT source) {
|
||||
// Low base bytes
|
||||
idtEntry[0] = source.base & 0xFF;
|
||||
idtEntry[1] = (source.base >> 8) & 0xFF;
|
||||
// Selector bytes
|
||||
idtEntry[2] = source.selector & 0xFF;
|
||||
idtEntry[3] = (source.selector >> 8) & 0xFF;
|
||||
idtEntry[4] = 0; // Null byte
|
||||
idtEntry[5] = source.flags; // Flag bytes
|
||||
// High base bytes
|
||||
idtEntry[6] = (source.base >> 16) & 0xFF;
|
||||
idtEntry[7] = (source.base >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
void initializeIDT() {
|
||||
struct IDT_ptr idt_ptr;
|
||||
idt_ptr.limit = 8*256 - 1;
|
||||
idt_ptr.base = (uint32_t)&idt_entries;
|
||||
|
||||
for (int i = 0; i < 256*8; i++)
|
||||
idt_entries[i] = 0; // Just to be safe, set IDT to all 0
|
||||
|
||||
encodeIDT(&idt_entries[0] , createIDT((uint32_t)isr0 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[1*8 - 1] , createIDT((uint32_t)isr1 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[2*8 - 1] , createIDT((uint32_t)isr2 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[3*8 - 1] , createIDT((uint32_t)isr3 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[4*8 - 1] , createIDT((uint32_t)isr4 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[5*8 - 1] , createIDT((uint32_t)isr5 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[6*8 - 1] , createIDT((uint32_t)isr6 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[7*8 - 1] , createIDT((uint32_t)isr7 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[8*8 - 1] , createIDT((uint32_t)isr8 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[9*8 - 1] , createIDT((uint32_t)isr9 , 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[10*8 - 1], createIDT((uint32_t)isr10, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[11*8 - 1], createIDT((uint32_t)isr11, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[12*8 - 1], createIDT((uint32_t)isr12, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[13*8 - 1], createIDT((uint32_t)isr13, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[14*8 - 1], createIDT((uint32_t)isr14, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[15*8 - 1], createIDT((uint32_t)isr15, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[16*8 - 1], createIDT((uint32_t)isr16, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[17*8 - 1], createIDT((uint32_t)isr17, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[18*8 - 1], createIDT((uint32_t)isr18, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[19*8 - 1], createIDT((uint32_t)isr19, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[20*8 - 1], createIDT((uint32_t)isr20, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[21*8 - 1], createIDT((uint32_t)isr21, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[22*8 - 1], createIDT((uint32_t)isr22, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[23*8 - 1], createIDT((uint32_t)isr23, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[24*8 - 1], createIDT((uint32_t)isr24, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[25*8 - 1], createIDT((uint32_t)isr25, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[26*8 - 1], createIDT((uint32_t)isr26, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[27*8 - 1], createIDT((uint32_t)isr27, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[28*8 - 1], createIDT((uint32_t)isr28, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[29*8 - 1], createIDT((uint32_t)isr29, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[30*8 - 1], createIDT((uint32_t)isr30, 0x08, 0x8E));
|
||||
encodeIDT(&idt_entries[31*8 - 1], createIDT((uint32_t)isr31, 0x08, 0x8E));
|
||||
|
||||
asm("lidt (%0)" : :"r" ((uint8_t*)(&idt_ptr)));
|
||||
}
|
8
src/isr.c
Normal file
8
src/isr.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include "isr.h"
|
||||
#include "print.h"
|
||||
|
||||
void isr_handler(struct registers regs) {
|
||||
printToMonitor("recieved interrupt: \n");
|
||||
printIntToMonitor(regs.int_no, 10);
|
||||
printToMonitor("\n");
|
||||
}
|
23
src/kernel.c
23
src/kernel.c
@ -1,22 +1,21 @@
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "isr.h"
|
||||
#include "types.h"
|
||||
#include "print.h"
|
||||
#include "port.h"
|
||||
|
||||
// inline function to swap two numbers
|
||||
|
||||
#define FOREGROUND 0x0
|
||||
#define BACKGROUND 0xF
|
||||
|
||||
void PrintWithScreenFill(char* string, TextOutput* output_stream) {
|
||||
// Print a string and fill the screen
|
||||
print(string, BACKGROUND, FOREGROUND, output_stream);
|
||||
int row = output_stream->terminal_row;
|
||||
while (output_stream->terminal_row < output_stream->max_row) {
|
||||
putChar('\n', BACKGROUND, FOREGROUND, output_stream);
|
||||
}
|
||||
output_stream->terminal_row = row;
|
||||
}
|
||||
|
||||
void kernel_main(void) {
|
||||
TextOutput output_stream = createOutput(25,80,(uint16_t*)0xB8000);
|
||||
PrintWithScreenFill("Hello, Logan World!\n", &output_stream);
|
||||
initializeGDT();
|
||||
initializeIDT();
|
||||
printToMonitor("Hello\n");
|
||||
printIntToMonitor(10, 10);
|
||||
asm ("int $0x3");
|
||||
asm ("int $0x4");
|
||||
}
|
||||
|
||||
|
21
src/port.c
Normal file
21
src/port.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "port.h"
|
||||
|
||||
uint8_t port_byte_in (uint8_t port) {
|
||||
uint8_t result;
|
||||
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_byte_out(uint8_t port, uint8_t data) {
|
||||
__asm__("out %%al, %%dx" : :"a" (data), "d" (port));
|
||||
}
|
||||
|
||||
uint16_t port_word_in (uint16_t port) {
|
||||
uint16_t result;
|
||||
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_word_out (uint16_t port, uint16_t data) {
|
||||
__asm__("out %%ax, %%dx" : :"a" (data), "d" (port));
|
||||
}
|
74
src/print.c
74
src/print.c
@ -1,5 +1,8 @@
|
||||
#include "print.h"
|
||||
|
||||
#define FOREGROUND 0x0
|
||||
#define BACKGROUND 0xF
|
||||
|
||||
TextOutput createOutput(const int max_row, const int max_column, uint16_t* vid_mem) {
|
||||
// Create a new TextOutput interface
|
||||
TextOutput output;
|
||||
@ -66,8 +69,77 @@ void putChar(uint8_t character, uint8_t background, uint8_t foreground,
|
||||
|
||||
void print(char* string, uint8_t background, uint8_t foreground, TextOutput* textOutput) {
|
||||
// Print a string
|
||||
for (string; *string; string++) {
|
||||
while (*string) {
|
||||
putChar(*string, background, foreground, textOutput);
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintWithScreenFill(char* string, TextOutput* output_stream) {
|
||||
// Print a string and fill the screen
|
||||
print(string, BACKGROUND, FOREGROUND, output_stream);
|
||||
int row = output_stream->terminal_row;
|
||||
while (output_stream->terminal_row < output_stream->max_row) {
|
||||
putChar('\n', BACKGROUND, FOREGROUND, output_stream);
|
||||
}
|
||||
output_stream->terminal_row = row;
|
||||
}
|
||||
|
||||
|
||||
inline void swap(char *x, char *y) {
|
||||
char t = *x; *x = *y; *y = t;
|
||||
}
|
||||
|
||||
int abs(int value) {
|
||||
return (value < 0 ? -value : value);
|
||||
}
|
||||
|
||||
// function to reverse buffer[i..j]
|
||||
char* reverse(char *buffer, int i, int j)
|
||||
{
|
||||
while (i < j)
|
||||
swap(&buffer[i++], &buffer[j--]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Iterative function to implement itoa() function in C
|
||||
char* itoa(int value, char* buffer, int base)
|
||||
{
|
||||
if (base < 2 || base > 32)
|
||||
return buffer;
|
||||
int n = abs(value);
|
||||
int i = 0;
|
||||
while (n)
|
||||
{
|
||||
int r = n % base;
|
||||
if (r >= 10)
|
||||
buffer[i++] = 65 + (r - 10);
|
||||
else
|
||||
buffer[i++] = 48 + r;
|
||||
n = n / base;
|
||||
}
|
||||
if (i == 0)
|
||||
buffer[i++] = '0';
|
||||
if (value < 0 && base == 10)
|
||||
buffer[i++] = '-';
|
||||
buffer[i] = '\0';
|
||||
return reverse(buffer, 0, i - 1);
|
||||
}
|
||||
|
||||
int haveFilledScreen = 0;
|
||||
|
||||
void printToMonitor(char* string) {
|
||||
if (!haveFilledScreen) {
|
||||
monitor = createOutput(25, 80, (uint16_t*)(0xB8000));
|
||||
PrintWithScreenFill(string, &monitor);
|
||||
haveFilledScreen = 1;
|
||||
}
|
||||
else
|
||||
print(string, BACKGROUND, FOREGROUND, &monitor);
|
||||
}
|
||||
|
||||
void printIntToMonitor(int num, int base) {
|
||||
char* buffer;
|
||||
printToMonitor(itoa(num, buffer, base));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user