boot: generalize video mode selection to work on BIOS
This commit is contained in:
parent
43b6bd32e3
commit
766d1be1d7
@ -37,13 +37,12 @@ char cmdline[1024] = {0};
|
||||
/* Names of the available boot modes. */
|
||||
struct bootmode boot_mode_names[] = {
|
||||
{1, "normal", "Normal Boot"},
|
||||
#ifdef EFI_PLATFORM
|
||||
{2, "video", "Configure Video Output"},
|
||||
#else
|
||||
{2, "vga", "VGA Text Mode"},
|
||||
#endif
|
||||
{3, "single", "Single-User Graphical Terminal"},
|
||||
{4, "headless", "Headless"},
|
||||
#ifndef EFI_PLATFORM
|
||||
{5, "vga", "VGA Text Mode"},
|
||||
#endif
|
||||
};
|
||||
|
||||
int base_sel = 0;
|
||||
@ -91,7 +90,6 @@ int kmain() {
|
||||
/* Loop over rendering the menu */
|
||||
show_menu();
|
||||
|
||||
#ifdef EFI_PLATFORM
|
||||
if (boot_mode == 2) {
|
||||
extern int video_menu(void);
|
||||
video_menu();
|
||||
@ -99,7 +97,6 @@ int kmain() {
|
||||
memset(cmdline, 0, 1024);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Build our command line. */
|
||||
strcat(cmdline, DEFAULT_ROOT_CMDLINE);
|
||||
@ -113,13 +110,13 @@ int kmain() {
|
||||
if (boot_mode == 1) {
|
||||
strcat(cmdline, DEFAULT_GRAPHICAL_CMDLINE);
|
||||
strcat(cmdline, _video_command_line);
|
||||
} else if (boot_mode == 2) {
|
||||
strcat(cmdline, DEFAULT_TEXT_CMDLINE);
|
||||
} else if (boot_mode == 3) {
|
||||
strcat(cmdline, DEFAULT_SINGLE_CMDLINE);
|
||||
strcat(cmdline, _video_command_line);
|
||||
} else if (boot_mode == 4) {
|
||||
strcat(cmdline, DEFAULT_HEADLESS_CMDLINE);
|
||||
} else if (boot_mode == 5) {
|
||||
strcat(cmdline, DEFAULT_TEXT_CMDLINE);
|
||||
}
|
||||
|
||||
if (_debug) {
|
||||
|
120
boot/multiboot.c
120
boot/multiboot.c
@ -289,124 +289,6 @@ static void finish_boot(void) {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void mode_selector(int sel, int ndx, char *str) {
|
||||
set_attr(sel == ndx ? 0x70 : 0x07);
|
||||
print_(str);
|
||||
if (x < 40) {
|
||||
while (x < 39) {
|
||||
print_(" ");
|
||||
}
|
||||
x = 40;
|
||||
} else {
|
||||
print_("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static char * print_int_into(char * str, unsigned int value) {
|
||||
unsigned int n_width = 1;
|
||||
unsigned int i = 9;
|
||||
while (value > i && i < UINT32_MAX) {
|
||||
n_width += 1;
|
||||
i *= 10;
|
||||
i += 9;
|
||||
}
|
||||
|
||||
char buf[n_width+1];
|
||||
for (int i = 0; i < n_width + 1; i++) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
i = n_width;
|
||||
while (i > 0) {
|
||||
unsigned int n = value / 10;
|
||||
int r = value % 10;
|
||||
buf[i - 1] = r + '0';
|
||||
i--;
|
||||
value = n;
|
||||
}
|
||||
for (char * c = buf; *c; c++) {
|
||||
*str++ = *c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int video_menu(void) {
|
||||
clear_();
|
||||
|
||||
int sel = 0;
|
||||
int sel_max = GOP->Mode->MaxMode;
|
||||
int select_this_mode = 0;
|
||||
|
||||
do {
|
||||
move_cursor(0,0);
|
||||
set_attr(0x1f);
|
||||
print_banner("Select Video Mode");
|
||||
set_attr(0x07);
|
||||
print_("\n");
|
||||
|
||||
for (int i = 0; i < GOP->Mode->MaxMode; ++i) {
|
||||
EFI_STATUS status;
|
||||
UINTN size;
|
||||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info;
|
||||
|
||||
status = uefi_call_wrapper(GOP->QueryMode,
|
||||
4, GOP, i, &size, &info);
|
||||
|
||||
if (EFI_ERROR(status) || info->PixelFormat != 1) {
|
||||
mode_selector(sel, i, "[invalid]");
|
||||
} else {
|
||||
|
||||
if (select_this_mode && sel == i) {
|
||||
uefi_call_wrapper(GOP->SetMode, 2, GOP, i);
|
||||
extern int init_graphics();
|
||||
init_graphics();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char tmp[100];
|
||||
char * t = tmp;
|
||||
t = print_int_into(t, info->HorizontalResolution); *t = 'x'; t++;
|
||||
t = print_int_into(t, info->VerticalResolution); *t = '\0';
|
||||
mode_selector(sel, i, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
int s = read_scancode(0);
|
||||
if (s == 0x50) { /* DOWN */
|
||||
if (sel >= 0 && sel < sel_max - 1) {
|
||||
sel = (sel + 2) % sel_max;
|
||||
} else {
|
||||
sel = (sel + 1) % sel_max;
|
||||
}
|
||||
} else if (s == 0x48) { /* UP */
|
||||
if (sel >= 1) {
|
||||
sel = (sel_max + sel - 2) % sel_max;
|
||||
} else {
|
||||
sel = (sel_max + sel - 1) % sel_max;
|
||||
}
|
||||
} else if (s == 0x4B) { /* LEFT */
|
||||
if (sel >= 0) {
|
||||
if ((sel + 1) % 2) {
|
||||
sel = (sel + 1) % sel_max;
|
||||
} else {
|
||||
sel -= 1;
|
||||
}
|
||||
}
|
||||
} else if (s == 0x4D) { /* RIGHT */
|
||||
if (sel >= 0) {
|
||||
if ((sel + 1) % 2) {
|
||||
sel = (sel + 1) % sel_max;
|
||||
} else {
|
||||
sel -= 1;
|
||||
}
|
||||
}
|
||||
} else if (s == 0x1c) {
|
||||
select_this_mode = 1;
|
||||
continue;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
}
|
||||
|
||||
void boot(void) {
|
||||
UINTN count;
|
||||
EFI_HANDLE * handles;
|
||||
@ -647,7 +529,7 @@ extern void bios_text_mode(void);
|
||||
|
||||
void boot(void) {
|
||||
/* Did we ask for VGA text mode and are currently in a video mode? */
|
||||
if (boot_mode == 2) {
|
||||
if (boot_mode == 5) {
|
||||
bios_text_mode();
|
||||
}
|
||||
|
||||
|
261
boot/video.c
Normal file
261
boot/video.c
Normal file
@ -0,0 +1,261 @@
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "kbd.h"
|
||||
|
||||
#ifdef EFI_PLATFORM
|
||||
#include <efi.h>
|
||||
extern EFI_SYSTEM_TABLE *ST;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
int platform_count_modes(void);
|
||||
int platform_list_modes(int sel, int select_this_mode);
|
||||
extern void init_graphics(void);
|
||||
|
||||
void mode_selector(int sel, int ndx, char *str) {
|
||||
set_attr(sel == ndx ? 0x70 : 0x07);
|
||||
print_(str);
|
||||
if (x < 26) {
|
||||
while (x < 25) {
|
||||
print_(" ");
|
||||
}
|
||||
x = 26;
|
||||
} else if (x < 52) {
|
||||
while (x < 51) {
|
||||
print_(" ");
|
||||
}
|
||||
x = 52;
|
||||
} else {
|
||||
print_("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static char * print_int_into(char * str, unsigned int value) {
|
||||
unsigned int n_width = 1;
|
||||
unsigned int i = 9;
|
||||
while (value > i && i < UINT32_MAX) {
|
||||
n_width += 1;
|
||||
i *= 10;
|
||||
i += 9;
|
||||
}
|
||||
|
||||
char buf[n_width+1];
|
||||
for (int i = 0; i < n_width + 1; i++) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
i = n_width;
|
||||
while (i > 0) {
|
||||
unsigned int n = value / 10;
|
||||
int r = value % 10;
|
||||
buf[i - 1] = r + '0';
|
||||
i--;
|
||||
value = n;
|
||||
}
|
||||
for (char * c = buf; *c; c++) {
|
||||
*str++ = *c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int video_menu(void) {
|
||||
clear_();
|
||||
|
||||
int sel = 0;
|
||||
int sel_max = platform_count_modes();
|
||||
int select_this_mode = 0;
|
||||
|
||||
int s = 0;
|
||||
|
||||
do {
|
||||
move_cursor(0,0);
|
||||
set_attr(0x1f);
|
||||
print_banner("Select Video Mode");
|
||||
set_attr(0x07);
|
||||
print_("\n");
|
||||
|
||||
if (platform_list_modes(sel,select_this_mode)) return 0;
|
||||
|
||||
read_again:
|
||||
s = read_scancode(0);
|
||||
if (s == 0x50) { /* DOWN */
|
||||
if (sel >= 0 && sel < sel_max - 1) {
|
||||
sel = (sel + 3) % sel_max;
|
||||
} else {
|
||||
sel = (sel + 1) % sel_max;
|
||||
}
|
||||
} else if (s == 0x48) { /* UP */
|
||||
if (sel >= 1) {
|
||||
sel = (sel_max + sel - 3) % sel_max;
|
||||
} else {
|
||||
sel = (sel_max + sel - 1) % sel_max;
|
||||
}
|
||||
} else if (s == 0x4B) { /* LEFT */
|
||||
if (sel >= 0) {
|
||||
if (sel % 3 != 0) {
|
||||
sel = (sel - 1) % sel_max;
|
||||
} else {
|
||||
sel += 2;
|
||||
}
|
||||
}
|
||||
} else if (s == 0x4D) { /* RIGHT */
|
||||
if (sel >= 0) {
|
||||
if (sel % 3 != 2) {
|
||||
sel = (sel + 1) % sel_max;
|
||||
} else {
|
||||
sel -= 2;
|
||||
}
|
||||
}
|
||||
} else if (s == 0x1c) {
|
||||
select_this_mode = 1;
|
||||
continue;
|
||||
} else {
|
||||
goto read_again;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
#ifdef EFI_PLATFORM
|
||||
extern EFI_GRAPHICS_OUTPUT_PROTOCOL * GOP;
|
||||
int platform_list_modes(int sel, int select_this_mode) {
|
||||
int index = 0;
|
||||
for (int i = 0; i < GOP->Mode->MaxMode; ++i) {
|
||||
EFI_STATUS status;
|
||||
UINTN size;
|
||||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info;
|
||||
|
||||
status = uefi_call_wrapper(GOP->QueryMode,
|
||||
4, GOP, i, &size, &info);
|
||||
|
||||
if (EFI_ERROR(status) || info->PixelFormat != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (select_this_mode && sel == index) {
|
||||
uefi_call_wrapper(GOP->SetMode, 2, GOP, i);
|
||||
init_graphics();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char tmp[100];
|
||||
char * t = tmp;
|
||||
t = print_int_into(t, info->HorizontalResolution); *t = 'x'; t++;
|
||||
t = print_int_into(t, info->VerticalResolution); *t = '\0';
|
||||
mode_selector(sel, index, tmp);
|
||||
index++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int platform_count_modes(void) {
|
||||
int index = 0;
|
||||
for (int i = 0; i < GOP->Mode->MaxMode; ++i) {
|
||||
EFI_STATUS status;
|
||||
UINTN size;
|
||||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info;
|
||||
status = uefi_call_wrapper(GOP->QueryMode,
|
||||
4, GOP, i, &size, &info);
|
||||
if (EFI_ERROR(status) || info->PixelFormat != 1) {
|
||||
continue;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
#else
|
||||
extern void do_bios_call(uint32_t function, uint32_t arg1);
|
||||
|
||||
extern uint32_t vbe_cont_info_mode_off;
|
||||
|
||||
struct ColorFormat {
|
||||
uint8_t mask;
|
||||
uint8_t offset;
|
||||
};
|
||||
|
||||
struct VbeMode {
|
||||
uint16_t attributes;
|
||||
uint16_t old_shit;
|
||||
uint16_t granularity;
|
||||
uint16_t window_size;
|
||||
uint32_t segments;
|
||||
uint32_t old_bank_switching_thing;
|
||||
uint16_t pitch;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t w_y;
|
||||
uint8_t planes;
|
||||
uint8_t bpp;
|
||||
uint8_t banks;
|
||||
uint8_t memory_model;
|
||||
uint8_t bank_size;
|
||||
uint8_t pages;
|
||||
uint8_t reserved;
|
||||
struct ColorFormat red;
|
||||
struct ColorFormat green;
|
||||
struct ColorFormat blue;
|
||||
struct ColorFormat alpha;
|
||||
uint8_t color_attributes;
|
||||
uint32_t framebuffer_addr;
|
||||
uint32_t memory_offset;
|
||||
uint32_t memory_size;
|
||||
uint8_t other[206];
|
||||
} __attribute__((packed));
|
||||
|
||||
extern volatile struct VbeMode vbe_info;
|
||||
static struct VbeMode vbe_info_save;
|
||||
|
||||
static int qualified(void) {
|
||||
if (!(vbe_info.attributes & (1 << 7))) return 0;
|
||||
if (vbe_info.bpp < 24) return 0;
|
||||
if (vbe_info.width < 640) return 0;
|
||||
if (vbe_info.height < 480) return 0;
|
||||
}
|
||||
|
||||
static char tmp[40];
|
||||
|
||||
int platform_list_modes(int sel, int select_this_mode) {
|
||||
uint32_t vbe_addr = ((vbe_cont_info_mode_off & 0xFFFF0000) >> 12) + (vbe_cont_info_mode_off & 0xFFFF);
|
||||
memcpy(&vbe_info_save, (char*)&vbe_info, sizeof(struct VbeMode));
|
||||
int index = 0;
|
||||
for (uint16_t * x = (uint16_t*)vbe_addr; *x != 0xFFFF; x++) {
|
||||
do_bios_call(2, *x);
|
||||
if (!qualified()) {
|
||||
memcpy((char*)&vbe_info, &vbe_info_save, sizeof(struct VbeMode));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (select_this_mode && sel == index) {
|
||||
do_bios_call(3, *x | 0x4000);
|
||||
init_graphics();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * t = tmp;
|
||||
t = print_int_into(t, vbe_info.width); *t = 'x'; t++;
|
||||
t = print_int_into(t, vbe_info.height); *t = 'x'; t++;
|
||||
t = print_int_into(t, vbe_info.bpp); *t = '\0';
|
||||
|
||||
memcpy((char*)&vbe_info, &vbe_info_save, sizeof(struct VbeMode));
|
||||
|
||||
mode_selector(sel, index, tmp);
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int platform_count_modes(void) {
|
||||
uint32_t vbe_addr = ((vbe_cont_info_mode_off & 0xFFFF0000) >> 12) + (vbe_cont_info_mode_off & 0xFFFF);
|
||||
int count = 0;
|
||||
memcpy(&vbe_info_save, (char*)&vbe_info, sizeof(struct VbeMode));
|
||||
for (uint16_t * x = (uint16_t*)vbe_addr; *x != 0xFFFF; x++) {
|
||||
do_bios_call(2, *x);
|
||||
if (!qualified()) continue;
|
||||
count++;
|
||||
}
|
||||
memcpy((char*)&vbe_info, &vbe_info_save, sizeof(struct VbeMode));
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user