In questo tutorial spiegheremo brevemente come utilizzare le modalita' grafiche offerte dallo standard vesa (oltre 640x480x6bit). Per prima cosa dovrete implementare in un header del vostro sistema queste strutture, per contenere le informazioni del vbe: (i campi usano dei tipi da me definiti, perche' a seconda dell'architettura e del compilatore i tipi base possono utilizzare diverse dimensioni; la “u” sta' per unsigned, il numero e' la dimensione in bit del tipo)
/** * Struttura per le informazioni generali del vbe */ typedef struct { char signature[4]; uint16_t version; uint32_t oem_string_ptr; uint32_t capabilities; uint32_t video_mode_ptr; uint16_t total_memory; // Vesa 2.0 uint32_t oem_software_rev; char *oem_vendor_name; char *oem_product_name; char *oem_product_rev; } vesa_info_t; /** * Struttura per le informazioni della modalita' del vbe */ typedef struct { uint16_t mode_attributes; uint8_t wina_attributes; uint8_t winb_attributes; uint16_t win_granularity; uint16_t win_size; uint16_t wina_segment; uint16_t winb_segment; uint32_t win_pos_func_ptr; uint16_t bytes_per_scan_line; uint16_t width; uint16_t height; uint8_t char_width; uint8_t char_height; uint8_t num_planes; uint8_t bits_per_pixel; uint8_t num_banks; uint8_t memory_model_type; uint8_t bank_size; uint8_t num_image_pages; uint8_t reserved1; uint8_t red_mask_size; uint8_t red_field_position; uint8_t green_mask_size; uint8_t green_field_position; uint8_t blue_mask_size; uint8_t blue_field_position; uint8_t reserved_mask_size; uint8_t reserved_mask_position; uint8_t direct_color_mode_info; uint32_t phys_base_ptr; uint32_t offscreen_mem_ptr; uint16_t offscreen_mem_size; uint16_t lin_bytes_per_scan_line; uint8_t bnk_num_image_pages; uint8_t lin_num_image_pages; uint8_t lin_red_mask_size; uint8_t lin_red_field_position; uint8_t lin_green_mask_size; uint8_t lin_green_field_position; uint8_t lin_blue_mask_size; uint8_t lin_blue_field_position; uint8_t lin_rsvd_mask_size; uint8_t lin_rsvd_field_position; uint32_t max_pixel_clock; uint8_t reserved4[190]; } vesa_mode_info_t;
La prima problematica, e forse anche la piu' complessa e' lo switching dalla modalita' vga (80 colonne di caratteri e 24 righe, in genere) alla modalita' vesa; per raggiungere questo scopo esistono pero' vari metodi:
Alcuni volenterosi programmatori hanno creato una patch per i sorgenti di grub, che permette di fare lo switching alle modalita' vesa tramite il bootloader (http://www.smksoftware.co.za/products/vbe-grub/). Per patchare grub, elenco velocemente i passaggi:
patch -i vbe_grub-0.97.patch sorgenti_grub (da verificare)
Dopo aver messo il grub patchato nella vostra iso, img, o quel che e', sara' necessario aggiungere al file di configurazione di grub (menu.lst) la linea:
vbeset modalita'
Dove modalita' e' un valore numerico che indica appunto la risoluzione e la profondita' del colore desiderata (per 800x600x32 il valore e' 0x115). Dovrete ora aggiungere al vostro kernel il supporto per il multiboot header; in particolare i campi del multiboot che ci serviranno saranno:
uint32_t boot_loader_name; ///< Nome del bootloader uint32_t apm_table; ///< Tabella specifiche apm uint32_t vbe_control_info; ///< Struttura controllo vesa bios uint32_t vbe_mode_info; ///< Struttura info vesa bios uint32_t vbe_mode; ///< Modalita vesa bios attiva uint32_t vbe_interface_seg; ///< Segmento interfaccia vesa bios uint32_t vbe_interface_off; ///< Offset interfaccia vesa bios uint32_t vbe_interface_len; ///< Lunghezza interfaccia vesa bios
In particolare vbe_control_info e vbe_mode_info, che sono due puntatori alle strutture viste in precedenza. L'accesso a queste strutture sara' necessario per conoscere la risoluzione, i bit del colore, e l'indirizzo fisico dove e' mappato il buffer vesa “phys_base_ptr”.
Per disegnare un pixel nello schermo, sara' necessario prima di tutto individuare le coordinate x e y del buffer.
(bytes_per_scan_line).
Per scrivere nella memoria video le info del pixel, sara' necessario scrivere nell'indirizzo “phys_base_ptr” con un offset di x+y, il valore del colore, nella sequenza r, g e b.
Per ottimizzare la velocita', conviene allocare un buffer nella ram di dimensione uguale al buffer video, scrivere li le informazioni dei pixel, e dopo tutte le operazioni, copiare il buffer in ram nella memoria video con memcpy.