diff --git a/.gitignore b/.gitignore index e69de29..f18e76d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.bin +build/boot/grub/grub.cfg +modos.iso diff --git a/Makefile b/Makefile index f735aea..61c4df5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,11 @@ -SRC = src/kernel.c \ - src/string.c \ - src/pixel.c \ - src/debug.c \ +SRC = src/kernel.c \ + src/string.c \ + src/pixel.c \ + src/debug.c \ + src/font.c \ + +# objcopy -O elf32-i386 -B i386 -I binary assets/zap-ext-light32.psf assets/zap-ext-light32.o +FONTS = assets/zap-ext-light32.o CFLAGS += -std=gnu99 -ffreestanding -O2 -Wall -Wextra CC = i686-elf-gcc @@ -22,7 +26,7 @@ all: $(EXEC) $(EXEC): ${OBJ} $(ASMC) $(BOOT_FILE) -o $(BOOT_BIN) - $(CC) -T $(LINKER_FILE) -o $(KERNEL_BIN) $(BOOT_BIN) $(OBJ) -lgcc -ffreestanding -O2 -nostdlib + $(CC) -T $(LINKER_FILE) -o $(KERNEL_BIN) $(BOOT_BIN) $(OBJ) $(FONTS) -lgcc -ffreestanding -O2 -nostdlib grub-file --is-x86-multiboot $(KERNEL_BIN) diff --git a/assets/zap-ext-light32.psf b/assets/zap-ext-light32.psf new file mode 100644 index 0000000..b3e3e65 Binary files /dev/null and b/assets/zap-ext-light32.psf differ diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..62a0401 --- /dev/null +++ b/include/config.h @@ -0,0 +1,14 @@ +/* +** EPITECH PROJECT, 2024 +** ModOS +** File description: +** config.h +*/ + +// TODO: implement config structure instead of macros so that it can be changed at runtime +#ifndef CONFIG_H_ + #define CONFIG_H_ + #define TEXT_COLOR 0xffffff + #define BACKGROUND_COLOR 0x111111 + +#endif /* !CONFIG_H_ */ diff --git a/include/font.h b/include/font.h index e962acf..8217f05 100644 --- a/include/font.h +++ b/include/font.h @@ -12,8 +12,8 @@ #define PSF_FONT_MAGIC 0x864ab572 typedef struct { - uint16_t magic; // Magic bytes for identification. - uint8_t fontMode; // PSF font mode. + uint16_t magic; // Magic bytes for identification. + uint8_t fontMode; // PSF font mode. uint8_t characterSize; // PSF character size. } psf1_header_t; @@ -28,4 +28,12 @@ typedef struct { uint32_t width; /* width in pixels */ } psf_font_t; +extern uint8_t _binary_zap_ext_light32_psf_start; +extern uint8_t _binary_zap_ext_light32_psf_end; +extern uint8_t _binary_zap_ext_light32_psf_size; + +void __os_putchar(unsigned short int c, int cx, int cy, uint32_t fg, + uint32_t bg, psf_font_t *font, uint8_t *font_start); + // , psf_font_t *font, uint8_t font_start[]); + #endif /* !FONT_H_ */ diff --git a/include/pixel.h b/include/pixel.h index 16f5294..2994d00 100644 --- a/include/pixel.h +++ b/include/pixel.h @@ -9,9 +9,9 @@ #define PIXEL_H_ #include -typedef uint32_t argb_t; +typedef uint32_t argb_pixel_t; -void put_pixel(uint32_t x, uint32_t y, argb_t color); +void put_pixel(uint32_t x, uint32_t y, argb_pixel_t color); void clear_screen(uint32_t color); #endif /* !PIXEL_H_ */ diff --git a/include/string.h b/include/string.h index ae55228..dcc8df2 100644 --- a/include/string.h +++ b/include/string.h @@ -7,5 +7,16 @@ #ifndef STRING_H_ #define STRING_H_ + #include + #include + #include + #include "config.h" + #include "font.h" + +void putchar(uint32_t unicode_char); +void puts(const char *str); +void put_uint(uint32_t value); +void put_uint_hex(uint32_t value); +void printf(const char *format, ...); #endif /* !STRING_H_ */ diff --git a/reconnect.sh b/reconnect.sh new file mode 100755 index 0000000..4b31621 --- /dev/null +++ b/reconnect.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +PORT=4444 +HOST=localhost +DELAY=1 + +while true; do + clear + echo "Connecting to QEMU serial port at $HOST:$PORT..." + nc $HOST $PORT + echo "Disconnected from QEMU serial port." + echo "Reconnecting in $DELAY seconds..." + sleep $DELAY +done diff --git a/src/font.c b/src/font.c index 3d9d501..4543121 100644 --- a/src/font.c +++ b/src/font.c @@ -1 +1,101 @@ #include "../include/font.h" +#include "../include/kernel.h" +#include "../include/pixel.h" +#include "stddef.h" + +uint16_t *unicode; + +// NOTE: Optional unicode decoding +// Needs calloc which we don't have right now. +// +// void psf_init() +// { +// uint16_t glyph = 0; +// psf_font_t *font = (psf_font_t*)&font_start; +// +// if (font->flags) { +// unicode = NULL; +// return; +// } +// +// char *s = (char *)( +// (unsigned char*)&font_start + +// font->headersize + +// font->numglyph * font->bytesperglyph +// ); +// unicode = calloc(USHRT_MAX, 2); +// while(s>_binary_zap_ext_light32_psf_end) { +// uint16_t uc = (uint16_t)((unsigned char *)s[0]); +// if(uc == 0xFF) { +// glyph++; +// s++; +// continue; +// } else if(uc & 128) { +// /* UTF-8 to unicode */ +// if((uc & 32) == 0 ) { +// uc = ((s[0] & 0x1F)<<6)+(s[1] & 0x3F); +// s++; +// } else +// if((uc & 16) == 0 ) { +// uc = ((((s[0] & 0xF)<<6)+(s[1] & 0x3F))<<6)+(s[2] & 0x3F); +// s+=2; +// } else +// if((uc & 8) == 0 ) { +// uc = ((((((s[0] & 0x7)<<6)+(s[1] & 0x3F))<<6)+(s[2] & +// 0x3F))<<6)+(s[3] & 0x3F); s+=3; +// } else +// uc = 0; +// } +// unicode[uc] = glyph; +// s++; +// } +// } + +/** + * @brief Unicode putchar + * + * @param c This is an int, not char as it's a unicode character + * @param cx Horizontal position on screen, in characters not in pixels + * @param cy Vertical position on screen, in characters not in pixels + * @param fg ARGB foreground color + * @param bg ARGB background color + */ +void __os_putchar( + unsigned short int c, + int cx, int cy, + uint32_t fg, uint32_t bg, + psf_font_t *font, + uint8_t *font_start) +{ + uint32_t bytesperline = (font->width + 7) / 8; + + if (unicode != NULL) { + c = unicode[c]; + } + + uint8_t *glyph = + (uint8_t *)font_start + font->headersize + + (c > 0 && c < font->numglyph ? c : 0) * font->bytesperglyph; + uint32_t offset = (cy * font->height * framebuffer_pitch) + + (cx * font->width * sizeof(argb_pixel_t)); + + for (uint32_t y = 0; y < font->height; y++) { + uint32_t line = offset; + uint8_t *glyph_row = glyph + y * bytesperline; + uint32_t bits_left = font->width; + + for (uint32_t b = 0; b < bytesperline; b++) { + uint8_t byte = glyph_row[b]; + + for (int bit = 7; bit >= 0 && bits_left > 0; bit--) { + uint32_t color = (byte & (1 << bit)) ? fg : bg; + + *((argb_pixel_t *)(framebuffer + line)) = color; + + line += sizeof(argb_pixel_t); + bits_left--; + } + } + offset += framebuffer_pitch; + } +} diff --git a/src/kernel.c b/src/kernel.c index e41b41a..e5a336c 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -13,11 +13,12 @@ #include "../include/kernel.h" #include "../include/multiboot.h" #include "../include/pixel.h" +#include "../include/config.h" +#include "../include/string.h" /* Check if the compiler thinks you are targeting the wrong operating system. */ #if defined(__linux__) -#error \ - "You are not using a cross-compiler, you will most certainly run into trouble" +#error "You are not using a cross-compiler, you will most certainly run into trouble" #endif /* This tutorial will only work for the 32-bit ix86 targets. */ @@ -55,5 +56,7 @@ void kernel_main(unsigned long magic, multiboot_info_t *mbi) { framebuffer_height = mbi->framebuffer_height; framebuffer_bpp = mbi->framebuffer_bpp; - clear_screen(0xffff0000); + clear_screen(BACKGROUND_COLOR); + + printf("Hello %d\n", 42); } diff --git a/src/pixel.c b/src/pixel.c index 2ca077d..0bd90ba 100644 --- a/src/pixel.c +++ b/src/pixel.c @@ -24,7 +24,7 @@ static inline uint32_t position(uint32_t x, uint32_t y) * x and y indicate the pixel position * color is a 32 bit unsigned integer such as 0xAARRGGBB */ -void put_pixel(uint32_t x, uint32_t y, argb_t color) +void put_pixel(uint32_t x, uint32_t y, argb_pixel_t color) { const uint32_t index = position(x, y); @@ -52,7 +52,7 @@ void put_pixel(uint32_t x, uint32_t y, argb_t color) } } -void clear_screen(argb_t color) +void clear_screen(argb_pixel_t color) { for (uint32_t y = 0; y < framebuffer_height; ++y) { for (uint32_t x = 0; x < framebuffer_width; ++x) { diff --git a/src/string.c b/src/string.c index 0dafc30..d4eb39e 100644 --- a/src/string.c +++ b/src/string.c @@ -1,4 +1,93 @@ #include "../include/string.h" +#include "../include/kernel.h" -void putchar(char c) { +uint32_t cx, cy = 0; +psf_font_t *font = (psf_font_t *)&_binary_zap_ext_light32_psf_start; + +void putchar(uint32_t unicode_char) +{ + if (unicode_char == '\n') { + cx = 0; ++cy; + return; + } + __os_putchar(unicode_char, cx, cy, TEXT_COLOR, BACKGROUND_COLOR, font, (uint8_t *)&_binary_zap_ext_light32_psf_start); + if (++cx > (uint32_t)framebuffer_pitch / font->bytesperglyph) { + cx = 0; ++cy; + } +} + +void put_uint(uint32_t value) +{ + char buffer[11]; + int i = 10; + buffer[i] = '\0'; + + if (value == 0) { + putchar('0'); + return; + } + + while (value > 0 && i > 0) { + buffer[--i] = '0' + (value % 10); + value /= 10; + } + + puts(&buffer[i]); +} + + +void put_uint_hex(uint32_t value) +{ + char buffer[9]; + const char *hex_chars = "0123456789abcdef"; + int i = 8; + buffer[i] = '\0'; + + if (value == 0) { + puts("0x0"); + return; + } + + while (value > 0 && i > 0) { + buffer[--i] = hex_chars[value & 0xF]; + value >>= 4; + } + + puts("0x"); + puts(&buffer[i]); +} + +void printf(const char *format, ...) +{ + va_list params; va_start(params, format); + for (uint32_t i = 0; format[i] != '\0'; ++i) { + if (!(format[i] == '%')) { + putchar(format[i]); + continue; + } + switch (format[++i]) { + case 'd': // idc for now + case 'u': + put_uint((uint32_t)va_arg(params, uint32_t)); + break; + case 'x': + put_uint_hex((uint32_t)va_arg(params, uint32_t)); + break; + case 'c': + putchar((uint8_t)va_arg(params, uint32_t)); + break; + case 's': + puts((char *)va_arg(params, char *)); + break; + default: + putchar(format[i]); + break; + } + } + va_end(params); +} + +void puts(const char *str) +{ + for (uint32_t i = 0; str[i] != '\0'; ++i) putchar(str[i]); }