#include "display.h" #include #include #define WIDTH 640 #define HEIGHT 480 #define MODE_VGA_320_200_8 0x13 #define MODE_VESA_640_480_8 0x101 // 8-color VGA palette gradient, lighter shades of lavender to pink #define COLOR_OFFSET 0x50 #define COLOR_NUM 8 #define COLOR_STEP (HEIGHT / COLOR_NUM) /* https://wiki.osdev.org/VESA_Video_Modes */ _Packed struct VbeInfoBlock { char VbeSignature[4]; // == "VESA" uint16_t VbeVersion; // == 0x0300 for VBE 3.0 uint16_t OemStringPtr[2]; // isa vbeFarPtr uint8_t Capabilities[4]; uint16_t VideoModePtr[2]; // isa vbeFarPtr uint16_t TotalMemory; // as # of 64KB blocks uint8_t Reserved[492]; }; _Packed struct ModeInfoBlock { uint16_t attributes; // deprecated, only bit 7 should be of interest to you, and it // indicates the mode supports a linear frame buffer. uint8_t window_a; // deprecated uint8_t window_b; // deprecated uint16_t granularity; // deprecated; used while calculating bank numbers uint16_t window_size; uint16_t segment_a; uint16_t segment_b; uint32_t win_func_ptr; // deprecated; used to switch banks from protected mode // without returning to real mode uint16_t pitch; // number of bytes per horizontal line uint16_t width; // width in pixels uint16_t height; // height in pixels uint8_t w_char; // unused... uint8_t y_char; // ... uint8_t planes; uint8_t bpp; // bits per pixel in this mode uint8_t banks; // deprecated; total number of banks in this mode uint8_t memory_model; uint8_t bank_size; // deprecated; size of a bank, almost always 64 KB but may // be 16 KB... uint8_t image_pages; uint8_t reserved0; uint8_t red_mask; uint8_t red_position; uint8_t green_mask; uint8_t green_position; uint8_t blue_mask; uint8_t blue_position; uint8_t reserved_mask; uint8_t reserved_position; uint8_t direct_color_attributes; uint32_t framebuffer; // physical address of the linear frame buffer; write // here to draw to the screen uint32_t off_screen_mem_off; uint16_t off_screen_mem_size; // size of memory in the framebuffer but not // being displayed on the screen uint8_t reserved1[206]; }; static char get_video_mode(); #pragma aux get_video_mode = "mov ah, 0x0f" \ "int 0x10" value[al] modify[ah]; static void set_video_mode(unsigned char); #pragma aux set_video_mode = "mov ah, 0x00" \ "int 0x10" parm[al] modify[ah]; static void set_vesa_video_mode(unsigned short); #pragma aux set_vesa_video_mode = "mov ax, 0x4f02" \ "int 0x10" parm[bx] modify[ah]; static void wait_for_key(); #pragma aux wait_for_key = "mov ah, 0x00" \ "int 0x16" modify[ah]; static short get_vesa_controller_info(struct VbeInfoBlock *); #pragma aux get_vesa_controller_info = "mov ax, 0x4f00" \ "int 0x10" parm[es di] value[ax]; static short get_vesa_mode_info(uint16_t mode, struct ModeInfoBlock *); #pragma aux get_vesa_mode_info = "mov ax, 0x4F01" \ "int 0x10" parm[cx][es di] value[ax]; /* https://wiki.osdev.org/User:Omarrx024/VESA_Tutorial*/ static char *find_display_memory(void) { struct VbeInfoBlock *ctrl = (struct VbeInfoBlock *)0x2000; struct ModeInfoBlock *inf = (struct ModeInfoBlock *)0x3000; uint16_t *modes; int i; strncpy(ctrl->VbeSignature, "VBE2", 4); if (get_vesa_controller_info(ctrl) != 0x004F) return NULL; modes = (uint16_t *)(ctrl->VideoModePtr); for (i = 0; modes[i] != 0xFFFF; ++i) { if (get_vesa_mode_info(modes[i], inf) != 0x004F) continue; // Check if this is a graphics mode with linear frame buffer support if ((inf->attributes & 0x80) != 0x80) continue; // Check if this is a packed pixel or direct color mode if (inf->memory_model != 4 && inf->memory_model != 6) continue; // Check if this is exactly the mode we're looking for if (WIDTH == inf->width && HEIGHT == inf->height && 256 == inf->pitch) return (char *)inf->framebuffer; } return NULL; } extern int plr_display_dos_main(int argc, char *argv[]) { char far *buf = (char far *)0xA0000; // VGA memory address int x, y; unsigned char saved_mode = get_video_mode(); // Save original mode set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode buf = find_display_memory(); /* TODO: Fetch info about the mode, to know the availability */ /* as well as base address in memory */ /* https://wiki.osdev.org/VESA_Video_Modes */ // Now draw. We draw pixel-by-pixel by directly setting the video memory like // it was an array. We step the color every 25 pixels so that we have 8 bands // of even height. for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP; } } wait_for_key(); set_video_mode(saved_mode); // Restore original mode return 0; }