diff --git a/Makefile b/Makefile index e69de29..52f2e24 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,10 @@ +iso: + grub-mkrescue iso_root -o iceOS.iso + +run: + qemu-system-x86_64 -cdrom iceOS.iso + +clean: + rm -rf obj/ kernel/*.o kernel/cpu/*.o iso_root/boot/kernel.elf + rm -rf kernel/drivers/*.o kernel/libc/*.o + rm -rf PyramidKernel.iso bochslog.txt commands \ No newline at end of file diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 index e69de29..5b7fed3 --- a/build.sh +++ b/build.sh @@ -0,0 +1,30 @@ +# grub config file +mkdir -p iso_root/boot/grub/ +cat iso_root/boot/grub/grub.cfg < + +/* outb: + * Redirect data to port(high level interface for ports.asm) + * @param port: Output port to send data to. + * @param data: The actual data to send to port +*/ +void outb(uint16_t port, uint8_t data); + +/* inb: + * Fetch data from a port, return a char + * @param port: Input port to read data from. +*/ +uint8_t inb(uint16_t port); + + +#endif \ No newline at end of file diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c new file mode 100644 index 0000000..253d7e5 --- /dev/null +++ b/kernel/drivers/tty.c @@ -0,0 +1,109 @@ +#include "tty.h" +#include "../libc/string.h" +#include "ports.h" + +#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer +// Also define a 2 byte pointer because cells are 16 bits wide +#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR) + +static uint32_t fb_col = 0; // X +static uint32_t fb_row = 0; // Y + +void write_cell(int16_t i, int8_t c, uint8_t fg, uint8_t bg) { + uint8_t *fb = VGA_PTR; + fb[i*2] = c; + fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg | 0x0F); +} + +void move_cursor(uint16_t pos) { + outb(VGA_CMD_PORT, VGA_HIGH_BYTE); + outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF)); + outb(VGA_CMD_PORT, VGA_LOW_BYTE); + outb(VGA_DATA_PORT, pos & 0x00FF); +} + +void cursor_adv() { + if(fb_col < VGA_WIDTH - 1) + fb_col--; + else + newline(); + + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} + +void cursor_prev() { + if(fb_col == 0) { + if(fb_row == 0) + return; // If first row do not do anything + fb_col = VGA_WIDTH - 1; + fb_row--; + } else + fb_col--; + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} + +void backspace() { + uint16_t pos; + uint8_t c = ' '; + + fb_col--; + pos = fb_col + (fb_row * VGA_WIDTH); + write_cell(pos, c, WHITE, BLACK); +} + +void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) { + uint16_t pos; + for(uint32_t i = 0; i < len; i++) { + uint8_t c = buf[i]; + if(c == '\n' || c == '\r') + newline(); + else if(c == '\t') { + pos = fb_col + (fb_row * VGA_WIDTH); + write_cell(pos, " ", fg, bg); + cursor_adv(); + } else { + pos = fb_col + (fb_row * VGA_WIDTH); + write_cell(pos, c, fg, bg); + cursor_adv(); + } + } +} + +void kprint(uint8_t *buf) { + kprint_c(buf, strlen(buf), WHITE, BLACK); +} + +void init_prompt() { + const uint8_t *prompt = "\nuser@iceOS-$"; + kprint_c(prompt, strlen(prompt), GREEN, BLACK); +} + +void clear_prompt() { + fb_col = 0; + fb_row = 0; + + for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++) + write_cell(i, ' ', WHITE, BLACK); + move_cursor(0); +} + +void clear_row(uint8_t row) { + for(size_t i = 0; i < VGA_WIDTH; i++) + write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK); +} + +void scroll() { + uint16_t *fb = UVGA_PTR; + memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1)); + clear_row(VGA_HEIGHT - 1); +} + +void newline() { + if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it + fb_row++; + else // Otherwise scroll framebuffer + scroll(); + + fb_col = 0; + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} \ No newline at end of file diff --git a/kernel/drivers/tty.h b/kernel/drivers/tty.h new file mode 100644 index 0000000..9e308cd --- /dev/null +++ b/kernel/drivers/tty.h @@ -0,0 +1,60 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ + +#ifndef _TTY_H_ +#define _TTY_H_ + +#include + +// VGA colors +enum TTY_COLORS { + BLACK, // 0 + BLUE, + GREEN, + CYAN, + RED, + MAGENTA, + BROWN, + LIGHT_GREY, + DARK_GREY, + LIGHT_BLUE, + LIGHT_GREEN, + LIGHT_CYAN, + LIGHT_RED, + LIGHT_MAGENTA, + LIGHT_BROWN, + WHITE // 15 +}; + +/* Framebuffer properties */ +#define VIDEO_MEM_ADDR 0x000B8000 // frame buffer address +#define VGA_WIDTH 80 +#define VGA_HEIGHT 25 + +/* VGA I/O ports */ +#define VGA_CMD_PORT 0x3D4 +#define VGA_DATA_PORT 0x3D5 + +/* VGA I/O ports commands */ +#define VGA_HIGH_BYTE 14 +#define VGA_LOW_BYTE 15 + +/* Kernel's VGA API */ +void write_cell(int16_t i, int8_t c, uint8_t fg, uint8_t bg); +void move_cursor(uint16_t pos); +void cursor_adv(); +void backspace(); +void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg); +void kprint(uint8_t *buf); +void init_prompt(); +void clear_prompt(); +void clear_row(uint8_t row); +void scroll(); // Scroll one row +void newline(); + +#endif \ No newline at end of file diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index e69de29..84dd91b 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -0,0 +1,9 @@ +#include "drivers/tty.h" +#include "libc/stdio.h" + +void kernel_main() { + clear_prompt(); + init_prompt(); + + puts("Hello World!"); +} \ No newline at end of file diff --git a/kernel/libc/Makefile b/kernel/libc/Makefile new file mode 100644 index 0000000..0743096 --- /dev/null +++ b/kernel/libc/Makefile @@ -0,0 +1,10 @@ +OBJS = stdio.o string.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + + +all:${OBJS} + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ \ No newline at end of file diff --git a/kernel/libc/stdio.c b/kernel/libc/stdio.c index 9a1fa7c..235235e 100644 --- a/kernel/libc/stdio.c +++ b/kernel/libc/stdio.c @@ -1,7 +1,6 @@ #include "stdio.h" #include "string.h" -#include "drivers/shell.h" - +#include "../drivers/tty.h" int printf(const char *format, ...) { char buf[20],c,*s; @@ -20,32 +19,36 @@ int printf(const char *format, ...) { case 'i': val = va_arg(ap, int); itoa(val, buf, 10); - printk(buf); + kprint(buf); break; case 'x': uval = va_arg(ap, uint32_t); uitoa(uval, buf, 16); - printk(buf); + kprint(buf); break; case 'd': uval = va_arg(ap, uint32_t); uitoa(uval, buf, 10); - printk(buf); + kprint(buf); break; case 'c': s = va_arg(ap, char*); - printk_c(&c, 1); + kprint_c(&c, 1, WHITE, BLACK); break; case 's': s = va_arg(ap, char*); - printk(s); + kprint(s); break; default: - printk_c((char*)format+1, 1); + kprint_c((char*)format+1, 1, WHITE, BLACK); } } else - printk_c((char*)format+1, 1); + kprint_c((char*)format+1, 1, WHITE, BLACK); } va_end(ap); return 0; +} + +void puts(int8_t *buf) { + printf("%s\n", buf); } \ No newline at end of file diff --git a/kernel/libc/stdio.h b/kernel/libc/stdio.h index 57ed36e..ffd50bd 100644 --- a/kernel/libc/stdio.h +++ b/kernel/libc/stdio.h @@ -1,10 +1,19 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ + #ifndef _STDIO_H_ -#define _STDIO_H +#define _STDIO_H_ #include #include #include int printf(const char *format, ...); +void puts(uint8_t *buf); #endif \ No newline at end of file diff --git a/link.ld b/link.ld index e69de29..2544e5c 100644 --- a/link.ld +++ b/link.ld @@ -0,0 +1,35 @@ +ENTRY(kernel_load) + +. = 0x00100000; + +SECTIONS { + + .boot ALIGN (0x1000): + { + *(.multiboot) + } + + .text ALIGN (0x1000): + { + *(.text) + } + + .rodata ALIGN (0x1000): + { + *(.rodata*) + } + + .data ALIGN (0x1000): + { + *(.data) + } + + .bss ALIGN (0x1000): + { + *(COMMON) + *(.bss) + } + +} + +end = .; \ No newline at end of file