diff --git a/Makefile b/Makefile index 3e7c985..b247d97 100644 --- a/Makefile +++ b/Makefile @@ -38,12 +38,13 @@ TARGET_ISO = $(OUT)/edgeos.iso ISO_DIR = $(OUT)/isodir OBJECTS = $(ASM_OBJ)/entry.o $(ASM_OBJ)/load_gdt.o\ - $(ASM_OBJ)/load_idt.o $(ASM_OBJ)/exception.o $(ASM_OBJ)/irq.o\ - $(OBJ)/io_ports.o $(OBJ)/vga.o\ - $(OBJ)/string.o $(OBJ)/console.o\ - $(OBJ)/gdt.o $(OBJ)/idt.o $(OBJ)/isr.o $(OBJ)/8259_pic.o\ - $(OBJ)/keyboard.o\ - $(OBJ)/kernel.o\ + $(ASM_OBJ)/load_idt.o $(ASM_OBJ)/exception.o $(ASM_OBJ)/irq.o\ + $(OBJ)/io_ports.o $(OBJ)/vga.o\ + $(OBJ)/fb.o\ + $(OBJ)/string.o $(OBJ)/console.o\ + $(OBJ)/gdt.o $(OBJ)/idt.o $(OBJ)/isr.o $(OBJ)/8259_pic.o\ + $(OBJ)/keyboard.o\ + $(OBJ)/kernel.o\ $(OBJ)/stdio.o\ $(OBJ)/fs.o @@ -94,6 +95,11 @@ $(OBJ)/vga.o : $(SRC)/vga.c $(CC) $(CFLAGS) -c $(SRC)/vga.c -o $(OBJ)/vga.o @printf "\n" +$(OBJ)/fb.o : $(SRC)/fb.c + @printf "[ $(SRC)/fb.c ]\n" + $(CC) $(CFLAGS) -c $(SRC)/fb.c -o $(OBJ)/fb.o + @printf "\n" + $(OBJ)/string.o : $(SRC)/string.c @printf "[ $(SRC)/string.c ]\n" $(CC) $(CFLAGS) -c $(SRC)/string.c -o $(OBJ)/string.o diff --git a/include/fb.h b/include/fb.h new file mode 100644 index 0000000..25ab526 --- /dev/null +++ b/include/fb.h @@ -0,0 +1,26 @@ +#ifndef FB_H +#define FB_H + +#include +#include + +typedef struct { + uint8_t *addr; + uint32_t width; + uint32_t height; + uint32_t pitch; + uint32_t bpp; + uint32_t r_mask, g_mask, b_mask; + uint32_t r_pos, g_pos, b_pos; +} fb_t; + +extern fb_t fb; + +bool fb_init_from_multiboot2(void *mb_info); +void fb_debug_dump(void); +void fb_putpixel(int x, int y, uint32_t argb); +void fb_clear(uint32_t argb); +bool fb_enable_backbuffer(void); +void fb_present(void); + +#endif /* FB_H */ diff --git a/src/fb.c b/src/fb.c new file mode 100644 index 0000000..d4253ca --- /dev/null +++ b/src/fb.c @@ -0,0 +1,125 @@ +#include "fb.h" +#include "string.h" +#include +#include "console.h" + +fb_t fb = {0}; + +static uint8_t *fb_backbuffer = NULL; +#define FB_BACKBUFFER_MAX (1024*768*4) +static uint8_t fb_backbuffer_storage[FB_BACKBUFFER_MAX]; /* up to 1024x768x32 */ + +#define ALIGN_UP(v, a) (((v) + (a) - 1) & ~((a) - 1)) + +struct multiboot_tag { + uint32_t type; + uint32_t size; +}; + +struct multiboot_tag_framebuffer { + struct multiboot_tag tag; + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + uint16_t reserved; + union { + struct { + uint32_t framebuffer_palette_addr; + uint16_t framebuffer_palette_num_colors; + }; + struct { + uint8_t framebuffer_red_field_position; + uint8_t framebuffer_red_mask_size; + uint8_t framebuffer_green_field_position; + uint8_t framebuffer_green_mask_size; + uint8_t framebuffer_blue_field_position; + uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +static uint32_t fb_argb_to_pixel(uint32_t argb) { + uint32_t r = (argb >> 16) & 0xFF; + uint32_t g = (argb >> 8) & 0xFF; + uint32_t b = argb & 0xFF; + uint32_t pixel = (r << fb.r_pos) & fb.r_mask; + pixel |= (g << fb.g_pos) & fb.g_mask; + pixel |= (b << fb.b_pos) & fb.b_mask; + return pixel; +} + +bool fb_init_from_multiboot2(void *mb_info) { + if (!mb_info) + return false; + uint8_t *ptr = (uint8_t *)mb_info; + struct multiboot_tag *tag = (struct multiboot_tag *)(ptr + 8); + while (tag->type != 0) { + if (tag->type == 8) { + struct multiboot_tag_framebuffer *fbtag = (struct multiboot_tag_framebuffer *)tag; + if (fbtag->framebuffer_type != 1) + return false; + fb.addr = (uint8_t *)(uintptr_t)fbtag->framebuffer_addr; + fb.pitch = fbtag->framebuffer_pitch; + fb.width = fbtag->framebuffer_width; + fb.height = fbtag->framebuffer_height; + fb.bpp = fbtag->framebuffer_bpp; + fb.r_pos = fbtag->framebuffer_red_field_position; + fb.g_pos = fbtag->framebuffer_green_field_position; + fb.b_pos = fbtag->framebuffer_blue_field_position; + fb.r_mask = ((1u << fbtag->framebuffer_red_mask_size) - 1u) << fb.r_pos; + fb.g_mask = ((1u << fbtag->framebuffer_green_mask_size) - 1u) << fb.g_pos; + fb.b_mask = ((1u << fbtag->framebuffer_blue_mask_size) - 1u) << fb.b_pos; + return true; + } + tag = (struct multiboot_tag *)((uint8_t *)tag + ALIGN_UP(tag->size, 8)); + } + return false; +} + +void fb_debug_dump(void) { + console_printf("FB addr=%p size=%ux%u pitch=%u bpp=%u\n", + fb.addr, fb.width, fb.height, fb.pitch, fb.bpp); + console_printf("R: mask=%08x pos=%u\n", fb.r_mask, fb.r_pos); + console_printf("G: mask=%08x pos=%u\n", fb.g_mask, fb.g_pos); + console_printf("B: mask=%08x pos=%u\n", fb.b_mask, fb.b_pos); +} + +void fb_putpixel(int x, int y, uint32_t argb) { + if (!fb.addr) + return; + if ((unsigned)x >= fb.width || (unsigned)y >= fb.height) + return; + uint8_t *base = fb_backbuffer ? fb_backbuffer : fb.addr; + uint32_t pixel = fb_argb_to_pixel(argb); + *(uint32_t *)(base + y * fb.pitch + x * (fb.bpp / 8)) = pixel; +} + +void fb_clear(uint32_t argb) { + if (!fb.addr) + return; + uint8_t *base = fb_backbuffer ? fb_backbuffer : fb.addr; + uint32_t pixel = fb_argb_to_pixel(argb); + for (uint32_t y = 0; y < fb.height; y++) { + uint32_t *row = (uint32_t *)(base + y * fb.pitch); + for (uint32_t x = 0; x < fb.width; x++) { + row[x] = pixel; + } + } +} + +bool fb_enable_backbuffer(void) { + size_t size = fb.pitch * fb.height; + if (size > FB_BACKBUFFER_MAX) + return false; + fb_backbuffer = fb_backbuffer_storage; + return true; +} + +void fb_present(void) { + if (!fb.addr || !fb_backbuffer) + return; + memcpy(fb.addr, fb_backbuffer, fb.pitch * fb.height); +}