Home | History | Annotate | Line # | Download | only in efiboot
eficons.c revision 1.3.6.1
      1  1.3.6.1  pgoyette /*	$NetBSD: eficons.c,v 1.3.6.1 2017/05/02 03:19:17 pgoyette Exp $	*/
      2      1.1    nonaka 
      3      1.1    nonaka /*-
      4      1.1    nonaka  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5      1.1    nonaka  * All rights reserved.
      6      1.1    nonaka  *
      7      1.1    nonaka  * Redistribution and use in source and binary forms, with or without
      8      1.1    nonaka  * modification, are permitted provided that the following conditions
      9      1.1    nonaka  * are met:
     10      1.1    nonaka  * 1. Redistributions of source code must retain the above copyright
     11      1.1    nonaka  *    notice, this list of conditions and the following disclaimer.
     12      1.1    nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1    nonaka  *    notice, this list of conditions and the following disclaimer in the
     14      1.1    nonaka  *    documentation and/or other materials provided with the distribution.
     15      1.1    nonaka  *
     16      1.1    nonaka  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17      1.1    nonaka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18      1.1    nonaka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19      1.1    nonaka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20      1.1    nonaka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21      1.1    nonaka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22      1.1    nonaka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23      1.1    nonaka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24      1.1    nonaka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25      1.1    nonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26      1.1    nonaka  * SUCH DAMAGE.
     27      1.1    nonaka  */
     28      1.1    nonaka 
     29      1.1    nonaka #include <sys/bitops.h>
     30      1.1    nonaka #include <sys/stdint.h>
     31      1.1    nonaka 
     32      1.1    nonaka #include "efiboot.h"
     33      1.1    nonaka 
     34      1.1    nonaka #include "bootinfo.h"
     35      1.1    nonaka #include "vbe.h"
     36      1.1    nonaka 
     37  1.3.6.1  pgoyette extern struct x86_boot_params boot_params;
     38  1.3.6.1  pgoyette 
     39      1.1    nonaka struct btinfo_console btinfo_console;
     40      1.1    nonaka 
     41      1.1    nonaka static EFI_GRAPHICS_OUTPUT_PROTOCOL *efi_gop;
     42      1.1    nonaka static int efi_gop_mode = -1;
     43      1.1    nonaka 
     44      1.1    nonaka static CHAR16 keybuf[16];
     45      1.1    nonaka static int keybuf_read = 0;
     46      1.1    nonaka static int keybuf_write = 0;
     47      1.1    nonaka 
     48      1.1    nonaka static void eficons_init_video(void);
     49      1.1    nonaka static void efi_switch_video_to_text_mode(void);
     50      1.1    nonaka 
     51  1.3.6.1  pgoyette static int
     52  1.3.6.1  pgoyette getcomaddr(int idx)
     53  1.3.6.1  pgoyette {
     54  1.3.6.1  pgoyette 	static const short comioport[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     55  1.3.6.1  pgoyette 
     56  1.3.6.1  pgoyette 	if (idx < __arraycount(comioport))
     57  1.3.6.1  pgoyette 		return comioport[idx];
     58  1.3.6.1  pgoyette 	return 0;
     59  1.3.6.1  pgoyette }
     60  1.3.6.1  pgoyette 
     61  1.3.6.1  pgoyette /*
     62  1.3.6.1  pgoyette  * XXX only pass console parameters to kernel.
     63  1.3.6.1  pgoyette  */
     64  1.3.6.1  pgoyette void
     65  1.3.6.1  pgoyette consinit(int dev, int ioport, int speed)
     66  1.3.6.1  pgoyette {
     67  1.3.6.1  pgoyette 	int iodev;
     68  1.3.6.1  pgoyette 
     69  1.3.6.1  pgoyette #if defined(CONSPEED)
     70  1.3.6.1  pgoyette 	btinfo_console.speed = CONSPEED;
     71  1.3.6.1  pgoyette #else
     72  1.3.6.1  pgoyette 	btinfo_console.speed = 9600;
     73  1.3.6.1  pgoyette #endif
     74  1.3.6.1  pgoyette 
     75  1.3.6.1  pgoyette 	switch (dev) {
     76  1.3.6.1  pgoyette 	case CONSDEV_AUTO:
     77  1.3.6.1  pgoyette 		/* XXX comport */
     78  1.3.6.1  pgoyette 		goto nocom;
     79  1.3.6.1  pgoyette 
     80  1.3.6.1  pgoyette 	case CONSDEV_COM0:
     81  1.3.6.1  pgoyette 	case CONSDEV_COM1:
     82  1.3.6.1  pgoyette 	case CONSDEV_COM2:
     83  1.3.6.1  pgoyette 	case CONSDEV_COM3:
     84  1.3.6.1  pgoyette 		iodev = dev;
     85  1.3.6.1  pgoyette comport:
     86  1.3.6.1  pgoyette 		btinfo_console.addr = ioport;
     87  1.3.6.1  pgoyette 		if (btinfo_console.addr == 0) {
     88  1.3.6.1  pgoyette 			btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
     89  1.3.6.1  pgoyette 			if (btinfo_console.addr == 0)
     90  1.3.6.1  pgoyette 				goto nocom;
     91  1.3.6.1  pgoyette 		}
     92  1.3.6.1  pgoyette 		if (speed != 0)
     93  1.3.6.1  pgoyette 			btinfo_console.speed = speed;
     94  1.3.6.1  pgoyette 		break;
     95  1.3.6.1  pgoyette 
     96  1.3.6.1  pgoyette 	case CONSDEV_COM0KBD:
     97  1.3.6.1  pgoyette 	case CONSDEV_COM1KBD:
     98  1.3.6.1  pgoyette 	case CONSDEV_COM2KBD:
     99  1.3.6.1  pgoyette 	case CONSDEV_COM3KBD:
    100  1.3.6.1  pgoyette 		iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
    101  1.3.6.1  pgoyette 		goto comport;	/* XXX kbd */
    102  1.3.6.1  pgoyette 
    103  1.3.6.1  pgoyette 	case CONSDEV_PC:
    104  1.3.6.1  pgoyette 	default:
    105  1.3.6.1  pgoyette nocom:
    106  1.3.6.1  pgoyette 		iodev = CONSDEV_PC;
    107  1.3.6.1  pgoyette 		break;
    108  1.3.6.1  pgoyette 	}
    109  1.3.6.1  pgoyette 
    110  1.3.6.1  pgoyette 	strlcpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
    111  1.3.6.1  pgoyette }
    112  1.3.6.1  pgoyette 
    113      1.1    nonaka int
    114      1.1    nonaka cninit(void)
    115      1.1    nonaka {
    116      1.1    nonaka 
    117      1.1    nonaka 	efi_switch_video_to_text_mode();
    118      1.1    nonaka 	eficons_init_video();
    119      1.1    nonaka 
    120  1.3.6.1  pgoyette 	consinit(boot_params.bp_consdev, boot_params.bp_consaddr,
    121  1.3.6.1  pgoyette 	    boot_params.bp_conspeed);
    122      1.1    nonaka 
    123      1.1    nonaka 	return 0;
    124      1.1    nonaka }
    125      1.1    nonaka 
    126      1.1    nonaka int
    127      1.1    nonaka getchar(void)
    128      1.1    nonaka {
    129      1.1    nonaka 	EFI_STATUS status;
    130      1.1    nonaka 	EFI_INPUT_KEY key;
    131      1.1    nonaka 	int c;
    132      1.1    nonaka 
    133      1.1    nonaka 	if (keybuf_read != keybuf_write) {
    134      1.1    nonaka 		c = keybuf[keybuf_read];
    135      1.1    nonaka 		keybuf_read = (keybuf_read + 1) % __arraycount(keybuf);
    136      1.1    nonaka 		return c;
    137      1.1    nonaka 	}
    138      1.1    nonaka 
    139      1.1    nonaka 	status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
    140      1.1    nonaka 	    &key);
    141      1.1    nonaka 	while (status == EFI_NOT_READY) {
    142      1.1    nonaka 		WaitForSingleEvent(ST->ConIn->WaitForKey, 0);
    143      1.1    nonaka 		status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
    144      1.1    nonaka 		    ST->ConIn, &key);
    145      1.1    nonaka 	}
    146      1.1    nonaka 	return key.UnicodeChar;
    147      1.1    nonaka }
    148      1.1    nonaka 
    149      1.1    nonaka void
    150      1.1    nonaka putchar(int c)
    151      1.1    nonaka {
    152      1.1    nonaka 	CHAR16 buf[2];
    153      1.1    nonaka 
    154      1.1    nonaka 	buf[1] = 0;
    155      1.1    nonaka 	if (c == '\n') {
    156      1.1    nonaka 		buf[0] = '\r';
    157      1.1    nonaka 		Output(buf);
    158      1.1    nonaka 	}
    159      1.1    nonaka 	buf[0] = c;
    160      1.1    nonaka 	Output(buf);
    161      1.1    nonaka }
    162      1.1    nonaka 
    163      1.1    nonaka /*ARGSUSED*/
    164      1.1    nonaka int
    165      1.1    nonaka iskey(int intr)
    166      1.1    nonaka {
    167      1.1    nonaka 	EFI_STATUS status;
    168      1.1    nonaka 	EFI_INPUT_KEY key;
    169      1.1    nonaka 
    170      1.1    nonaka 	if (keybuf_read != keybuf_write)
    171      1.1    nonaka 		return 1;
    172      1.1    nonaka 
    173      1.1    nonaka 	status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
    174      1.1    nonaka 	    &key);
    175      1.1    nonaka 	if (EFI_ERROR(status))
    176      1.1    nonaka 		return 0;
    177      1.1    nonaka 
    178      1.1    nonaka 	keybuf[keybuf_write] = key.UnicodeChar;
    179      1.1    nonaka 	keybuf_write = (keybuf_write + 1) % __arraycount(keybuf);
    180      1.1    nonaka 	return 1;
    181      1.1    nonaka }
    182      1.1    nonaka 
    183      1.1    nonaka char
    184      1.1    nonaka awaitkey(int timeout, int tell)
    185      1.1    nonaka {
    186      1.1    nonaka 	char c = 0;
    187      1.1    nonaka 
    188      1.1    nonaka 	for (;;) {
    189      1.1    nonaka 		if (tell) {
    190      1.1    nonaka 			char numbuf[32];
    191      1.1    nonaka 			int len;
    192      1.1    nonaka 
    193      1.1    nonaka 			len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ",
    194      1.1    nonaka 			    timeout);
    195      1.1    nonaka 			if (len > 0 && len < sizeof(numbuf)) {
    196      1.1    nonaka 				char *p = numbuf;
    197      1.1    nonaka 
    198      1.1    nonaka 				printf("%s", numbuf);
    199      1.1    nonaka 				while (*p)
    200      1.1    nonaka 					*p++ = '\b';
    201      1.1    nonaka 				printf("%s", numbuf);
    202      1.1    nonaka 			}
    203      1.1    nonaka 		}
    204      1.1    nonaka 		if (iskey(1)) {
    205      1.1    nonaka 			/* flush input buffer */
    206      1.1    nonaka 			while (iskey(0))
    207      1.1    nonaka 				c = getchar();
    208      1.1    nonaka 			if (c == 0)
    209      1.1    nonaka 				c = -1;
    210      1.1    nonaka 			goto out;
    211      1.1    nonaka 		}
    212      1.1    nonaka 		if (timeout--)
    213      1.1    nonaka 			WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000);
    214      1.1    nonaka 		else
    215      1.1    nonaka 			break;
    216      1.1    nonaka 	}
    217      1.1    nonaka 
    218      1.1    nonaka out:
    219      1.1    nonaka 	if (tell)
    220      1.1    nonaka 		printf("0 seconds.     \n");
    221      1.1    nonaka 
    222      1.1    nonaka 	return c;
    223      1.1    nonaka }
    224      1.1    nonaka 
    225      1.1    nonaka void
    226      1.1    nonaka clear_pc_screen(void)
    227      1.1    nonaka {
    228      1.1    nonaka 
    229      1.1    nonaka 	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
    230      1.1    nonaka }
    231      1.1    nonaka 
    232      1.1    nonaka static uint8_t
    233      1.1    nonaka getdepth(const EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info)
    234      1.1    nonaka {
    235      1.1    nonaka 
    236      1.1    nonaka 	switch (info->PixelFormat) {
    237      1.1    nonaka 	case PixelBlueGreenRedReserved8BitPerColor:
    238      1.1    nonaka 	case PixelRedGreenBlueReserved8BitPerColor:
    239      1.1    nonaka 		return 32;
    240      1.1    nonaka 
    241      1.1    nonaka 	case PixelBitMask:
    242      1.1    nonaka 		return fls32(info->PixelInformation.RedMask
    243      1.1    nonaka 		    | info->PixelInformation.GreenMask
    244      1.1    nonaka 		    | info->PixelInformation.BlueMask
    245      1.1    nonaka 		    | info->PixelInformation.ReservedMask);
    246      1.1    nonaka 
    247      1.1    nonaka 	case PixelBltOnly:
    248      1.1    nonaka 	case PixelFormatMax:
    249      1.1    nonaka 		return 0;
    250      1.1    nonaka 	}
    251      1.1    nonaka 	return 0;
    252      1.1    nonaka }
    253      1.1    nonaka 
    254      1.1    nonaka static void
    255      1.1    nonaka setpixelformat(UINT32 mask, uint8_t *num, uint8_t *pos)
    256      1.1    nonaka {
    257      1.1    nonaka 	uint8_t n, p;
    258      1.1    nonaka 
    259      1.1    nonaka 	n = popcount32(mask);
    260      1.1    nonaka 	p = ffs32(mask);
    261      1.1    nonaka 	if (p > 0)
    262      1.1    nonaka 		p--;
    263      1.1    nonaka 
    264      1.1    nonaka 	*num = n;
    265      1.1    nonaka 	*pos = p;
    266      1.1    nonaka }
    267      1.1    nonaka 
    268      1.1    nonaka static void
    269      1.1    nonaka bi_framebuffer(void)
    270      1.1    nonaka {
    271      1.1    nonaka 	EFI_STATUS status;
    272      1.1    nonaka 	EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
    273      1.1    nonaka 	struct btinfo_framebuffer fb;
    274      1.1    nonaka 	INT32 bestmode = -1;
    275      1.1    nonaka 
    276      1.1    nonaka 	if (efi_gop == NULL) {
    277      1.1    nonaka 		framebuffer_configure(NULL);
    278      1.1    nonaka 		return;
    279      1.1    nonaka 	}
    280      1.1    nonaka 
    281      1.1    nonaka 	if (efi_gop_mode >= 0) {
    282      1.1    nonaka 		bestmode = efi_gop_mode;
    283      1.1    nonaka 	} else {
    284      1.2    nonaka #if 0
    285      1.2    nonaka 		UINT64 res, bestres = 0;
    286      1.2    nonaka 		UINTN sz;
    287      1.2    nonaka 		UINT32 i;
    288      1.2    nonaka 
    289      1.2    nonaka 		/* XXX EDID? EFI_EDID_DISCOVERED_PROTOCOL */
    290      1.1    nonaka 		for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
    291      1.1    nonaka 			status = uefi_call_wrapper(efi_gop->QueryMode, 4,
    292      1.1    nonaka 			    efi_gop, i, &sz, &info);
    293      1.1    nonaka 			if (EFI_ERROR(status))
    294      1.1    nonaka 				continue;
    295      1.1    nonaka 
    296      1.1    nonaka 			res = (UINT64)info->HorizontalResolution *
    297      1.1    nonaka 			    (UINT64)info->VerticalResolution *
    298      1.1    nonaka 			    (UINT64)getdepth(info);
    299      1.1    nonaka 			if (res > bestres) {
    300      1.1    nonaka 				bestmode = i;
    301      1.1    nonaka 				bestres = res;
    302      1.1    nonaka 			}
    303      1.1    nonaka 		}
    304      1.2    nonaka #endif
    305      1.1    nonaka 	}
    306      1.1    nonaka 	if (bestmode >= 0) {
    307      1.1    nonaka 		status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop,
    308      1.1    nonaka 		    bestmode);
    309      1.1    nonaka 		if (EFI_ERROR(status) || efi_gop->Mode->Mode != bestmode)
    310      1.1    nonaka 			Print(L"GOP setmode failed: %r\n", status);
    311      1.1    nonaka 	}
    312      1.1    nonaka 
    313      1.1    nonaka 	info = efi_gop->Mode->Info;
    314      1.1    nonaka 	memset(&fb, 0, sizeof(fb));
    315      1.1    nonaka 	fb.physaddr = efi_gop->Mode->FrameBufferBase;
    316      1.1    nonaka 	fb.flags = 0;
    317      1.1    nonaka 	fb.width = info->HorizontalResolution;
    318      1.1    nonaka 	fb.height = info->VerticalResolution;
    319      1.1    nonaka 	fb.depth = getdepth(info);
    320      1.1    nonaka 	fb.stride = info->PixelsPerScanLine * ((fb.depth + 7) / 8);
    321      1.1    nonaka 	fb.vbemode = 0;	/* XXX */
    322      1.1    nonaka 
    323      1.1    nonaka 	switch (info->PixelFormat) {
    324      1.1    nonaka 	case PixelBlueGreenRedReserved8BitPerColor:
    325      1.1    nonaka 		fb.rnum = 8;
    326      1.1    nonaka 		fb.gnum = 8;
    327      1.1    nonaka 		fb.bnum = 8;
    328      1.1    nonaka 		fb.rpos = 16;
    329      1.1    nonaka 		fb.gpos = 8;
    330      1.1    nonaka 		fb.bpos = 0;
    331      1.1    nonaka 		break;
    332      1.1    nonaka 
    333      1.1    nonaka 	case PixelRedGreenBlueReserved8BitPerColor:
    334      1.1    nonaka 		fb.rnum = 8;
    335      1.1    nonaka 		fb.gnum = 8;
    336      1.1    nonaka 		fb.bnum = 8;
    337      1.1    nonaka 		fb.rpos = 0;
    338      1.1    nonaka 		fb.gpos = 8;
    339      1.1    nonaka 		fb.bpos = 16;
    340      1.1    nonaka 		break;
    341      1.1    nonaka 
    342      1.1    nonaka 	case PixelBitMask:
    343      1.1    nonaka 		setpixelformat(info->PixelInformation.RedMask,
    344      1.1    nonaka 		    &fb.rnum, &fb.rpos);
    345      1.1    nonaka 		setpixelformat(info->PixelInformation.GreenMask,
    346      1.1    nonaka 		    &fb.gnum, &fb.gpos);
    347      1.1    nonaka 		setpixelformat(info->PixelInformation.BlueMask,
    348      1.1    nonaka 		    &fb.bnum, &fb.bpos);
    349      1.1    nonaka 		break;
    350      1.1    nonaka 
    351      1.1    nonaka 	case PixelBltOnly:
    352      1.1    nonaka 	case PixelFormatMax:
    353      1.1    nonaka 		Panic(L"Error: invalid pixel format (%d)", info->PixelFormat);
    354      1.1    nonaka 		break;
    355      1.1    nonaka 	}
    356      1.1    nonaka 
    357      1.1    nonaka 	framebuffer_configure(&fb);
    358      1.1    nonaka }
    359      1.1    nonaka 
    360      1.1    nonaka int
    361      1.1    nonaka vbe_commit(void)
    362      1.1    nonaka {
    363      1.1    nonaka 
    364      1.1    nonaka 	bi_framebuffer();
    365      1.1    nonaka 	return 0;
    366      1.1    nonaka }
    367      1.1    nonaka 
    368      1.1    nonaka static void
    369      1.1    nonaka print_text_modes(void)
    370      1.1    nonaka {
    371      1.1    nonaka 	EFI_STATUS status;
    372      1.1    nonaka 	UINTN cols, rows;
    373      1.1    nonaka 	INT32 i, curmode;
    374      1.1    nonaka 
    375      1.1    nonaka 	curmode = ST->ConOut->Mode->Mode;
    376      1.1    nonaka 	for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
    377      1.1    nonaka 		status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
    378      1.1    nonaka 		    ST->ConOut, i, &cols, &rows);
    379      1.1    nonaka 		if (EFI_ERROR(status))
    380      1.1    nonaka 			continue;
    381      1.1    nonaka 		Print(L"%c%d: %dx%d\n", i == curmode ? '*' : ' ',
    382      1.1    nonaka 		    i, cols, rows);
    383      1.1    nonaka 	}
    384      1.1    nonaka }
    385      1.1    nonaka 
    386      1.1    nonaka static int
    387      1.1    nonaka efi_find_text_mode(char *arg)
    388      1.1    nonaka {
    389      1.1    nonaka 	EFI_STATUS status;
    390      1.1    nonaka 	UINTN cols, rows;
    391      1.1    nonaka 	INT32 i;
    392      1.1    nonaka 	char mode[32];
    393      1.1    nonaka 
    394      1.1    nonaka 	for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
    395      1.1    nonaka 		status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
    396      1.1    nonaka 		    ST->ConOut, i, &cols, &rows);
    397      1.1    nonaka 		if (EFI_ERROR(status))
    398      1.1    nonaka 			continue;
    399      1.1    nonaka 		snprintf(mode, sizeof(mode), "%lux%lu", (long)cols, (long)rows);
    400      1.1    nonaka 		if (strcmp(arg, mode) == 0)
    401      1.1    nonaka 			return i;
    402      1.1    nonaka 	}
    403      1.1    nonaka 	return -1;
    404      1.1    nonaka }
    405      1.1    nonaka 
    406      1.1    nonaka void
    407      1.1    nonaka command_text(char *arg)
    408      1.1    nonaka {
    409      1.1    nonaka 	EFI_STATUS status;
    410      1.1    nonaka 	INT32 modenum;
    411      1.1    nonaka 
    412      1.1    nonaka 	if (*arg == '\0' || strcmp(arg, "list") == 0) {
    413      1.1    nonaka 		print_text_modes();
    414      1.1    nonaka 		return;
    415      1.1    nonaka 	}
    416      1.1    nonaka 
    417      1.1    nonaka 	if (strchr(arg, 'x') != NULL) {
    418      1.1    nonaka 		modenum = efi_find_text_mode(arg);
    419      1.1    nonaka 		if (modenum == -1) {
    420      1.1    nonaka 			printf("mode %s not supported by firmware\n", arg);
    421      1.1    nonaka 			return;
    422      1.1    nonaka 		}
    423      1.1    nonaka 	} else {
    424      1.1    nonaka 		modenum = strtoul(arg, NULL, 0);
    425      1.1    nonaka 	}
    426      1.1    nonaka 
    427      1.1    nonaka 	status = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, modenum);
    428      1.1    nonaka 	if (!EFI_ERROR(status))
    429      1.1    nonaka 		return;
    430      1.1    nonaka 
    431      1.1    nonaka 	printf("invalid flag, must be 'list', a display mode, "
    432      1.1    nonaka 	    "or a mode number\n");
    433      1.1    nonaka }
    434      1.1    nonaka 
    435      1.1    nonaka static int
    436      1.1    nonaka print_gop_modes(void)
    437      1.1    nonaka {
    438      1.1    nonaka 	EFI_STATUS status;
    439      1.1    nonaka 	EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
    440      1.1    nonaka 	UINTN sz;
    441      1.1    nonaka 	UINT32 i;
    442      1.1    nonaka 	uint8_t depth;
    443      1.1    nonaka 
    444      1.1    nonaka 	if (efi_gop == NULL)
    445      1.1    nonaka 		return 1;
    446      1.1    nonaka 
    447      1.1    nonaka 	for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
    448      1.1    nonaka 		status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i,
    449      1.1    nonaka 		    &sz, &info);
    450      1.1    nonaka 		if (EFI_ERROR(status) && status == EFI_NOT_STARTED) {
    451      1.1    nonaka 			status = uefi_call_wrapper(efi_gop->SetMode, 2,
    452      1.1    nonaka 			    efi_gop, efi_gop->Mode->Mode);
    453      1.1    nonaka 			status = uefi_call_wrapper(efi_gop->QueryMode, 4,
    454      1.1    nonaka 			    efi_gop, i, &sz, &info);
    455      1.1    nonaka 		}
    456      1.1    nonaka 		if (EFI_ERROR(status))
    457      1.1    nonaka 			continue;
    458      1.1    nonaka 
    459      1.1    nonaka 		Print(L"%c%d: %dx%d ",
    460      1.1    nonaka 		    memcmp(info, efi_gop->Mode->Info, sizeof(*info)) == 0 ?
    461      1.1    nonaka 		      '*' : ' ',
    462      1.1    nonaka 		      i, info->HorizontalResolution, info->VerticalResolution);
    463      1.1    nonaka 		switch (info->PixelFormat) {
    464      1.1    nonaka 		case PixelRedGreenBlueReserved8BitPerColor:
    465      1.1    nonaka 			Print(L"RGBR");
    466      1.1    nonaka 			break;
    467      1.1    nonaka 		case PixelBlueGreenRedReserved8BitPerColor:
    468      1.1    nonaka 			Print(L"BGRR");
    469      1.1    nonaka 			break;
    470      1.1    nonaka 		case PixelBitMask:
    471      1.1    nonaka 			Print(L"R:%08x G:%08x B:%08x X:%08x",
    472      1.1    nonaka 			    info->PixelInformation.RedMask,
    473      1.1    nonaka 			    info->PixelInformation.GreenMask,
    474      1.1    nonaka 			    info->PixelInformation.BlueMask,
    475      1.1    nonaka 			    info->PixelInformation.ReservedMask);
    476      1.1    nonaka 			break;
    477      1.1    nonaka 		case PixelBltOnly:
    478      1.1    nonaka 			Print(L"(blt only)");
    479      1.1    nonaka 			break;
    480      1.1    nonaka 		default:
    481      1.1    nonaka 			Print(L"(Invalid pixel format)");
    482      1.1    nonaka 			break;
    483      1.1    nonaka 		}
    484      1.1    nonaka 		Print(L" pitch %d", info->PixelsPerScanLine);
    485      1.1    nonaka 		depth = getdepth(info);
    486      1.1    nonaka 		if (depth > 0)
    487      1.1    nonaka 			Print(L" bpp %d", depth);
    488      1.1    nonaka 		Print(L"\n");
    489      1.1    nonaka 	}
    490      1.1    nonaka 
    491      1.1    nonaka 	return 0;
    492      1.1    nonaka }
    493      1.1    nonaka 
    494      1.1    nonaka static int
    495      1.1    nonaka efi_find_gop_mode(char *arg)
    496      1.1    nonaka {
    497      1.1    nonaka 	EFI_STATUS status;
    498      1.1    nonaka 	EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
    499      1.1    nonaka 	UINTN sz;
    500      1.1    nonaka 	UINT32 i;
    501      1.1    nonaka 	char mode[32];
    502      1.1    nonaka 	uint8_t depth;
    503      1.1    nonaka 
    504      1.1    nonaka 	for (i = 0; i < efi_gop->Mode->MaxMode; i++) {
    505      1.1    nonaka 		status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i,
    506      1.1    nonaka 		    &sz, &info);
    507      1.1    nonaka 		if (EFI_ERROR(status))
    508      1.1    nonaka 			continue;
    509      1.1    nonaka 
    510      1.1    nonaka 		depth = getdepth(info);
    511      1.1    nonaka 		if (depth == 0)
    512      1.1    nonaka 			continue;
    513      1.1    nonaka 
    514      1.1    nonaka 		snprintf(mode, sizeof(mode), "%lux%lux%u",
    515      1.1    nonaka 		    (long)info->HorizontalResolution,
    516      1.1    nonaka 		    (long)info->HorizontalResolution,
    517      1.1    nonaka 		    depth);
    518      1.1    nonaka 		if (strcmp(arg, mode) == 0)
    519      1.1    nonaka 			return i;
    520      1.1    nonaka 	}
    521      1.1    nonaka 	return -1;
    522      1.1    nonaka }
    523      1.1    nonaka 
    524      1.1    nonaka void
    525      1.1    nonaka command_gop(char *arg)
    526      1.1    nonaka {
    527      1.1    nonaka 	EFI_STATUS status;
    528      1.1    nonaka 	INT32 modenum;
    529      1.1    nonaka 
    530      1.1    nonaka 	if (efi_gop == NULL) {
    531      1.1    nonaka 		printf("GOP not supported by firmware\n");
    532      1.1    nonaka 		return;
    533      1.1    nonaka 	}
    534      1.1    nonaka 
    535      1.1    nonaka 	if (*arg == '\0' || strcmp(arg, "list") == 0) {
    536      1.1    nonaka 		print_gop_modes();
    537      1.1    nonaka 		return;
    538      1.1    nonaka 	}
    539      1.1    nonaka 
    540      1.1    nonaka 	if (strchr(arg, 'x') != NULL) {
    541      1.1    nonaka 		modenum = efi_find_gop_mode(arg);
    542      1.1    nonaka 		if (modenum == -1) {
    543      1.1    nonaka 			printf("mode %s not supported by firmware\n", arg);
    544      1.1    nonaka 			return;
    545      1.1    nonaka 		}
    546      1.1    nonaka 	} else {
    547      1.1    nonaka 		modenum = strtoul(arg, NULL, 0);
    548      1.1    nonaka 	}
    549      1.1    nonaka 
    550      1.1    nonaka 	status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop, modenum);
    551      1.1    nonaka 	if (!EFI_ERROR(status) && efi_gop->Mode->Mode == modenum) {
    552      1.1    nonaka 		efi_gop_mode = modenum;
    553      1.1    nonaka 		return;
    554      1.1    nonaka 	}
    555      1.1    nonaka 
    556      1.1    nonaka 	printf("invalid flag, must be 'list', a display mode, "
    557      1.1    nonaka 	    "or a mode number\n");
    558      1.1    nonaka }
    559      1.1    nonaka 
    560      1.1    nonaka static void
    561      1.1    nonaka eficons_init_video(void)
    562      1.1    nonaka {
    563      1.1    nonaka 	EFI_STATUS status;
    564      1.3    nonaka 	UINTN cols, rows;
    565      1.3    nonaka 	INT32 i, best, mode80x25, mode100x31;
    566      1.1    nonaka 
    567      1.1    nonaka 	/*
    568      1.1    nonaka 	 * Setup text mode
    569      1.1    nonaka 	 */
    570      1.1    nonaka 	uefi_call_wrapper(ST->ConOut->Reset, 2, ST->ConOut, TRUE);
    571      1.1    nonaka 
    572      1.3    nonaka 	mode80x25 = mode100x31 = -1;
    573      1.1    nonaka 	for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) {
    574      1.1    nonaka 		status = uefi_call_wrapper(ST->ConOut->QueryMode, 4,
    575      1.1    nonaka 		    ST->ConOut, i, &cols, &rows);
    576      1.1    nonaka 		if (EFI_ERROR(status))
    577      1.1    nonaka 			continue;
    578      1.3    nonaka 
    579      1.3    nonaka 		if (mode80x25 < 0 && cols == 80 && rows == 25)
    580      1.3    nonaka 			mode80x25 = i;
    581      1.3    nonaka 		else if (mode100x31 < 0 && cols == 100 && rows == 31)
    582      1.3    nonaka 			mode100x31 = i;
    583      1.1    nonaka 	}
    584      1.3    nonaka 	best = mode100x31 >= 0 ? mode100x31 : mode80x25 >= 0 ? mode80x25 : -1;
    585      1.1    nonaka 	if (best >= 0)
    586      1.1    nonaka 		uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, best);
    587      1.1    nonaka 	uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
    588      1.1    nonaka 	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
    589      1.1    nonaka 
    590      1.1    nonaka 	LibLocateProtocol(&GraphicsOutputProtocol, (void **)&efi_gop);
    591      1.1    nonaka }
    592      1.1    nonaka 
    593      1.1    nonaka /*
    594      1.1    nonaka  * for Apple EFI
    595      1.1    nonaka  */
    596      1.1    nonaka #define	CONSOLE_CONTROL_PROTOCOL \
    597      1.1    nonaka 	{0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21}}
    598      1.1    nonaka static EFI_GUID ConsoleControlProtocol = CONSOLE_CONTROL_PROTOCOL;
    599      1.1    nonaka 
    600      1.1    nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE;
    601      1.1    nonaka typedef struct _EFI_CONSOLE_CONTROL_INTERFACE EFI_CONSOLE_CONTROL_INTERFACE;
    602      1.1    nonaka typedef enum { EfiConsoleControlScreenText } EFI_CONSOLE_CONTROL_SCREEN_MODE;
    603      1.1    nonaka typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
    604      1.1    nonaka 	IN EFI_CONSOLE_CONTROL_INTERFACE *This,
    605      1.1    nonaka 	IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
    606      1.1    nonaka );
    607      1.1    nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE {
    608      1.1    nonaka 	VOID *GetMode;
    609      1.1    nonaka 	EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
    610      1.1    nonaka 	VOID *LockStdIn;
    611      1.1    nonaka };
    612      1.1    nonaka 
    613      1.1    nonaka static void
    614      1.1    nonaka efi_switch_video_to_text_mode(void)
    615      1.1    nonaka {
    616      1.1    nonaka 	EFI_STATUS status;
    617      1.1    nonaka 	EFI_CONSOLE_CONTROL_INTERFACE *cci;
    618      1.1    nonaka 
    619      1.1    nonaka 	/* Set up the console, so printf works. */
    620      1.1    nonaka 	status = LibLocateProtocol(&ConsoleControlProtocol, (void **)&cci);
    621      1.1    nonaka 	if (!EFI_ERROR(status)) {
    622      1.1    nonaka 		uefi_call_wrapper(cci->SetMode, 2, cci,
    623      1.1    nonaka 		    EfiConsoleControlScreenText);
    624      1.1    nonaka 	}
    625      1.1    nonaka }
    626