summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-06-14 20:48:16 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-06-14 20:48:16 +0200
commit8fb9efc08388d3a866cfdf911b07e372de24b556 (patch)
tree3afaf07e27fb37bd5a88b187d505137abdaa817b
parent7a3b38c6462587657f20d684a833f0264de230b5 (diff)
downloadabaos-8fb9efc08388d3a866cfdf911b07e372de24b556.tar.gz
abaos-8fb9efc08388d3a866cfdf911b07e372de24b556.tar.bz2
got switch to graphical VGA mode working
-rw-r--r--doc/LINKS.TODO1
-rw-r--r--src/Makefile4
-rw-r--r--src/boot/stage2_real_functions.asm2
-rw-r--r--src/drivers/video/vga.c230
-rw-r--r--src/drivers/video/vga.h40
-rw-r--r--src/hardware/pci.c7
-rw-r--r--src/kernel/kernel.c18
-rw-r--r--src/kernel/vgatext.c4
8 files changed, 294 insertions, 12 deletions
diff --git a/doc/LINKS.TODO b/doc/LINKS.TODO
index 014ed8b..cc117a7 100644
--- a/doc/LINKS.TODO
+++ b/doc/LINKS.TODO
@@ -84,3 +84,4 @@ http://www.drdobbs.com/extending-c-for-object-oriented-programm/184402731
VGA:
http://www.inp.nsk.su./~bolkhov/files/fonts/univga/
https://sourceforge.net/projects/bdf2c/
+http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
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 <stdbool.h>
+
#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;
}