From 8fb9efc08388d3a866cfdf911b07e372de24b556 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 14 Jun 2017 20:48:16 +0200 Subject: got switch to graphical VGA mode working --- src/Makefile | 4 +- src/boot/stage2_real_functions.asm | 2 +- src/drivers/video/vga.c | 230 ++++++++++++++++++++++++++++++++++++- src/drivers/video/vga.h | 40 ++++++- src/hardware/pci.c | 7 ++ src/kernel/kernel.c | 18 ++- src/kernel/vgatext.c | 4 +- 7 files changed, 293 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index a5aa9d0..c1dfd2b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,13 +15,13 @@ all: image.bin kernel.sym # + 1 * 512 = 512 for magic.bin # (M + N + 1 is the number of sectors to be read in stage 2, as stage 1 # loads only the first sector, and stage 1 loads 3 sectors of stage 2, -# adapt NOF_LOAD_SECTORS to 37) +# adapt NOF_LOAD_SECTORS to 41) # then we make sure the image has the size of a 1.44 MB floppy # (emulators like qemu do some guess work for CHS resolution based # on the size of the image) image.bin: boot.bin kernel.bin magic.bin cat boot.bin kernel.bin > image.tmp - truncate -s 20480 image.tmp + truncate -s 22528 image.tmp cat image.tmp magic.bin > image.bin truncate -s 1474560 image.bin diff --git a/src/boot/stage2_real_functions.asm b/src/boot/stage2_real_functions.asm index d49bfce..8a0ab8d 100644 --- a/src/boot/stage2_real_functions.asm +++ b/src/boot/stage2_real_functions.asm @@ -2,7 +2,7 @@ ; (note: the first sector gets loaded by the BIOS, the ; next 3 sectors are read by the simple stage 1 loader, ; so subtract 3 here!) -NOF_LOAD_SECTORS equ 37 +NOF_LOAD_SECTORS equ 41 ; data sections used for reading the kernel from disk SECTORS_PER_CYLINDER: diff --git a/src/drivers/video/vga.c b/src/drivers/video/vga.c index 0462984..75a47f4 100644 --- a/src/drivers/video/vga.c +++ b/src/drivers/video/vga.c @@ -2,6 +2,8 @@ #include "stdio.h" +#include "kernel.h" + #undef DEBUG static vga_vtable_t vga_vtable = { @@ -17,6 +19,18 @@ void vga_init( vga_t *vga, void *context ) { memset( vga, 0, sizeof( vga_t ) ); + port8_init( &vga->misc_port, 0x3C2 ); + port8_init( &vga->crtc_index_port, 0x3D4 ); + port8_init( &vga->crtc_data_port, 0x3D5 ); + port8_init( &vga->sequencer_index_port, 0x3C4 ); + port8_init( &vga->sequencer_data_port, 0x3C5 ); + port8_init( &vga->graphics_controller_index_port, 0x3CE ); + port8_init( &vga->graphics_controller_data_port, 0x3CF ); + port8_init( &vga->attribute_controller_index_port, 0x3C0 ); + port8_init( &vga->attribute_controller_read_port, 0x3C1 ); + port8_init( &vga->attribute_controller_write_port, 0x3C0 ); + port8_init( &vga->attribute_controller_reset_port, 0x3DA ); + vga->context = context; vga->base.vtable = &vga_vtable.base; @@ -25,15 +39,11 @@ void vga_init( vga_t *vga, void *context ) void vga_activate( void *obj ) { puts( "Activating driver for VGA video card.." ); - -// vga_t *vga = obj; } void vga_deactivate( void *obj ) { puts( "Dectivating driver for VGA video card.." ); - -// vga_t *vga = obj; } void vga_deinit( void *obj ) @@ -43,5 +53,215 @@ void vga_deinit( void *obj ) void vga_print_info( void *obj ) { - puts( "VGA video driver" ); + puts( "Generic VGA video driver" ); +} + +static void write_registers( vga_t *vga, uint8_t *regs ) +{ + // misc + port8_write( &vga->misc_port, *( regs++ ) ); + + // seq (5) + for( uint8_t i = 0; i < 5; i++ ) { + port8_write( &vga->sequencer_index_port, i ); + port8_write( &vga->sequencer_data_port, *( regs++ ) ); + } + + // unlock CRTC register (and make sure mode data doesn't lock it again by accident) + port8_write( &vga->crtc_index_port, 0x03 ); + port8_write( &vga->crtc_data_port, port8_read( &vga->crtc_data_port ) | 0x80 ); + port8_write( &vga->crtc_index_port, 0x11 ); + port8_write( &vga->crtc_data_port, port8_read( &vga->crtc_data_port ) & ~0x80 ); + regs[0x3] |= 0x80; + regs[0x11] &= ~0x80; + + // crtc (25) + for( uint8_t i = 0; i < 25; i++ ) { + port8_write( &vga->crtc_index_port, i ); + port8_write( &vga->crtc_data_port, *( regs++ ) ); + } + + // gc (9) + for( uint8_t i = 0; i < 9; i++ ) { + port8_write( &vga->graphics_controller_index_port, i ); + port8_write( &vga->graphics_controller_data_port, *( regs++ ) ); + } + + // ac (21) + for( uint8_t i = 0; i < 21; i++ ) { + (void)port8_read( &vga->attribute_controller_reset_port ); + port8_write( &vga->attribute_controller_index_port, i ); + port8_write( &vga->attribute_controller_write_port, *( regs++ ) ); + } + + // lock 16-color palette and unblank display + (void)port8_read( &vga->attribute_controller_reset_port ); + port8_write( &vga->attribute_controller_index_port, 0x20 ); +} + +vga_mode_t vga_make_mode( const int x, const int y, const int color_depth ) +{ + vga_mode_t mode; + + mode.x = x; + mode.y = y; + mode.color_depth = color_depth; + + return mode; +} + + +static vga_mode_t modes[] = { + { 320, 200, 8, + // from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c + { + /* MISC */ + 0x63, + /* SEQ */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + /* CRTC */ + 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3, + 0xFF, + /* GC */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + /* AC */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00 + } + } +}; + +bool vga_supports_mode( const vga_mode_t mode ) +{ + for( int i = 0; modes[i].x != 0; i++ ) { + if( mode.x == modes[i].x && + mode.y == modes[i].y && + mode.color_depth == modes[i].color_depth ) { + return true; + } + } + + return false; +} + +static int get_matching_mode_idx( const vga_mode_t mode ) +{ + for( int i = 0; modes[i].x != 0; i++ ) { + if( mode.x == modes[i].x && + mode.y == modes[i].y && + mode.color_depth == modes[i].color_depth ) { + return i; + } + } + + return -1; +} + +bool vga_set_mode( vga_t *vga, const vga_mode_t mode ) +{ + // do not allow unknown timings! + if( !vga_supports_mode( mode ) ) { + return false; + } + + vga_mode_t matching_mode = modes[get_matching_mode_idx( mode )]; + + write_registers( vga, matching_mode.regs ); + + vga->mode = mode; + + return true; +} + + +vga_color_t vga_make_RGB( int R, int G, int B ) +{ + vga_color_t c; + + c.R = R; + c.G = G; + c.B = B; + + return c; +} + +static uint8_t *get_frame_buffer_segment( vga_t *vga ) +{ + port8_write( &vga->graphics_controller_index_port, 0x06 ); + uint8_t segment_no = ( port8_read( &vga->graphics_controller_data_port ) >> 2 ) & 0x03; + uint8_t *segment; + + switch( segment_no ) { + case 0: // A0000h - BFFFFh, 128k + segment = (uint8_t *)0xA0000; + break; + + case 1: // A0000h - AFFFFh, 64k + segment = (uint8_t *)0xA0000; + break; + + case 2: // B0000h - B7FFFh, 32k + segment = (uint8_t *)0xB0000; + break; + + case 3: // B8000h - BFFFFh, 32k + segment = (uint8_t *)0xB8000; + break; + } + +#ifdef DEBUG + printf( "segment: %d 0x%X\n", segment_no, segment ); +#endif + + return segment; +} + +static uint8_t get_color_index( const vga_color_t c ) +{ + // TODO: for now white and black, standard VGA palette entries? + if( c.R == 0x00 && c.G == 0x00 && c.B == 0x00 ) return 0x00; + if( c.R == 0x00 && c.G == 0x00 && c.B == 0xA8 ) return 0x01; + if( c.R == 0xFF && c.G == 0xFF && c.B == 0xFF ) return 0x3F; + + return 0x00; +} + +static bool params_ok( vga_t *vga, const int x, const int y ) +{ + if( x < 0 || x > vga->mode.x || y < 0 || y > vga->mode.y ) { + return false; + } + + return true; +} + +void vga_set_pixel( vga_t *vga, const int x, const int y, const vga_color_t color ) +{ + if( !params_ok( vga, x, y ) ) { + kernel_panic( "Pixel coordinates are out of bounds: (%d, %d), resolution is only (%d, %d)", + x, y, vga->mode.x, vga->mode.y ); + } + + uint8_t color_idx = get_color_index( color ); + + uint8_t *segment = get_frame_buffer_segment( vga ); + + uint8_t *addr = segment + vga->mode.x * y + x; + +// printf( "%d %d 0x%X, 0x%X 0x%X\n", x, y, segment, addr, color_idx ); + *addr = color_idx; +} + +void vga_draw_rectangle( vga_t *vga, const int x, const int y, const int w, const int h, const vga_color_t color ) +{ + for( int yy = y; yy < y + h; yy++ ) { + for( int xx = x; xx < x + w; xx++ ) { + vga_set_pixel( vga, xx, yy, color ); + } + } } + diff --git a/src/drivers/video/vga.h b/src/drivers/video/vga.h index 9b7f5c3..7c710c3 100644 --- a/src/drivers/video/vga.h +++ b/src/drivers/video/vga.h @@ -1,6 +1,8 @@ #ifndef VGA_H #define VGA_H +#include + #include "string.h" #include "interrupts.h" @@ -8,11 +10,30 @@ #include "driver.h" +#define NOF_MODE_REGS 66 + +typedef struct { + int x; + int y; + int color_depth; + uint8_t regs[NOF_MODE_REGS]; +} vga_mode_t; + typedef struct { driver_t base; interrupt_t *interrupts; - port8_t command_port; - port8_t data_port; + port8_t misc_port; + port8_t crtc_index_port; + port8_t crtc_data_port; + port8_t sequencer_index_port; + port8_t sequencer_data_port; + port8_t graphics_controller_index_port; + port8_t graphics_controller_data_port; + port8_t attribute_controller_index_port; + port8_t attribute_controller_read_port; + port8_t attribute_controller_write_port; + port8_t attribute_controller_reset_port; + vga_mode_t mode; void *context; } vga_t; @@ -26,4 +47,19 @@ void vga_deactivate( void *obj ); void vga_deinit( void *obj ); void vga_print_info( void *obj ); +vga_mode_t vga_make_mode( const int x, const int y, const int color_depth ); +bool vga_set_mode( vga_t *vga, const vga_mode_t mode ); +bool vga_supports_mode( const vga_mode_t mode ); + +typedef struct { + int R; + int G; + int B; +} vga_color_t; + +vga_color_t vga_make_RGB( int R, int G, int B ); + +void vga_set_pixel( vga_t *vga, const int x, const int y, const vga_color_t color ); +void vga_draw_rectangle( vga_t *vga, const int x, const int y, const int w, const int h, const vga_color_t color ); + #endif // VGA_H diff --git a/src/hardware/pci.c b/src/hardware/pci.c index 6b124b2..6aae01e 100644 --- a/src/hardware/pci.c +++ b/src/hardware/pci.c @@ -3,6 +3,8 @@ #include "string.h" #include "stdio.h" +#include "drivers/video/vga.h" + #define NOF_BUSES 8 #define NOF_DEVICES_PER_BUS 32 #define NOF_FUNCTIONS_PER_DEVICE 8 @@ -176,6 +178,11 @@ driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_ case 0x03: // graphics switch( descriptor->subclass_id ) { case 0x00: // VGA + // TODO: we need a memory manager, otherwise we + // cannot load dynamically a VGA driver here! + // for now, let's put it directly into kernel.c + // for testing + // vga_t *vga = malloc( sizeof( vga_t ) ); break; } break; diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 3c520d6..41c2b4a 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -17,6 +17,9 @@ #include "kernel.h" +// TODO: move away from main! +#include "drivers/video/vga.h" + static jmp_buf panic_jmp_buf; static void handle_keyboard_event( keyboard_event_t *event, void *context ); @@ -93,14 +96,27 @@ void kernel_main( void ) pci_controller_init( &pci_controller ); pci_controller_scan_and_register( &pci_controller, &driver_manager, &interrupt ); + // TODO: move away in pci.c or in a dynamic loader module later + vga_t vga; + vga_init( &vga, NULL ); + driver_manager_add_driver( &driver_manager, (driver_t *)&vga ); + puts( "Activating drivers" ); driver_manager_activate_all( &driver_manager ); + if( vga_set_mode( &vga, vga_make_mode( 320, 200, 8 ) ) ) { +// vga_set_pixel( &vga, 1, 1, vga_make_RGB( 0x00, 0x00, 0xA8 ) ); + vga_draw_rectangle( &vga, 0, 0, 319, 199, vga_make_RGB( 0x00, 0x00, 0xA8 ) ); + } + + // TODO: later, disable VGA text console in stdio and add the + // graphical one.. + puts( "Enabling interrupt handing now.." ); interrupts_enable( ); puts( "Running.." ); - + // endless loop doing nothing, later we have to get events // here from queues and for instance print characters received // from the keyboard to stdout diff --git a/src/kernel/vgatext.c b/src/kernel/vgatext.c index cbee587..76bfd46 100644 --- a/src/kernel/vgatext.c +++ b/src/kernel/vgatext.c @@ -147,7 +147,9 @@ static uint8_t calculate_color_cell( vga_text_t *vga_text ) static bool params_ok( vga_text_t *vga_text, const int x, const int y ) { - if( x > vga_text->res_x || y > vga_text->res_y ) return false; + if( x < 0 || x > vga_text->res_x || y < 0 || y > vga_text->res_y ) { + return false; + } return true; } -- cgit v1.2.3-54-g00ecf