From 573b82fd2d46ebca7f98e5323e9f18e593a7996f Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Mon, 10 Jul 2017 21:04:18 +0200 Subject: VGA Z-buffer is now dynamically allocated and freed memory management can reuse the last pointer malloced if freed again --- src/.gdbinit | 1 - src/drivers/video/vga.c | 55 ++++++++++++++++++++++++++++++++++++++----- src/drivers/video/vga.h | 6 +---- src/kernel/kernel.c | 13 +++++----- src/kernel/memorymanagement.c | 15 ++++++++++-- src/kernel/memorymanagement.h | 1 + 6 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/.gdbinit b/src/.gdbinit index e5b0f07..da2e75c 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -1,4 +1,3 @@ -set disassemble-next-line on target remote localhost:1234 symbol-file kernel.sym break kernel_main diff --git a/src/drivers/video/vga.c b/src/drivers/video/vga.c index 0cd623d..751cbc5 100644 --- a/src/drivers/video/vga.c +++ b/src/drivers/video/vga.c @@ -1,6 +1,7 @@ #include "vga.h" #include "stdio.h" +#include "stdlib.h" #include "kernel.h" @@ -48,7 +49,12 @@ void vga_deactivate( void *obj ) void vga_deinit( void *obj ) { - // nothing to do + vga_t *vga = (vga_t *)obj; + + if( vga->zbuffer != NULL ) { + free( vga->zbuffer ); + vga->zbuffer = NULL; + } } void vga_print_info( void *obj ) @@ -213,19 +219,19 @@ static uint8_t *get_frame_buffer_segment( vga_t *vga ) uint8_t *segment = 0x0; switch( segment_no ) { - case 0: // A0000h - BFFFFh, 128k + case 0: // A0000h - BFFFFh segment = (uint8_t *)0xA0000; break; - case 1: // A0000h - AFFFFh, 64k + case 1: // A0000h - AFFFFh segment = (uint8_t *)0xA0000; break; - case 2: // B0000h - B7FFFh, 32k + case 2: // B0000h - B7FFFh segment = (uint8_t *)0xB0000; break; - case 3: // B8000h - BFFFFh, 32k + case 3: // B8000h - BFFFFh segment = (uint8_t *)0xB8000; break; } @@ -237,6 +243,34 @@ static uint8_t *get_frame_buffer_segment( vga_t *vga ) return segment; } +static size_t get_frame_buffer_segment_size( vga_t *vga ) +{ + port8_write( &vga->graphics_controller_index_port, 0x06 ); + uint8_t segment_no = ( port8_read( &vga->graphics_controller_data_port ) >> 2 ) & 0x03; + size_t segment_size = 0; + + switch( segment_no ) { + case 0: // 128k + segment_size = 128 * 1024; + break; + + case 1: // 64k + segment_size = 64 * 1024; + break; + + case 2: // 32k + case 3: + segment_size = 32 * 1024; + break; + } + +#ifdef DEBUG + printf( "segment size: %d 0x%X\n", segment_no, segment_size ); +#endif + + return segment_size; +} + bool vga_set_mode( vga_t *vga, const vga_mode_t mode ) { // do not allow unknown timings! @@ -252,7 +286,6 @@ bool vga_set_mode( vga_t *vga, const vga_mode_t mode ) vga->mode.segment = get_frame_buffer_segment( vga ); vga_use_z_buffer( vga, false ); - memset( vga->zbuffer, 0, sizeof( vga->zbuffer ) ); return true; } @@ -389,11 +422,21 @@ void vga_wait_for_retrace( vga_t *vga ) void vga_use_z_buffer( vga_t *vga, bool use ) { + if( vga->use_z_buffer == use ) { + return; + } + vga->use_z_buffer = use; if( vga->use_z_buffer ) { + size_t size = get_frame_buffer_segment_size( vga ); + vga->zbuffer = (uint8_t *)malloc( size ); vga->base_addr = &vga->zbuffer[0]; } else { + if( vga->zbuffer != NULL ) { + free( vga->zbuffer ); + vga->zbuffer = NULL; + } vga->base_addr = vga->mode.segment; } } diff --git a/src/drivers/video/vga.h b/src/drivers/video/vga.h index bdc15cf..aa842dc 100644 --- a/src/drivers/video/vga.h +++ b/src/drivers/video/vga.h @@ -42,11 +42,7 @@ typedef struct { port8_t attribute_controller_reset_port; vga_mode_t mode; bool use_z_buffer; - // TODO: the Z-buffer should actually be allocated dynamically - // depending on the current mode, for now it's a static buffer - // able to store the biggest resolution, being planar - // 320x200x8 aka 64k - uint8_t zbuffer[65535]; + uint8_t *zbuffer; // stores either the address to the beginning of the segment // (real mapped I/O memory or the beginning of the Z buffer uint8_t *base_addr; diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index f2210d6..c0bc285 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -91,13 +91,14 @@ void kernel_main( void ) // TODO: get memupper from multiboot header (but this needs // a multiboot compliant entry function first) or use BIOS // functions to determine size of memory, for now assume we - // have at least, for now use the memory above 1 MB, 64 MB - // heap is enough for what we are doing in the kernel - memory_manager_init( &global_context.memory_manager, 0x100000, 0xFFFF ); + // have at least, for now use the memory above 1 MB, 128 KB + // heap is enough for what we are doing in the kernel plus + // eventual z buffering the VGA graphic mode + uint32_t heap_offset = 0x01000000; + size_t heap_size = 128 * 1024; + memory_manager_init( &global_context.memory_manager, heap_offset, heap_size ); __stdlib_set_memory_manager( &global_context.memory_manager ); - printf( "Kernel heap at 0x%X, size 0x%X\n", 0x100000, 0xFFFF ); - void *test = malloc( 2048 ); - free( test ); + printf( "Kernel heap at 0x%X, size 0x%X\n", heap_offset, heap_size ); // exit point in case of kernel panic, do this as soon as // possible, as soon we have an early console we can croak on diff --git a/src/kernel/memorymanagement.c b/src/kernel/memorymanagement.c index dc2d160..b8a84b2 100644 --- a/src/kernel/memorymanagement.c +++ b/src/kernel/memorymanagement.c @@ -11,6 +11,7 @@ void memory_manager_init( memory_manager_t *memory_manager, size_t offset, size_ memory_manager->offset = offset; memory_manager->size = size; memory_manager->free_ptr = offset; + memory_manager->prev_ptr = 0xFFFFFFFF; } void *memory_manager_allocate( memory_manager_t *memory_manager, size_t size ) @@ -19,10 +20,11 @@ void *memory_manager_allocate( memory_manager_t *memory_manager, size_t size ) if( memory_manager->free_ptr - memory_manager->offset + size > memory_manager->size ) { kernel_panic( "Heap allocation out of memory (requested %d bytes, available %d)", - size, size - ( memory_manager->free_ptr - memory_manager->offset ) - 1 ); + size, size - ( memory_manager->free_ptr - memory_manager->offset ) ); } p = (void *)memory_manager->free_ptr; + memory_manager->prev_ptr = memory_manager->free_ptr; memory_manager->free_ptr += size; return p; @@ -34,7 +36,16 @@ void memory_manager_deallocate( memory_manager_t *memory_manager, void **p ) kernel_panic( "Double free of pointer 0x%X in heap", *p ); } - *p = NULL; + // This actually doesn't work and we do it outside after free, when + // a buffer has an optional semantic + //*p = NULL; + + // are we freeing the previously allocated block, if yes, we can + // adjust the free pointer + if( (uint32_t)*p == memory_manager->prev_ptr ) { + memory_manager->free_ptr = memory_manager->prev_ptr; + memory_manager->prev_ptr = 0xFFFFFFFF; + } } diff --git a/src/kernel/memorymanagement.h b/src/kernel/memorymanagement.h index 16f0b29..647c05d 100644 --- a/src/kernel/memorymanagement.h +++ b/src/kernel/memorymanagement.h @@ -6,6 +6,7 @@ typedef struct { size_t offset; size_t size; + uint32_t prev_ptr; uint32_t free_ptr; } memory_manager_t; -- cgit v1.2.3-54-g00ecf