Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
|
05c8516217 | ||
|
ef72a8d37a |
5 changed files with 196 additions and 253 deletions
|
@ -11,8 +11,14 @@ To compile, you need:
|
||||||
- `nasm` for compiling the bootloader
|
- `nasm` for compiling the bootloader
|
||||||
- `qemu-system-i386` for emulating (`qemu-system-x86_64` will probably work too, but that is not directly supported)
|
- `qemu-system-i386` for emulating (`qemu-system-x86_64` will probably work too, but that is not directly supported)
|
||||||
|
|
||||||
|
More information about installing a cross compiler can be found [here](https://wiki.osdev.org/GCC_Cross-Compiler#The_Build).
|
||||||
|
|
||||||
If you run `make bin`, it will generate `target/boot.bin`, this is a binary file layed out as described in [the docs](docs/bootloader.md). To burn it on a USB drive, simply `dd if=target/boot.bin of=/dev/sdb` and the drive is bootable and contains an SFS filesystem with the files in `filesystem/`.
|
If you run `make bin`, it will generate `target/boot.bin`, this is a binary file layed out as described in [the docs](docs/bootloader.md). To burn it on a USB drive, simply `dd if=target/boot.bin of=/dev/sdb` and the drive is bootable and contains an SFS filesystem with the files in `filesystem/`.
|
||||||
|
|
||||||
|
In case there are errors in the bootloader you can use `make compile_kernel` to only compile the kernel.
|
||||||
|
|
||||||
|
To run TABS in the qemu simulator run `make run`.
|
||||||
|
|
||||||
## Bootloader
|
## Bootloader
|
||||||
|
|
||||||
The bootloader is self-written, based on articles on [the OSDev wiki](https://wiki.osdev.org/). It's a single stage, ELF-loading bootloader in the most basic way possible.
|
The bootloader is self-written, based on articles on [the OSDev wiki](https://wiki.osdev.org/). It's a single stage, ELF-loading bootloader in the most basic way possible.
|
||||||
|
|
|
@ -21,65 +21,60 @@ __attribute__((interrupt)) void NAME (interrupt_frame* frame, uint32_t err_code)
|
||||||
bsod(frame, STR, err_code); \
|
bsod(frame, STR, err_code); \
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal_state state;
|
|
||||||
|
|
||||||
void exception_set_terminal_state(terminal_state* s){
|
|
||||||
terminal_state_copy(s,&state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bsod(interrupt_frame* frame, char* err_msg, int32_t err_code) {
|
void bsod(interrupt_frame* frame, char* err_msg, int32_t err_code) {
|
||||||
|
|
||||||
terminal_write_str(&state,"An exception occured: ");
|
terminal_initialize();
|
||||||
terminal_write_str(&state,err_msg);
|
terminal_writestring("An exception occured: ");
|
||||||
|
terminal_writestring(err_msg);
|
||||||
if(err_code != -1) {
|
if(err_code != -1) {
|
||||||
terminal_write_str(&state," (error code = 0x");
|
terminal_writestring(" (error code = 0x");
|
||||||
terminal_write_int(&state,err_code, 16);
|
terminal_writeint(err_code, 16);
|
||||||
terminal_write_str(&state,")");
|
terminal_writestring(")");
|
||||||
}
|
}
|
||||||
terminal_write_str(&state,"\nHere's what we know:\n");
|
terminal_writestring("\nHere's what we know:\n");
|
||||||
terminal_write_str(&state,"eip = 0x");
|
terminal_writestring("eip = 0x");
|
||||||
terminal_write_int(&state,frame->eip, 16);
|
terminal_writeint(frame->eip, 16);
|
||||||
terminal_write_str(&state,"\ncs = 0x");
|
terminal_writestring("\ncs = 0x");
|
||||||
terminal_write_int(&state,frame->cs, 16);
|
terminal_writeint(frame->cs, 16);
|
||||||
terminal_write_str(&state,"\neflags = 0b");
|
terminal_writestring("\neflags = 0b");
|
||||||
terminal_write_int(&state,frame->eflags, 2);
|
terminal_writeint(frame->eflags, 2);
|
||||||
terminal_write_str(&state,"\n(");
|
terminal_writestring("\n(");
|
||||||
|
|
||||||
terminal_write_str(&state,(0x0001 & frame->eflags) != 0 ? "NC,": "CY,");
|
terminal_writestring((0x0001 & frame->eflags) != 0 ? "NC,": "CY,");
|
||||||
terminal_write_str(&state,(0x0004 & frame->eflags) != 0 ? "PE,": "PO,");
|
terminal_writestring((0x0004 & frame->eflags) != 0 ? "PE,": "PO,");
|
||||||
terminal_write_str(&state,(0x0010 & frame->eflags) != 0 ? "AC,": "NA,");
|
terminal_writestring((0x0010 & frame->eflags) != 0 ? "AC,": "NA,");
|
||||||
terminal_write_str(&state,(0x0040 & frame->eflags) != 0 ? "ZR,": "NZ,");
|
terminal_writestring((0x0040 & frame->eflags) != 0 ? "ZR,": "NZ,");
|
||||||
terminal_write_str(&state,(0x0080 & frame->eflags) != 0 ? "NG,": "PL,");
|
terminal_writestring((0x0080 & frame->eflags) != 0 ? "NG,": "PL,");
|
||||||
terminal_write_str(&state,"TF:");
|
terminal_writestring("TF:");
|
||||||
terminal_write_int(&state,(0x0100 & frame->eflags) >> 8, 2);
|
terminal_writeint((0x0100 & frame->eflags) >> 8, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,(0x0200 & frame->eflags) != 0 ? "EI,": "DI,");
|
terminal_writestring((0x0200 & frame->eflags) != 0 ? "EI,": "DI,");
|
||||||
terminal_write_str(&state,(0x0400 & frame->eflags) != 0 ? "DN,": "UP,");
|
terminal_writestring((0x0400 & frame->eflags) != 0 ? "DN,": "UP,");
|
||||||
terminal_write_str(&state,(0x0800 & frame->eflags) != 0 ? "OV,": "NV,");
|
terminal_writestring((0x0800 & frame->eflags) != 0 ? "OV,": "NV,");
|
||||||
terminal_write_str(&state,"IOPL:");
|
terminal_writestring("IOPL:");
|
||||||
terminal_write_int(&state,(0x3000 & frame->eflags) >> 12, 10);
|
terminal_writeint((0x3000 & frame->eflags) >> 12, 10);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"NT:");
|
terminal_writestring("NT:");
|
||||||
terminal_write_int(&state,(0x4000 & frame->eflags) >> 14, 2);
|
terminal_writeint((0x4000 & frame->eflags) >> 14, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"RF:");
|
terminal_writestring("RF:");
|
||||||
terminal_write_int(&state,(0x0001000 & frame->eflags) >> 16, 2);
|
terminal_writeint((0x0001000 & frame->eflags) >> 16, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"VM:");
|
terminal_writestring("VM:");
|
||||||
terminal_write_int(&state,(0x0002000 & frame->eflags) >> 17, 2);
|
terminal_writeint((0x0002000 & frame->eflags) >> 17, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"AC:");
|
terminal_writestring("AC:");
|
||||||
terminal_write_int(&state,(0x0004000 & frame->eflags) >> 18, 2);
|
terminal_writeint((0x0004000 & frame->eflags) >> 18, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"VIF:");
|
terminal_writestring("VIF:");
|
||||||
terminal_write_int(&state,(0x0008000 & frame->eflags) >> 19, 2);
|
terminal_writeint((0x0008000 & frame->eflags) >> 19, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"VIP:");
|
terminal_writestring("VIP:");
|
||||||
terminal_write_int(&state,(0x0010000 & frame->eflags) >> 20, 2);
|
terminal_writeint((0x0010000 & frame->eflags) >> 20, 2);
|
||||||
terminal_write_char(&state,',');
|
terminal_putchar(',');
|
||||||
terminal_write_str(&state,"ID:");
|
terminal_writestring("ID:");
|
||||||
terminal_write_int(&state,(0x0020000 & frame->eflags) >> 21, 2);
|
terminal_writeint((0x0020000 & frame->eflags) >> 21, 2);
|
||||||
terminal_write_char(&state,')');
|
terminal_putchar(')');
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
|
|
|
@ -27,25 +27,20 @@ static inline bool are_interrupts_enabled() {
|
||||||
|
|
||||||
void kernel_main(void)
|
void kernel_main(void)
|
||||||
{
|
{
|
||||||
terminal_state state;
|
/* Initialize terminal interface */
|
||||||
terminal_initialize_state(&state);
|
terminal_initialize();
|
||||||
|
|
||||||
terminal_set_color(&state, VGA_COLOR_BLACK, VGA_COLOR_RED);
|
terminal_putchar('H');
|
||||||
terminal_write_char(&state, 'H');
|
terminal_putchar('e');
|
||||||
terminal_set_color(&state, VGA_COLOR_BLACK, VGA_COLOR_GREEN);
|
terminal_putchar('l');
|
||||||
terminal_write_char(&state, 'e');
|
terminal_putchar('l');
|
||||||
terminal_set_color(&state, VGA_COLOR_BLACK, VGA_COLOR_BLUE);
|
terminal_putchar('o');
|
||||||
terminal_write_char(&state, 'l');
|
|
||||||
terminal_set_color(&state, VGA_COLOR_BLACK, VGA_COLOR_MAGENTA);
|
|
||||||
terminal_write_char(&state, 'l');
|
|
||||||
terminal_set_color(&state, VGA_COLOR_BLACK, VGA_COLOR_WHITE);
|
|
||||||
terminal_write_char(&state, 'o');
|
|
||||||
|
|
||||||
terminal_set_color(&state, VGA_COLOR_GREEN, VGA_COLOR_WHITE);
|
terminal_setcolor(vga_entry_color(VGA_COLOR_GREEN, VGA_COLOR_BLACK));
|
||||||
terminal_write_str(&state," kernel");
|
terminal_writestring(" kernel");
|
||||||
terminal_set_color(&state, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
terminal_setcolor(vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK));
|
||||||
terminal_write_str(&state," World!\n");
|
terminal_writestring(" World!\n");
|
||||||
terminal_write_str(&state,"Newlines!\n");
|
terminal_writestring("Newlines!\n");
|
||||||
|
|
||||||
char* memory_str = alloc(sizeof(char) * 7);
|
char* memory_str = alloc(sizeof(char) * 7);
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
|
@ -59,13 +54,11 @@ void kernel_main(void)
|
||||||
}
|
}
|
||||||
management_str[13] = 0;
|
management_str[13] = 0;
|
||||||
|
|
||||||
/* terminal_write_str(&state,memory_str); */
|
terminal_writestring(memory_str);
|
||||||
/* terminal_write_str(&state,management_str); */
|
terminal_writestring(management_str);
|
||||||
|
|
||||||
terminal_write_str(&state, (are_interrupts_enabled())? "Interrupts!\n": "No interrupts :(\n");
|
terminal_writestring((are_interrupts_enabled())? "Interrupts!\n": "No interrupts :(\n");
|
||||||
|
|
||||||
shell_set_terminal_state(&state);
|
|
||||||
exception_set_terminal_state(&state);
|
|
||||||
interrupt_init();
|
interrupt_init();
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
|
@ -11,36 +11,31 @@
|
||||||
|
|
||||||
char buffer[SHELL_CMD_BUFFER_SIZE];
|
char buffer[SHELL_CMD_BUFFER_SIZE];
|
||||||
int buffer_idx = 0;
|
int buffer_idx = 0;
|
||||||
terminal_state state;
|
|
||||||
|
|
||||||
void shell_set_terminal_state(terminal_state* s){
|
|
||||||
terminal_state_copy(s,&state);
|
|
||||||
}
|
|
||||||
|
|
||||||
int echo(char* input) {
|
int echo(char* input) {
|
||||||
terminal_write_str(&state,input);
|
terminal_writestring(input);
|
||||||
terminal_write_char(&state,'\n');
|
terminal_putchar('\n');
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hello(char* unused) {
|
int hello(char* unused) {
|
||||||
terminal_write_str(&state,"Hello, world!\n");
|
terminal_writestring("Hello, world!\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cls(char* unused) {
|
int cls(char* unused) {
|
||||||
terminal_clear_state(&state);
|
terminal_initialize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_gdt(char* unused) {
|
int get_gdt(char* unused) {
|
||||||
gdt_desc desc = {2,2};
|
gdt_desc desc = {2,2};
|
||||||
sgdt(&desc);
|
sgdt(&desc);
|
||||||
terminal_write_str(&state,"limit = ");
|
terminal_writestring("limit = ");
|
||||||
terminal_write_int(&state,desc.limit, 10);
|
terminal_writeint(desc.limit, 10);
|
||||||
terminal_write_str(&state,"\nbase = 0x");
|
terminal_writestring("\nbase = 0x");
|
||||||
terminal_write_int(&state,desc.base, 16);
|
terminal_writeint(desc.base, 16);
|
||||||
terminal_write_char(&state,'\n');
|
terminal_putchar('\n');
|
||||||
|
|
||||||
gdt_entry* entries = (gdt_entry*) desc.base;
|
gdt_entry* entries = (gdt_entry*) desc.base;
|
||||||
int num_entries = (desc.limit+1) / 8;
|
int num_entries = (desc.limit+1) / 8;
|
||||||
|
@ -51,73 +46,74 @@ int get_gdt(char* unused) {
|
||||||
uint8_t flags = (entry.flags_limit_higher >> 4);
|
uint8_t flags = (entry.flags_limit_higher >> 4);
|
||||||
bool is_data = ((entry.access_byte & 0b00001000) >> 3) == 0;
|
bool is_data = ((entry.access_byte & 0b00001000) >> 3) == 0;
|
||||||
|
|
||||||
//terminal_write_str(&state,"\nEntry ");
|
//terminal_writestring("\nEntry ");
|
||||||
//terminal_write_int(&state,entry_num, 10);
|
//terminal_writeint(entry_num, 10);
|
||||||
terminal_write_str(&state,"base = 0x");
|
terminal_writestring("base = 0x");
|
||||||
terminal_write_int(&state,base, 16);
|
terminal_writeint(base, 16);
|
||||||
terminal_write_str(&state,"\nlimit = 0x");
|
terminal_writestring("\nlimit = 0x");
|
||||||
terminal_write_int(&state,limit, 16);
|
terminal_writeint(limit, 16);
|
||||||
terminal_write_str(&state,"\nflags = 0b");
|
terminal_writestring("\nflags = 0b");
|
||||||
terminal_write_int(&state,(entry.flags_limit_higher >> 4), 2);
|
terminal_writeint((entry.flags_limit_higher >> 4), 2);
|
||||||
|
|
||||||
if ((flags & 0b1000) == 0) {
|
if ((flags & 0b1000) == 0) {
|
||||||
terminal_write_str(&state," (byte granularity");
|
terminal_writestring(" (byte granularity");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state," (page granularity");
|
terminal_writestring(" (page granularity");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & 0b0100) == 0) {
|
if ((flags & 0b0100) == 0) {
|
||||||
terminal_write_str(&state,", 16 bit)");
|
terminal_writestring(", 16 bit)");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state,", 32 bit)");
|
terminal_writestring(", 32 bit)");
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal_write_str(&state,"\naccess = 0b");
|
terminal_writestring("\naccess = 0b");
|
||||||
terminal_write_int(&state,entry.access_byte, 2);
|
terminal_writeint(entry.access_byte, 2);
|
||||||
terminal_write_str(&state," (ring ");
|
terminal_writestring(" (ring ");
|
||||||
terminal_write_int(&state,(entry.access_byte & 0b01100000) >> 5, 10);
|
terminal_writeint((entry.access_byte & 0b01100000) >> 5, 10);
|
||||||
if ((entry.access_byte & 0b00010000) == 0) {
|
if ((entry.access_byte & 0b00010000) == 0) {
|
||||||
terminal_write_str(&state,", System");
|
terminal_writestring(", System");
|
||||||
}
|
}
|
||||||
if (is_data) {
|
if (is_data) {
|
||||||
terminal_write_str(&state,", Data");
|
terminal_writestring(", Data");
|
||||||
|
|
||||||
if((entry.access_byte & 0b00000100) == 0) {
|
if((entry.access_byte & 0b00000100) == 0) {
|
||||||
terminal_write_str(&state," (growing up, ");
|
terminal_writestring(" (growing up, ");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state," (growing down, ");
|
terminal_writestring(" (growing down, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if((entry.access_byte & 0b00000010) == 0) {
|
if((entry.access_byte & 0b00000010) == 0) {
|
||||||
terminal_write_str(&state,"r--)");
|
terminal_writestring("r--)");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state,"rw-)");
|
terminal_writestring("rw-)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state,", Code");
|
terminal_writestring(", Code");
|
||||||
|
|
||||||
if((entry.access_byte & 0b00000100) == 0) {
|
if((entry.access_byte & 0b00000100) == 0) {
|
||||||
terminal_write_str(&state," (non-conforming, ");
|
terminal_writestring(" (non-conforming, ");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state," (conforming, ");
|
terminal_writestring(" (conforming, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if((entry.access_byte & 0b00000010) == 0) {
|
if((entry.access_byte & 0b00000010) == 0) {
|
||||||
terminal_write_str(&state,"--x)");
|
terminal_writestring("--x)");
|
||||||
} else {
|
} else {
|
||||||
terminal_write_str(&state,"r-x)");
|
terminal_writestring("r-x)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal_write_str(&state,")\n");
|
terminal_writestring(")\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ree(char* unused) {
|
int ree(char* unused) {
|
||||||
terminal_write_char(&state,'R');
|
terminal_initialize();
|
||||||
|
terminal_putchar('R');
|
||||||
for (int i = 1; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
for (int i = 1; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
||||||
terminal_write_char(&state,'e');
|
terminal_putchar('e');
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +167,7 @@ void shell_step() {
|
||||||
char curr_char = getchar();
|
char curr_char = getchar();
|
||||||
|
|
||||||
if (curr_char == '\n') {
|
if (curr_char == '\n') {
|
||||||
terminal_write_char(&state,curr_char);
|
terminal_putchar(curr_char);
|
||||||
buffer[buffer_idx] = 0;
|
buffer[buffer_idx] = 0;
|
||||||
int result = run_command(buffer);
|
int result = run_command(buffer);
|
||||||
for (int i = 0; i < SHELL_CMD_BUFFER_SIZE; i++) {
|
for (int i = 0; i < SHELL_CMD_BUFFER_SIZE; i++) {
|
||||||
|
@ -180,18 +176,18 @@ void shell_step() {
|
||||||
buffer_idx = 0;
|
buffer_idx = 0;
|
||||||
|
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
terminal_write_str(&state,"No such command\n");
|
terminal_writestring("No such command\n");
|
||||||
}
|
}
|
||||||
} else if (curr_char == 0x08) {
|
} else if (curr_char == 0x08) {
|
||||||
if (buffer_idx != 0) {
|
if (buffer_idx != 0) {
|
||||||
buffer_idx--;
|
buffer_idx--;
|
||||||
buffer[buffer_idx] = 0;
|
buffer[buffer_idx] = 0;
|
||||||
terminal_write_char(&state,curr_char);
|
terminal_putchar(curr_char);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer[buffer_idx] = curr_char;
|
buffer[buffer_idx] = curr_char;
|
||||||
buffer_idx++;
|
buffer_idx++;
|
||||||
terminal_write_char(&state,curr_char);
|
terminal_putchar(curr_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define VGA_WIDTH 80
|
static const size_t VGA_WIDTH = 80;
|
||||||
#define VGA_HEIGHT 25
|
static const size_t VGA_HEIGHT = 25;
|
||||||
#define MAX_ENTRIES (VGA_HEIGHT*VGA_WIDTH)
|
|
||||||
#define TERMINAL_BUFFER_START 0xB8000
|
|
||||||
#define BLANK_CHAR ' '
|
|
||||||
|
|
||||||
/* Hardware text mode color constants. */
|
/* Hardware text mode color constants. */
|
||||||
enum vga_color {
|
enum vga_color {
|
||||||
|
@ -31,127 +28,83 @@ enum vga_color {
|
||||||
VGA_COLOR_WHITE = 15,
|
VGA_COLOR_WHITE = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct terminal_entry{
|
size_t terminal_row;
|
||||||
enum vga_color bg_color;
|
size_t terminal_column;
|
||||||
enum vga_color fg_color;
|
uint8_t terminal_color;
|
||||||
char value;
|
uint16_t* terminal_buffer;
|
||||||
} terminal_entry;
|
|
||||||
|
|
||||||
typedef struct terminal_state{
|
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
|
||||||
terminal_entry entries[MAX_ENTRIES];
|
return fg | bg << 4;
|
||||||
int position;
|
|
||||||
enum vga_color bg_color, fg_color;
|
|
||||||
} terminal_state;
|
|
||||||
|
|
||||||
/* Clear the terminal with only blank spaces */
|
|
||||||
void __terminal_clear(terminal_state* state){
|
|
||||||
uint16_t* terminal_buffer = (uint16_t*) TERMINAL_BUFFER_START;
|
|
||||||
uint16_t empty_color = VGA_COLOR_BLACK | VGA_COLOR_GREEN << 4;
|
|
||||||
for(size_t y=0;y<VGA_HEIGHT;++y)
|
|
||||||
for(size_t x=0;x<VGA_WIDTH;++x){
|
|
||||||
size_t index = y * VGA_WIDTH + x;
|
|
||||||
terminal_buffer[index] = (uint16_t) ((unsigned char)BLANK_CHAR) | (uint16_t) empty_color << 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialise a state, i.e. put every char on blank and the default color everywhere */
|
uint16_t vga_entry(unsigned char uc, uint8_t color) {
|
||||||
void terminal_initialize_state(terminal_state* state){
|
return (uint16_t) uc | (uint16_t) color << 8;
|
||||||
state->position=0;
|
|
||||||
state->bg_color = VGA_COLOR_BLACK;
|
|
||||||
state->fg_color = VGA_COLOR_WHITE;
|
|
||||||
for(size_t y=0;y<VGA_HEIGHT;++y)
|
|
||||||
for(size_t x=0;x<VGA_WIDTH;++x){
|
|
||||||
size_t index = y * VGA_WIDTH + x;
|
|
||||||
state->entries[index].value = BLANK_CHAR;
|
|
||||||
}
|
|
||||||
__terminal_clear(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the state from one to the other */
|
size_t strlen(const char* str) {
|
||||||
void terminal_state_copy(terminal_state* from, terminal_state* to){
|
|
||||||
to->position=from->position;
|
|
||||||
to->bg_color = from->bg_color;
|
|
||||||
to->fg_color = from->fg_color;
|
|
||||||
for(size_t y=0;y<VGA_HEIGHT;++y)
|
|
||||||
for(size_t x=0;x<VGA_WIDTH;++x){
|
|
||||||
size_t index = y * VGA_WIDTH + x;
|
|
||||||
to->entries[index].value = from->entries[index].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function will update the terminal buffer with the given state */
|
|
||||||
void terminal_update(terminal_state *state){
|
|
||||||
__terminal_clear(state);
|
|
||||||
uint16_t* terminal_buffer = (uint16_t*) TERMINAL_BUFFER_START;
|
|
||||||
for(size_t y=0;y<VGA_HEIGHT;++y)
|
|
||||||
for(size_t x=0;x<VGA_WIDTH;++x){
|
|
||||||
size_t index = y * VGA_WIDTH + x;
|
|
||||||
terminal_entry entry = state->entries[index];
|
|
||||||
uint8_t color = entry.fg_color | entry.bg_color << 4;
|
|
||||||
terminal_buffer[index] = (uint16_t) ((unsigned char)entry.value) | (uint16_t) color << 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the background color */
|
|
||||||
void __terminal_set_bg_color(terminal_state* state, enum vga_color color){
|
|
||||||
state->bg_color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the foreground color */
|
|
||||||
void __terminal_set_fg_color(terminal_state* state, enum vga_color color){
|
|
||||||
state->fg_color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the color */
|
|
||||||
void terminal_set_color(terminal_state* state, enum vga_color bg_color, enum vga_color fg_color){
|
|
||||||
__terminal_set_bg_color(state, bg_color);
|
|
||||||
__terminal_set_fg_color(state, fg_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a char to the state */
|
|
||||||
void __terminal_put_char(terminal_state *state, char c){
|
|
||||||
size_t pos = state->position;
|
|
||||||
terminal_entry entry;
|
|
||||||
/* If there is a new line, keep going until the end of the line (with blank space in black) */
|
|
||||||
if(c == '\n'){
|
|
||||||
entry.bg_color = VGA_COLOR_BLACK;
|
|
||||||
entry.fg_color = VGA_COLOR_BLACK;
|
|
||||||
entry.value = BLANK_CHAR;
|
|
||||||
while(pos % VGA_WIDTH){
|
|
||||||
state->entries[pos] = entry;
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
state->position = (pos % MAX_ENTRIES);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
entry.bg_color = state->bg_color;
|
|
||||||
entry.fg_color = state->fg_color;
|
|
||||||
entry.value = c;
|
|
||||||
state->entries[pos] = entry;
|
|
||||||
state->position = ((pos+1) % MAX_ENTRIES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a char to the state and run an update */
|
|
||||||
void terminal_write_char(terminal_state *state, const char c){
|
|
||||||
__terminal_put_char(state, c);
|
|
||||||
terminal_update(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a string to the state and run an update */
|
|
||||||
void terminal_write_str(terminal_state *state, const char* str){
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (str[len]) {
|
while (str[len])
|
||||||
__terminal_put_char(state, str[len]);
|
len++;
|
||||||
++len;
|
return len;
|
||||||
}
|
|
||||||
terminal_update(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the terminal en reset the state to the initial state */
|
void terminal_initialize(void) {
|
||||||
void terminal_clear_state(terminal_state* state){
|
terminal_row = 0;
|
||||||
__terminal_clear(state);
|
terminal_column = 0;
|
||||||
terminal_initialize_state(state);
|
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||||
|
terminal_buffer = (uint16_t*) 0xB8000;
|
||||||
|
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
||||||
|
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
|
terminal_buffer[index] = vga_entry(' ', terminal_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_setcolor(uint8_t color) {
|
||||||
|
terminal_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) {
|
||||||
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
|
terminal_buffer[index] = vga_entry(c, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_putchar(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
terminal_column = 0;
|
||||||
|
terminal_row++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (c == 0x08) {
|
||||||
|
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
|
||||||
|
if (terminal_column == 0) {
|
||||||
|
if(terminal_row != 0) {
|
||||||
|
terminal_row--;
|
||||||
|
terminal_column = VGA_WIDTH - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terminal_column--;
|
||||||
|
}
|
||||||
|
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
|
||||||
|
if (++terminal_column == VGA_WIDTH) {
|
||||||
|
terminal_column = 0;
|
||||||
|
if (++terminal_row == VGA_HEIGHT)
|
||||||
|
terminal_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_write(const char* data, size_t size) {
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
terminal_putchar(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal_writestring(const char* data) {
|
||||||
|
terminal_write(data, strlen(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* itoa(unsigned int value, char* result, int base) {
|
char* itoa(unsigned int value, char* result, int base) {
|
||||||
|
@ -176,10 +129,10 @@ char* itoa(unsigned int value, char* result, int base) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminal_write_int(terminal_state* state,int number, int base) {
|
void terminal_writeint(int number, int base) {
|
||||||
char* result = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
|
char* result = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
|
||||||
itoa(number, result, base);
|
itoa(number, result, base);
|
||||||
terminal_write_str(state, result);
|
terminal_writestring(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //TERMINAL_C
|
#endif //TERMINAL_C
|
Loading…
Reference in a new issue