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. */
|
/* Names of the available boot modes. */
|
||||||
struct bootmode boot_mode_names[] = {
|
struct bootmode boot_mode_names[] = {
|
||||||
{1, "normal", "Normal Boot"},
|
{1, "normal", "Normal Boot"},
|
||||||
#ifdef EFI_PLATFORM
|
|
||||||
{2, "video", "Configure Video Output"},
|
{2, "video", "Configure Video Output"},
|
||||||
#else
|
|
||||||
{2, "vga", "VGA Text Mode"},
|
|
||||||
#endif
|
|
||||||
{3, "single", "Single-User Graphical Terminal"},
|
{3, "single", "Single-User Graphical Terminal"},
|
||||||
{4, "headless", "Headless"},
|
{4, "headless", "Headless"},
|
||||||
|
#ifndef EFI_PLATFORM
|
||||||
|
{5, "vga", "VGA Text Mode"},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
int base_sel = 0;
|
int base_sel = 0;
|
||||||
@ -91,7 +90,6 @@ int kmain() {
|
|||||||
/* Loop over rendering the menu */
|
/* Loop over rendering the menu */
|
||||||
show_menu();
|
show_menu();
|
||||||
|
|
||||||
#ifdef EFI_PLATFORM
|
|
||||||
if (boot_mode == 2) {
|
if (boot_mode == 2) {
|
||||||
extern int video_menu(void);
|
extern int video_menu(void);
|
||||||
video_menu();
|
video_menu();
|
||||||
@ -99,7 +97,6 @@ int kmain() {
|
|||||||
memset(cmdline, 0, 1024);
|
memset(cmdline, 0, 1024);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Build our command line. */
|
/* Build our command line. */
|
||||||
strcat(cmdline, DEFAULT_ROOT_CMDLINE);
|
strcat(cmdline, DEFAULT_ROOT_CMDLINE);
|
||||||
@ -113,13 +110,13 @@ int kmain() {
|
|||||||
if (boot_mode == 1) {
|
if (boot_mode == 1) {
|
||||||
strcat(cmdline, DEFAULT_GRAPHICAL_CMDLINE);
|
strcat(cmdline, DEFAULT_GRAPHICAL_CMDLINE);
|
||||||
strcat(cmdline, _video_command_line);
|
strcat(cmdline, _video_command_line);
|
||||||
} else if (boot_mode == 2) {
|
|
||||||
strcat(cmdline, DEFAULT_TEXT_CMDLINE);
|
|
||||||
} else if (boot_mode == 3) {
|
} else if (boot_mode == 3) {
|
||||||
strcat(cmdline, DEFAULT_SINGLE_CMDLINE);
|
strcat(cmdline, DEFAULT_SINGLE_CMDLINE);
|
||||||
strcat(cmdline, _video_command_line);
|
strcat(cmdline, _video_command_line);
|
||||||
} else if (boot_mode == 4) {
|
} else if (boot_mode == 4) {
|
||||||
strcat(cmdline, DEFAULT_HEADLESS_CMDLINE);
|
strcat(cmdline, DEFAULT_HEADLESS_CMDLINE);
|
||||||
|
} else if (boot_mode == 5) {
|
||||||
|
strcat(cmdline, DEFAULT_TEXT_CMDLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_debug) {
|
if (_debug) {
|
||||||
|
120
boot/multiboot.c
120
boot/multiboot.c
@ -289,124 +289,6 @@ static void finish_boot(void) {
|
|||||||
__builtin_unreachable();
|
__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) {
|
void boot(void) {
|
||||||
UINTN count;
|
UINTN count;
|
||||||
EFI_HANDLE * handles;
|
EFI_HANDLE * handles;
|
||||||
@ -647,7 +529,7 @@ extern void bios_text_mode(void);
|
|||||||
|
|
||||||
void boot(void) {
|
void boot(void) {
|
||||||
/* Did we ask for VGA text mode and are currently in a video mode? */
|
/* 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();
|
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