#include "display.h" #include #include #include #include #define WIDTH 320 #define HEIGHT 200 #define MODE_VGA_320_200_8 0x13 #define MODE_VESA_640_480_8 0x101 /* https://www.phatcode.net/res/262/files/dpmi09.html */ /* http://www.techhelpmanual.com/27-dos__bios___extensions_service_index.html */ // 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; // } /* Not really needed i guess? */ // static inline bool real_mode_interrupt(uint8_t interrupt) { // bool carry_clear; // __asm__ volatile("int $0x31" // : "=@ccnc"(carry_clear) // : "a"(0x0300), "b"(interrupt), "c"(0), "D"(&dpmi_regs) // : "memory", "cc"); // return !carry_clear; // } typedef struct { uint16_t rm_segment; uint16_t pm_selector; } LowMemBlock; // Allocates low memory under 1MB static inline LowMemBlock allocate_low_mem(uint32_t size_in_bytes) { LowMemBlock block = {0, 0}; uint32_t paragraphs = (size_in_bytes + 15) >> 4; // Convert bytes to paragraphs uint16_t seg, sel; uint8_t failed = 0; __asm__ __volatile__( "movw $0x0100, %%ax \n\t" // DPMI allocate DOS memory block "int $0x31 \n\t" "setc %2 \n\t" // Check Carry Flag for error : "=a"(seg), "=d"(sel), "=r"(failed) : "b"(paragraphs) : "cc"); if (!failed) { block.rm_segment = seg; block.pm_selector = sel; } return block; } static inline void copy_to_low_mem(LowMemBlock block, char *data, uint32_t size) { __asm__ volatile("movw %0, %%es\n" "movw %1, %%di\n" "movw %2, %%si\n" "movw .data, %%ax\n" "movw %3, %%cx\n" "cld\n" "rep movsb" ::"r"(block.rm_segment), "r"(block.pm_selector), "r"(data), "r"(size) : "memory", "cc", "ax", "bx", "cx", "esi", "di"); } // Frees the allocated low memory (DPMI Ax=0101h) static inline void free_low_mem(uint16_t selector) { __asm__ __volatile__("movw $0x0101, %%ax \n\t" // DPMI free DOS memory block "int $0x31" : : "d"(selector) : "ax", "cc"); } static inline void set_video_mode(uint16_t mode) { __asm__ volatile("int $0x10" : : "a"(mode) : "memory", "cc"); } /* http://www.techhelpmanual.com/439-dos_fn_40h__write_to_file_via_handle.html */ static inline void writetest(void) { __asm__ volatile("int $0x21" : : "a"(0x0200), "d"('Y') : "memory", "cc"); } /* http://www.techhelpmanual.com/630-int_31h_0800h__physical_address_mapping.html */ static inline void *map_physical_address(uint32_t physical_addr, uint32_t size) { uint16_t high, low; bool carry_clear; __asm__ volatile("int $0x31" : "=b"(high), "=c"(low), "=@ccnc"(carry_clear) : "a"(0x0800), "b"(physical_addr >> 16), "c"(physical_addr & 0xFFFF), "S"(size >> 16), "D"(size & 0xFFFF) : "memory", "cc"); return !carry_clear ? NULL : (void *)(intptr_t)((high << 16) | low); } static inline uint16_t alloc_ldt_descriptor(void) { bool carry_clear; uint16_t selector; __asm__ volatile("int $0x31" : "=a"(selector), "=@ccnc"(carry_clear) : "a"(0x0000), "c"(1) : "memory", "cc"); return !carry_clear ? selector : 0; } static inline bool set_segment_base_address(uint16_t selector, uint32_t baseaddr) { bool carry_clear; __asm__ volatile("int $0x31" : "=a"(selector), "=@ccnc"(carry_clear) : "a"(0x0007), "c"(baseaddr >> 16), "d"(baseaddr & 0xFFFF) : "memory", "cc"); return !carry_clear; } static inline bool set_segment_limit(uint16_t selector, uint32_t size) { bool carry_clear; __asm__ volatile("int $0x31" : "=@ccnc"(carry_clear) : "a"(0x0008), "b"(selector), "c"(size >> 16), "d"(size & 0xFFFF) : "memory", "cc"); return !carry_clear; } static inline bool set_segment_rights(uint16_t selector, bool read, bool write) { bool carry_clear; uint16_t flags = 1 | (write << 1) | (1 << 4) | (1 << 7) | (1 << 14) | (1 << 15); __asm__ volatile("int $0x31" : "=@ccnc"(carry_clear) : "a"(0x0009), "b"(selector), "c"(flags) : "memory", "cc"); return !carry_clear; } static inline void use_segment(uint16_t selector) { __asm__ volatile("" : "=S"(selector)::); } /* https://tippach.hier-im-netz.de/wdosx/int21api.html#f09 */ static inline void print_to_console(char *const str) { __asm__ volatile("int $0x21" ::"a"(0x0900), "d"(str) : "memory", "cc", "esi", "edi", "esp"); } static uint32_t test = 0x1420124; // extern int plr_display_dos_main(int argc, char *argv[]) { extern int plr_display_dos_main(void) { print_to_console("Fuck you stupid shit"); return -1; uint16_t base = alloc_ldt_descriptor(); if (!base) { print_to_console("Cannot allocate LDT descriptor"); return -1; } if (!set_segment_base_address(base, 0xA0000)) { print_to_console("Cannot set LDT base address"); return -1; } if (!set_segment_limit(base, 0x10000)) { print_to_console("Cannot set LDT limit"); return -1; } use_segment(base); // char *volatile buf = (void *)(intptr_t)0xA0000; // VGA memory address // char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory // address if (!buf) return -1; int x, y; // if (!buf) // return -1; // unsigned char saved_mode = get_video_mode(); // Save original mode // set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode set_video_mode(MODE_VGA_320_200_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 while (1) { for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP; // __asm__ volatile("int $0x10" // : // : "a"(0x0C << 8 | COLOR_OFFSET + y / COLOR_STEP), // "b"(0), "c"(x), "d"(y) // : "memory", "cc"); } } // writetest(); __asm__ volatile("int $0x16" : : "a"(0x00) : "memory", "cc"); } // dpmi_regs = (struct dpmi_regs){.eax = 0x00004C00}; // __asm__ volatile("movw $0x0300, %%ax\n" // "movb $0x21, %%bl\n" // "xorb %%bh, %%bh\n" // "xorw %%cx, %%cx\n" // "movl $dpmi_regs, %%edi\n" // "int $0x31" :: // : "memory", "cc", "ax", "bx", "cx", "edi"); return 0; }