I am developing a custom operating system and using the GRUB bootloader to load my kernel. In my development process, I've encountered an issue where I am unable to switch the display mode from text to graphics mode. Despite configuring GRUB to start in a graphics mode (1024x768x32), the system appears to remain in text mode during booting.
The assembly bootloader and the section of the kernel where I try to use graphics mode are provided below: ; bootloader.asm
[bits 32]
section .multiboot
align 4
dd 0x1BADB002 ; Multiboot magic number
dd 0x00 ; Flags
dd -(0x1BADB002 + 0x00) ; Checksum (must be such that all the dword sums to zero)
section .bootstrap_stack
align 16
stack_bottom:
times 16384 db 0 ; Declare a stack of 16KB
stack_top:
section .text
extern kmain ; This should be in your kernel code
global start
start:
mov esp, stack_top ; Set up the stack
call kmain ; Call the main function in the kernel
cli ; Disable interrupts
.hang:
hlt ; Halt the CPU
jmp .hang ; Infinite loop just in case
my kernel.c file looks like: // kernel.c
#define VIDEO_MEMORY 0xA0000
void print(char *str, int x, int y) {
volatile char *video = (volatile char*)(0xB8000 + 2*x + 160*y);
while (*str != 0) {
*video = *str;
video += 2;
str++;
}
}
#define VIDEO_MEMORY 0xA0000
void fill_screen(unsigned char color) {
unsigned char* video_memory = (unsigned char*)VIDEO_MEMORY;
int i;
for (i = 0; i < 320 * 200; i++)
video_memory[i] = color;
}
void draw_pixel(int x, int y, unsigned char color) {
unsigned char* video_memory = (unsigned char*)VIDEO_MEMORY;
int offset = y * 320 + x;
video_memory[offset] = color;
}
void fillRect(int x, int y, int width, int height, unsigned char color) {
unsigned char* video_memory = (unsigned char*)0xA0000;
int i, j;
for (i = y; i < y + height; i++) {
for (j = x; j < x + width; j++) {
draw_pixel(x+i,y+j, color);
}
}
}
void kmain() {
print("hello", 0, 0);
fill_screen(0x0F); // Fill the screen with white color (0x0F)
draw_pixel(160, 100, 0x0); // Draw a black pixel at (160, 100)
fillRect(5,10,20,20,0xFF);
uint8_t* framebuffer = (uint8_t*)0xA0000; // Replace with your framebuffer address
unsigned int bytes_per_pixel = 3; // Replace with your bytes per pixel
unsigned int bytes_per_scanline = 1920; // Replace with your bytes per scanline
unsigned int x = 10; // The x coordinate of the pixel
unsigned int y = 10; // The y coordinate of the pixel
uint8_t* pixel_address = framebuffer + y * bytes_per_scanline + x * bytes_per_pixel;
pixel_address[0] = 0xFF; // Red
pixel_address[1] = 0x00; // Green
pixel_address[2] = 0x00; // Blue
}
Here's the configuration in my grub.cfg file:
set default=0
set timeout=0
menuentry "My OS" {
multiboot /boot/myos.bin
set gfxpayload=1024x768x32
insmod all_video
boot
}
In my kernel, I implemented a print function that prints text to the screen. My expectation was that, if the system had successfully switched to graphics mode, this function would fail as it is designed for text mode. However, the print function worked as if the system was still in text mode, which suggests that the system never made the switch to graphics mode.
I've tried this setup on several virtual machines and physical machines, and I am consistently experiencing the same issue. I am currently using GRUB version 2.06.
I am stumped as to why the switch to graphics mode isn't happening, despite being specified in the GRUB configuration. Any advice or pointers would be greatly appreciated!
Please remember to replace the comments "More drawing functions" and "More drawing code" with the actual drawing functions and code you are using. This will help others diagnose your issue more accurately.
Instead of gfxpayload in grub.cfg to change the resolution, you can use the framebuffer tag in your Multiboot2 header.
To do this, after checksum add this:
dw 5
dw 0 ;instead of 0, you can specify your flags
dd 20
dd 1024 ;instead of 1024, you can specify your width
dd 768 ;instead of 768, you can specify your height
dd 32 ;instead of 32, you can specify your BPP
Also don't forget that 0xA0000 has a limit of 64,000 bytes and that you can paint over a maximum of 16,000 pixels at 32 BPP.