cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

video.c (7248B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* -*- linux-c -*- ------------------------------------------------------- *
      3 *
      4 *   Copyright (C) 1991, 1992 Linus Torvalds
      5 *   Copyright 2007 rPath, Inc. - All Rights Reserved
      6 *   Copyright 2009 Intel Corporation; author H. Peter Anvin
      7 *
      8 * ----------------------------------------------------------------------- */
      9
     10/*
     11 * Select video mode
     12 */
     13
     14#include <uapi/asm/boot.h>
     15
     16#include "boot.h"
     17#include "video.h"
     18#include "vesa.h"
     19
     20static u16 video_segment;
     21
     22static void store_cursor_position(void)
     23{
     24	struct biosregs ireg, oreg;
     25
     26	initregs(&ireg);
     27	ireg.ah = 0x03;
     28	intcall(0x10, &ireg, &oreg);
     29
     30	boot_params.screen_info.orig_x = oreg.dl;
     31	boot_params.screen_info.orig_y = oreg.dh;
     32
     33	if (oreg.ch & 0x20)
     34		boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
     35
     36	if ((oreg.ch & 0x1f) > (oreg.cl & 0x1f))
     37		boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
     38}
     39
     40static void store_video_mode(void)
     41{
     42	struct biosregs ireg, oreg;
     43
     44	/* N.B.: the saving of the video page here is a bit silly,
     45	   since we pretty much assume page 0 everywhere. */
     46	initregs(&ireg);
     47	ireg.ah = 0x0f;
     48	intcall(0x10, &ireg, &oreg);
     49
     50	/* Not all BIOSes are clean with respect to the top bit */
     51	boot_params.screen_info.orig_video_mode = oreg.al & 0x7f;
     52	boot_params.screen_info.orig_video_page = oreg.bh;
     53}
     54
     55/*
     56 * Store the video mode parameters for later usage by the kernel.
     57 * This is done by asking the BIOS except for the rows/columns
     58 * parameters in the default 80x25 mode -- these are set directly,
     59 * because some very obscure BIOSes supply insane values.
     60 */
     61static void store_mode_params(void)
     62{
     63	u16 font_size;
     64	int x, y;
     65
     66	/* For graphics mode, it is up to the mode-setting driver
     67	   (currently only video-vesa.c) to store the parameters */
     68	if (graphic_mode)
     69		return;
     70
     71	store_cursor_position();
     72	store_video_mode();
     73
     74	if (boot_params.screen_info.orig_video_mode == 0x07) {
     75		/* MDA, HGC, or VGA in monochrome mode */
     76		video_segment = 0xb000;
     77	} else {
     78		/* CGA, EGA, VGA and so forth */
     79		video_segment = 0xb800;
     80	}
     81
     82	set_fs(0);
     83	font_size = rdfs16(0x485); /* Font size, BIOS area */
     84	boot_params.screen_info.orig_video_points = font_size;
     85
     86	x = rdfs16(0x44a);
     87	y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1;
     88
     89	if (force_x)
     90		x = force_x;
     91	if (force_y)
     92		y = force_y;
     93
     94	boot_params.screen_info.orig_video_cols  = x;
     95	boot_params.screen_info.orig_video_lines = y;
     96}
     97
     98static unsigned int get_entry(void)
     99{
    100	char entry_buf[4];
    101	int i, len = 0;
    102	int key;
    103	unsigned int v;
    104
    105	do {
    106		key = getchar();
    107
    108		if (key == '\b') {
    109			if (len > 0) {
    110				puts("\b \b");
    111				len--;
    112			}
    113		} else if ((key >= '0' && key <= '9') ||
    114			   (key >= 'A' && key <= 'Z') ||
    115			   (key >= 'a' && key <= 'z')) {
    116			if (len < sizeof(entry_buf)) {
    117				entry_buf[len++] = key;
    118				putchar(key);
    119			}
    120		}
    121	} while (key != '\r');
    122	putchar('\n');
    123
    124	if (len == 0)
    125		return VIDEO_CURRENT_MODE; /* Default */
    126
    127	v = 0;
    128	for (i = 0; i < len; i++) {
    129		v <<= 4;
    130		key = entry_buf[i] | 0x20;
    131		v += (key > '9') ? key-'a'+10 : key-'0';
    132	}
    133
    134	return v;
    135}
    136
    137static void display_menu(void)
    138{
    139	struct card_info *card;
    140	struct mode_info *mi;
    141	char ch;
    142	int i;
    143	int nmodes;
    144	int modes_per_line;
    145	int col;
    146
    147	nmodes = 0;
    148	for (card = video_cards; card < video_cards_end; card++)
    149		nmodes += card->nmodes;
    150
    151	modes_per_line = 1;
    152	if (nmodes >= 20)
    153		modes_per_line = 3;
    154
    155	for (col = 0; col < modes_per_line; col++)
    156		puts("Mode: Resolution:  Type: ");
    157	putchar('\n');
    158
    159	col = 0;
    160	ch = '0';
    161	for (card = video_cards; card < video_cards_end; card++) {
    162		mi = card->modes;
    163		for (i = 0; i < card->nmodes; i++, mi++) {
    164			char resbuf[32];
    165			int visible = mi->x && mi->y;
    166			u16 mode_id = mi->mode ? mi->mode :
    167				(mi->y << 8)+mi->x;
    168
    169			if (!visible)
    170				continue; /* Hidden mode */
    171
    172			if (mi->depth)
    173				sprintf(resbuf, "%dx%d", mi->y, mi->depth);
    174			else
    175				sprintf(resbuf, "%d", mi->y);
    176
    177			printf("%c %03X %4dx%-7s %-6s",
    178			       ch, mode_id, mi->x, resbuf, card->card_name);
    179			col++;
    180			if (col >= modes_per_line) {
    181				putchar('\n');
    182				col = 0;
    183			}
    184
    185			if (ch == '9')
    186				ch = 'a';
    187			else if (ch == 'z' || ch == ' ')
    188				ch = ' '; /* Out of keys... */
    189			else
    190				ch++;
    191		}
    192	}
    193	if (col)
    194		putchar('\n');
    195}
    196
    197#define H(x)	((x)-'a'+10)
    198#define SCAN	((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n'))
    199
    200static unsigned int mode_menu(void)
    201{
    202	int key;
    203	unsigned int sel;
    204
    205	puts("Press <ENTER> to see video modes available, "
    206	     "<SPACE> to continue, or wait 30 sec\n");
    207
    208	kbd_flush();
    209	while (1) {
    210		key = getchar_timeout();
    211		if (key == ' ' || key == 0)
    212			return VIDEO_CURRENT_MODE; /* Default */
    213		if (key == '\r')
    214			break;
    215		putchar('\a');	/* Beep! */
    216	}
    217
    218
    219	for (;;) {
    220		display_menu();
    221
    222		puts("Enter a video mode or \"scan\" to scan for "
    223		     "additional modes: ");
    224		sel = get_entry();
    225		if (sel != SCAN)
    226			return sel;
    227
    228		probe_cards(1);
    229	}
    230}
    231
    232/* Save screen content to the heap */
    233static struct saved_screen {
    234	int x, y;
    235	int curx, cury;
    236	u16 *data;
    237} saved;
    238
    239static void save_screen(void)
    240{
    241	/* Should be called after store_mode_params() */
    242	saved.x = boot_params.screen_info.orig_video_cols;
    243	saved.y = boot_params.screen_info.orig_video_lines;
    244	saved.curx = boot_params.screen_info.orig_x;
    245	saved.cury = boot_params.screen_info.orig_y;
    246
    247	if (!heap_free(saved.x*saved.y*sizeof(u16)+512))
    248		return;		/* Not enough heap to save the screen */
    249
    250	saved.data = GET_HEAP(u16, saved.x*saved.y);
    251
    252	set_fs(video_segment);
    253	copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16));
    254}
    255
    256static void restore_screen(void)
    257{
    258	/* Should be called after store_mode_params() */
    259	int xs = boot_params.screen_info.orig_video_cols;
    260	int ys = boot_params.screen_info.orig_video_lines;
    261	int y;
    262	addr_t dst = 0;
    263	u16 *src = saved.data;
    264	struct biosregs ireg;
    265
    266	if (graphic_mode)
    267		return;		/* Can't restore onto a graphic mode */
    268
    269	if (!src)
    270		return;		/* No saved screen contents */
    271
    272	/* Restore screen contents */
    273
    274	set_fs(video_segment);
    275	for (y = 0; y < ys; y++) {
    276		int npad;
    277
    278		if (y < saved.y) {
    279			int copy = (xs < saved.x) ? xs : saved.x;
    280			copy_to_fs(dst, src, copy*sizeof(u16));
    281			dst += copy*sizeof(u16);
    282			src += saved.x;
    283			npad = (xs < saved.x) ? 0 : xs-saved.x;
    284		} else {
    285			npad = xs;
    286		}
    287
    288		/* Writes "npad" blank characters to
    289		   video_segment:dst and advances dst */
    290		asm volatile("pushw %%es ; "
    291			     "movw %2,%%es ; "
    292			     "shrw %%cx ; "
    293			     "jnc 1f ; "
    294			     "stosw \n\t"
    295			     "1: rep;stosl ; "
    296			     "popw %%es"
    297			     : "+D" (dst), "+c" (npad)
    298			     : "bdS" (video_segment),
    299			       "a" (0x07200720));
    300	}
    301
    302	/* Restore cursor position */
    303	if (saved.curx >= xs)
    304		saved.curx = xs-1;
    305	if (saved.cury >= ys)
    306		saved.cury = ys-1;
    307
    308	initregs(&ireg);
    309	ireg.ah = 0x02;		/* Set cursor position */
    310	ireg.dh = saved.cury;
    311	ireg.dl = saved.curx;
    312	intcall(0x10, &ireg, NULL);
    313
    314	store_cursor_position();
    315}
    316
    317void set_video(void)
    318{
    319	u16 mode = boot_params.hdr.vid_mode;
    320
    321	RESET_HEAP();
    322
    323	store_mode_params();
    324	save_screen();
    325	probe_cards(0);
    326
    327	for (;;) {
    328		if (mode == ASK_VGA)
    329			mode = mode_menu();
    330
    331		if (!set_mode(mode))
    332			break;
    333
    334		printf("Undefined video mode number: %x\n", mode);
    335		mode = ASK_VGA;
    336	}
    337	boot_params.hdr.vid_mode = mode;
    338	vesa_store_edid();
    339	store_mode_params();
    340
    341	if (do_restore)
    342		restore_screen();
    343}