I have been working on a simple kernel that has a basic file system and graphics. I first got 320x200x8 graphics working perfectly, using GRUB 2 to load my kernel, and using the multiboot header with GRUB 2 to change graphics mode:
I soon found the resolution to be too small, and so I changed the target resolution on the multiboot header to 640x400x8, and modified my graphics driver to work with the changes. When I boot the kernel, the display works at first, but when the console grows downward about a quarter of the way to the bottom, nothing is shown:
Here is my boot.s file with the multiboot header.:
Code: Select all
.set ALIGN, 1<<0
.set MEMINFO, 1<<1
.set VIDINFO, 1<<2
.set FLAGS, ALIGN | MEMINFO | VIDINFO
.set MAGIC, 0x1BADB002
.set CHECKSUM, -(MAGIC + FLAGS)
#the multiboot header
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.long 0, 0, 0, 0, 0
.long 0 #set graphics mode
.long 640, 400, 8 #width, height, depth
.section .bootstrap_stack, "aw", @nobits
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
.section .text
.global _start
.type _start, @function
_start:
movl $stack_top, %esp
call kernel_main
cli
hlt
.Lhang:
jmp .Lhang
.size _start, . - _start
Here is my vga code (vga.h & vga.c):
Code: Select all
#ifndef VGA_H
#define VGA_H
/* Hardware 8-bit color constants. */
enum vga_color {
COLOR_BLACK = 0,
COLOR_BLUE = 1,
COLOR_GREEN = 2,
COLOR_CYAN = 3,
COLOR_RED = 4,
COLOR_MAGENTA = 5,
COLOR_BROWN = 6,
COLOR_LIGHT_GREY = 7,
COLOR_DARK_GREY = 8,
COLOR_LIGHT_BLUE = 9,
COLOR_LIGHT_GREEN = 10,
COLOR_LIGHT_CYAN = 11,
COLOR_LIGHT_RED = 12,
COLOR_LIGHT_MAGENTA = 13,
COLOR_LIGHT_BROWN = 14,
COLOR_WHITE = 15,
};
#define Video_Width 640
#define Video_Height 400
typedef uint8_t pixel;
void putpixel(int x,int y, int color);
void graphics_clear(int color);
void graphics_fillrect(size_t x, size_t y, size_t width, size_t height, int color);
// WARNING ----- Will have to be updated for different screen resolution
void graphics_rect(size_t x, size_t y, size_t width, size_t height, int color);
void graphics_drawline(size_t x1, size_t y1, size_t x2, size_t y2, int color);
void graphics_bitmap( int x, int y, int width, int height, uint8_t *data, int forecolor, int backcolor);
void graphics_char( int x, int y, char ch, int forecolor, int backcolor);
void graphics_string( int x, int y, const char *ch, int forecolor, int backcolor);
void graphics_init();
#endif
Code: Select all
#include "system.h"
#include "font.h"
//===============GRAPHICS====================
const size_t memory_location = 0xA0000;
const size_t pitch = 1;
pixel* graphics_buffer;
void putpixel(int x,int y, int color) {
unsigned where = x*pitch + y*Video_Width*pitch;
graphics_buffer[where] = color;
}
void graphics_clear(int color)
{
for (size_t y = 0; y < Video_Height; y++) {
for (size_t x = 0; x < Video_Width; x++) {
putpixel(x, y, color);
}
}
}
void graphics_fillrect(size_t x, size_t y, size_t width, size_t height, int color)
{
for (size_t ypos = y; ypos < (y+height); ypos++) {
for (size_t xpos = x; xpos < (x+width); xpos++) {
putpixel(xpos, ypos, color);
}
}
}
// WARNING ----- Will have to be updated for different screen resolution
void graphics_rect(size_t x, size_t y, size_t width, size_t height, int color)
{
unsigned where = x*pitch + y*Video_Width*pitch;
graphics_buffer[where] = color;
for(size_t top=0; top < width; top++)
{
graphics_buffer[where+top] = color;
}
for(size_t lside=0; lside < height; lside++)
{
graphics_buffer[where+(lside*Video_Width)] = color;
}
for(size_t rside=0; rside < height; rside++)
{
graphics_buffer[where+width+(rside*Video_Width)] = color;
}
for(size_t bottom=0; bottom < width; bottom++)
{
graphics_buffer[where+bottom + Video_Width*height] = color;
}
}
void graphics_drawline(size_t x1, size_t y1, size_t x2, size_t y2, int color)
{
double xpos = (double)x1;
double ypos = (double)y1;
double xdir=(double)x2-(double)x1;
double ydir=(double)y2-(double)y1;
double length = sqroot(sqr(xdir)+sqr(ydir));
if (length != 0){
xdir = xdir/length;
ydir = ydir/length;
}
while(true)
{
if (sqroot(sqr(xpos-(double)x1)+sqr(ypos-(double)y1)) >= length)
break;
putpixel(xpos, ypos, color);
xpos += xdir;
ypos += ydir;
}
}
void graphics_bitmap( int x, int y, int width, int height, uint8_t *data, int forecolor, int backcolor)
{
int i,j,b;
int value;
b=0;
for(j=0;j<height;j++) {
for(i=0;i<width;i++) {
value = ((*data)<<b)&0x80;
if(value) {
putpixel(x+i,y+j,forecolor);
} else {
putpixel(x+i,y+j,backcolor);
}
b++;
if(b==8) {
data++;
b=0;
}
}
}
}
void graphics_char( int x, int y, char ch, int forecolor, int backcolor)
{
int u = ((int)ch)*FONT_WIDTH*FONT_HEIGHT/8;
return graphics_bitmap(x,y,FONT_WIDTH,FONT_HEIGHT,&fontdata[u],forecolor,backcolor);
}
void graphics_string( int x, int y, const char *ch, int forecolor, int backcolor)
{
int _char=0;
while(*ch) {
graphics_char( x + _char*8, y, *ch, forecolor, backcolor);
ch++;
_char++;
}
}
void graphics_init() {
graphics_buffer = (pixel*) memory_location;
graphics_clear(256);
//can't use printf because its not initialized yet
graphics_string(0, 0, "vga: ready\n", COLOR_RED, COLOR_BLACK);
}
I have noticed that the amount of memory required to change from 320x200x8 to 640x400x8 is about four times more than the former resolution, and the point at which the display ceases to work is about a quarter of the way down the screen. By the way, my grub.cfg file is just a very basic menuentry and multiboot command. Is it possible I have to tell GRUB in the cfg file what resolution to use, or that the vga memory is not initialized properly? Thanks!