xref: /illumos-gate/usr/src/cmd/bhyve/pci_fbuf.c (revision 32640292)
14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2015 Nahanni Systems, Inc.
54c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
637fc8a1fSAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
74c87aefeSPatrick Mooney  * All rights reserved.
84c87aefeSPatrick Mooney  *
94c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
104c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
114c87aefeSPatrick Mooney  * are met:
124c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
144c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
154c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
164c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
174c87aefeSPatrick Mooney  *
184c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
194c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
204c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
214c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
224c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
234c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
244c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
254c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
264c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
274c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
284c87aefeSPatrick Mooney  * SUCH DAMAGE.
294c87aefeSPatrick Mooney  */
304c87aefeSPatrick Mooney 
314c87aefeSPatrick Mooney #include <sys/cdefs.h>
324c87aefeSPatrick Mooney 
334c87aefeSPatrick Mooney #include <sys/types.h>
344c87aefeSPatrick Mooney #include <sys/mman.h>
354c87aefeSPatrick Mooney 
364c87aefeSPatrick Mooney #include <machine/vmm.h>
374c87aefeSPatrick Mooney #include <vmmapi.h>
384c87aefeSPatrick Mooney 
394c87aefeSPatrick Mooney #include <stdio.h>
404c87aefeSPatrick Mooney #include <stdlib.h>
414c87aefeSPatrick Mooney #include <string.h>
424c87aefeSPatrick Mooney 
434c87aefeSPatrick Mooney #include <errno.h>
444c87aefeSPatrick Mooney #include <unistd.h>
454c87aefeSPatrick Mooney 
464c87aefeSPatrick Mooney #include "bhyvegc.h"
474c87aefeSPatrick Mooney #include "bhyverun.h"
482b948146SAndy Fiddaman #include "config.h"
49154972afSPatrick Mooney #include "debug.h"
504c87aefeSPatrick Mooney #include "console.h"
514c87aefeSPatrick Mooney #include "inout.h"
524c87aefeSPatrick Mooney #include "pci_emul.h"
534c87aefeSPatrick Mooney #include "rfb.h"
544c87aefeSPatrick Mooney #include "vga.h"
554c87aefeSPatrick Mooney 
564c87aefeSPatrick Mooney /*
574c87aefeSPatrick Mooney  * bhyve Framebuffer device emulation.
584c87aefeSPatrick Mooney  * BAR0 points to the current mode information.
594c87aefeSPatrick Mooney  * BAR1 is the 32-bit framebuffer address.
604c87aefeSPatrick Mooney  *
614c87aefeSPatrick Mooney  *  -s <b>,fbuf,wait,vga=on|io|off,rfb=<ip>:port,w=width,h=height
624c87aefeSPatrick Mooney  */
634c87aefeSPatrick Mooney 
644c87aefeSPatrick Mooney static int fbuf_debug = 1;
654c87aefeSPatrick Mooney #define	DEBUG_INFO	1
664c87aefeSPatrick Mooney #define	DEBUG_VERBOSE	4
67154972afSPatrick Mooney #define	DPRINTF(level, params)  if (level <= fbuf_debug) PRINTLN params
684c87aefeSPatrick Mooney 
694c87aefeSPatrick Mooney 
704c87aefeSPatrick Mooney #define	KB	(1024UL)
714c87aefeSPatrick Mooney #define	MB	(1024 * 1024UL)
724c87aefeSPatrick Mooney 
734c87aefeSPatrick Mooney #define	DMEMSZ	128
744c87aefeSPatrick Mooney 
754c87aefeSPatrick Mooney #define	FB_SIZE		(16*MB)
764c87aefeSPatrick Mooney 
774c87aefeSPatrick Mooney #define COLS_MAX	1920
784c87aefeSPatrick Mooney #define	ROWS_MAX	1200
794c87aefeSPatrick Mooney 
804c87aefeSPatrick Mooney #define COLS_DEFAULT	1024
814c87aefeSPatrick Mooney #define ROWS_DEFAULT	768
824c87aefeSPatrick Mooney 
834c87aefeSPatrick Mooney #define COLS_MIN	640
844c87aefeSPatrick Mooney #define ROWS_MIN	480
854c87aefeSPatrick Mooney 
864c87aefeSPatrick Mooney struct pci_fbuf_softc {
874c87aefeSPatrick Mooney 	struct pci_devinst *fsc_pi;
884c87aefeSPatrick Mooney 	struct {
894c87aefeSPatrick Mooney 		uint32_t fbsize;
904c87aefeSPatrick Mooney 		uint16_t width;
914c87aefeSPatrick Mooney 		uint16_t height;
924c87aefeSPatrick Mooney 		uint16_t depth;
934c87aefeSPatrick Mooney 		uint16_t refreshrate;
944c87aefeSPatrick Mooney 		uint8_t  reserved[116];
954c87aefeSPatrick Mooney 	} __packed memregs;
964c87aefeSPatrick Mooney 
974c87aefeSPatrick Mooney 	/* rfb server */
984c87aefeSPatrick Mooney 	char      *rfb_host;
994c87aefeSPatrick Mooney 	char      *rfb_password;
1004c87aefeSPatrick Mooney 	int       rfb_port;
1014c87aefeSPatrick Mooney #ifndef __FreeBSD__
1022b948146SAndy Fiddaman 	const char *rfb_unix;
1034c87aefeSPatrick Mooney #endif
1044c87aefeSPatrick Mooney 	int       rfb_wait;
1054c87aefeSPatrick Mooney 	int       vga_enabled;
1064c87aefeSPatrick Mooney 	int	  vga_full;
1074c87aefeSPatrick Mooney 
1084c87aefeSPatrick Mooney 	uint32_t  fbaddr;
1094c87aefeSPatrick Mooney 	char      *fb_base;
1104c87aefeSPatrick Mooney 	uint16_t  gc_width;
1114c87aefeSPatrick Mooney 	uint16_t  gc_height;
1124c87aefeSPatrick Mooney 	void      *vgasc;
1134c87aefeSPatrick Mooney 	struct bhyvegc_image *gc_image;
1144c87aefeSPatrick Mooney };
1154c87aefeSPatrick Mooney 
1164c87aefeSPatrick Mooney static struct pci_fbuf_softc *fbuf_sc;
1174c87aefeSPatrick Mooney 
1184c87aefeSPatrick Mooney #define	PCI_FBUF_MSI_MSGS	 4
1194c87aefeSPatrick Mooney 
1204c87aefeSPatrick Mooney static void
pci_fbuf_write(struct pci_devinst * pi,int baridx,uint64_t offset,int size,uint64_t value)121*32640292SAndy Fiddaman pci_fbuf_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size,
12259d65d31SAndy Fiddaman     uint64_t value)
1234c87aefeSPatrick Mooney {
1244c87aefeSPatrick Mooney 	struct pci_fbuf_softc *sc;
1254c87aefeSPatrick Mooney 	uint8_t *p;
1264c87aefeSPatrick Mooney 
1274c87aefeSPatrick Mooney 	assert(baridx == 0);
1284c87aefeSPatrick Mooney 
1294c87aefeSPatrick Mooney 	sc = pi->pi_arg;
1304c87aefeSPatrick Mooney 
1314c87aefeSPatrick Mooney 	DPRINTF(DEBUG_VERBOSE,
132154972afSPatrick Mooney 	    ("fbuf wr: offset 0x%lx, size: %d, value: 0x%lx",
1334c87aefeSPatrick Mooney 	    offset, size, value));
1344c87aefeSPatrick Mooney 
1354c87aefeSPatrick Mooney 	if (offset + size > DMEMSZ) {
1364c87aefeSPatrick Mooney 		printf("fbuf: write too large, offset %ld size %d\n",
1374c87aefeSPatrick Mooney 		       offset, size);
1384c87aefeSPatrick Mooney 		return;
1394c87aefeSPatrick Mooney 	}
1404c87aefeSPatrick Mooney 
1414c87aefeSPatrick Mooney 	p = (uint8_t *)&sc->memregs + offset;
1424c87aefeSPatrick Mooney 
1434c87aefeSPatrick Mooney 	switch (size) {
1444c87aefeSPatrick Mooney 	case 1:
1454c87aefeSPatrick Mooney 		*p = value;
1464c87aefeSPatrick Mooney 		break;
1474c87aefeSPatrick Mooney 	case 2:
1484c87aefeSPatrick Mooney 		*(uint16_t *)p = value;
1494c87aefeSPatrick Mooney 		break;
1504c87aefeSPatrick Mooney 	case 4:
1514c87aefeSPatrick Mooney 		*(uint32_t *)p = value;
1524c87aefeSPatrick Mooney 		break;
1534c87aefeSPatrick Mooney 	case 8:
1544c87aefeSPatrick Mooney 		*(uint64_t *)p = value;
1554c87aefeSPatrick Mooney 		break;
1564c87aefeSPatrick Mooney 	default:
1574c87aefeSPatrick Mooney 		printf("fbuf: write unknown size %d\n", size);
1584c87aefeSPatrick Mooney 		break;
1594c87aefeSPatrick Mooney 	}
1604c87aefeSPatrick Mooney 
1614c87aefeSPatrick Mooney 	if (!sc->gc_image->vgamode && sc->memregs.width == 0 &&
1624c87aefeSPatrick Mooney 	    sc->memregs.height == 0) {
163154972afSPatrick Mooney 		DPRINTF(DEBUG_INFO, ("switching to VGA mode"));
1644c87aefeSPatrick Mooney 		sc->gc_image->vgamode = 1;
1654c87aefeSPatrick Mooney 		sc->gc_width = 0;
1664c87aefeSPatrick Mooney 		sc->gc_height = 0;
1674c87aefeSPatrick Mooney 	} else if (sc->gc_image->vgamode && sc->memregs.width != 0 &&
1684c87aefeSPatrick Mooney 	    sc->memregs.height != 0) {
169154972afSPatrick Mooney 		DPRINTF(DEBUG_INFO, ("switching to VESA mode"));
1704c87aefeSPatrick Mooney 		sc->gc_image->vgamode = 0;
1714c87aefeSPatrick Mooney 	}
1724c87aefeSPatrick Mooney }
1734c87aefeSPatrick Mooney 
1744f3f3e9aSAndy Fiddaman static uint64_t
pci_fbuf_read(struct pci_devinst * pi,int baridx,uint64_t offset,int size)175*32640292SAndy Fiddaman pci_fbuf_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size)
1764c87aefeSPatrick Mooney {
1774c87aefeSPatrick Mooney 	struct pci_fbuf_softc *sc;
1784c87aefeSPatrick Mooney 	uint8_t *p;
1794c87aefeSPatrick Mooney 	uint64_t value;
1804c87aefeSPatrick Mooney 
1814c87aefeSPatrick Mooney 	assert(baridx == 0);
1824c87aefeSPatrick Mooney 
1834c87aefeSPatrick Mooney 	sc = pi->pi_arg;
1844c87aefeSPatrick Mooney 
1854c87aefeSPatrick Mooney 
1864c87aefeSPatrick Mooney 	if (offset + size > DMEMSZ) {
1874c87aefeSPatrick Mooney 		printf("fbuf: read too large, offset %ld size %d\n",
1884c87aefeSPatrick Mooney 		       offset, size);
1894c87aefeSPatrick Mooney 		return (0);
1904c87aefeSPatrick Mooney 	}
1914c87aefeSPatrick Mooney 
1924c87aefeSPatrick Mooney 	p = (uint8_t *)&sc->memregs + offset;
1934c87aefeSPatrick Mooney 	value = 0;
1944c87aefeSPatrick Mooney 	switch (size) {
1954c87aefeSPatrick Mooney 	case 1:
1964c87aefeSPatrick Mooney 		value = *p;
1974c87aefeSPatrick Mooney 		break;
1984c87aefeSPatrick Mooney 	case 2:
1994c87aefeSPatrick Mooney 		value = *(uint16_t *)p;
2004c87aefeSPatrick Mooney 		break;
2014c87aefeSPatrick Mooney 	case 4:
2024c87aefeSPatrick Mooney 		value = *(uint32_t *)p;
2034c87aefeSPatrick Mooney 		break;
2044c87aefeSPatrick Mooney 	case 8:
2054c87aefeSPatrick Mooney 		value = *(uint64_t *)p;
2064c87aefeSPatrick Mooney 		break;
2074c87aefeSPatrick Mooney 	default:
2084c87aefeSPatrick Mooney 		printf("fbuf: read unknown size %d\n", size);
2094c87aefeSPatrick Mooney 		break;
2104c87aefeSPatrick Mooney 	}
2114c87aefeSPatrick Mooney 
2124c87aefeSPatrick Mooney 	DPRINTF(DEBUG_VERBOSE,
213154972afSPatrick Mooney 	    ("fbuf rd: offset 0x%lx, size: %d, value: 0x%lx",
2144c87aefeSPatrick Mooney 	     offset, size, value));
2154c87aefeSPatrick Mooney 
2164c87aefeSPatrick Mooney 	return (value);
2174c87aefeSPatrick Mooney }
2184c87aefeSPatrick Mooney 
2192b948146SAndy Fiddaman static void
pci_fbuf_baraddr(struct pci_devinst * pi,int baridx,int enabled,uint64_t address)220*32640292SAndy Fiddaman pci_fbuf_baraddr(struct pci_devinst *pi, int baridx, int enabled,
221*32640292SAndy Fiddaman     uint64_t address)
2224c87aefeSPatrick Mooney {
2232b948146SAndy Fiddaman 	struct pci_fbuf_softc *sc;
2242b948146SAndy Fiddaman 	int prot;
2254c87aefeSPatrick Mooney 
2262b948146SAndy Fiddaman 	if (baridx != 1)
2272b948146SAndy Fiddaman 		return;
2284c87aefeSPatrick Mooney 
2292b948146SAndy Fiddaman 	sc = pi->pi_arg;
2306dc98349SAndy Fiddaman 	if (!enabled) {
231*32640292SAndy Fiddaman 		if (vm_munmap_memseg(pi->pi_vmctx, sc->fbaddr, FB_SIZE) != 0)
2322b948146SAndy Fiddaman 			EPRINTLN("pci_fbuf: munmap_memseg failed");
2332b948146SAndy Fiddaman 		sc->fbaddr = 0;
2346dc98349SAndy Fiddaman 	} else {
2352b948146SAndy Fiddaman 		prot = PROT_READ | PROT_WRITE;
236*32640292SAndy Fiddaman 		if (vm_mmap_memseg(pi->pi_vmctx, address, VM_FRAMEBUFFER, 0,
237*32640292SAndy Fiddaman 		    FB_SIZE, prot) != 0)
2382b948146SAndy Fiddaman 			EPRINTLN("pci_fbuf: mmap_memseg failed");
2392b948146SAndy Fiddaman 		sc->fbaddr = address;
2402b948146SAndy Fiddaman 	}
2412b948146SAndy Fiddaman }
2422b948146SAndy Fiddaman 
2432b948146SAndy Fiddaman 
2442b948146SAndy Fiddaman static int
pci_fbuf_parse_config(struct pci_fbuf_softc * sc,nvlist_t * nvl)2452b948146SAndy Fiddaman pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl)
2462b948146SAndy Fiddaman {
2472b948146SAndy Fiddaman 	const char *value;
2482b948146SAndy Fiddaman 	char *cp;
2492b948146SAndy Fiddaman 
2502b948146SAndy Fiddaman 	sc->rfb_wait = get_config_bool_node_default(nvl, "wait", false);
2512b948146SAndy Fiddaman 
2522b948146SAndy Fiddaman 	/* Prefer "rfb" to "tcp". */
2532b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "rfb");
2542b948146SAndy Fiddaman 	if (value == NULL)
2552b948146SAndy Fiddaman 		value = get_config_value_node(nvl, "tcp");
2562b948146SAndy Fiddaman 	if (value != NULL) {
2572b948146SAndy Fiddaman 		/*
2582b948146SAndy Fiddaman 		 * IPv4 -- host-ip:port
2592b948146SAndy Fiddaman 		 * IPv6 -- [host-ip%zone]:port
2602b948146SAndy Fiddaman 		 * XXX for now port is mandatory for IPv4.
2612b948146SAndy Fiddaman 		 */
2622b948146SAndy Fiddaman 		if (value[0] == '[') {
2632b948146SAndy Fiddaman 			cp = strchr(value + 1, ']');
2642b948146SAndy Fiddaman 			if (cp == NULL || cp == value + 1) {
2652b948146SAndy Fiddaman 				EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"",
2662b948146SAndy Fiddaman 				    value);
2672b948146SAndy Fiddaman 				return (-1);
2682b948146SAndy Fiddaman 			}
2692b948146SAndy Fiddaman 			sc->rfb_host = strndup(value + 1, cp - (value + 1));
2702b948146SAndy Fiddaman 			cp++;
2712b948146SAndy Fiddaman 			if (*cp == ':') {
2722b948146SAndy Fiddaman 				cp++;
2732b948146SAndy Fiddaman 				if (*cp == '\0') {
2742b948146SAndy Fiddaman 					EPRINTLN(
2752b948146SAndy Fiddaman 					    "fbuf: Missing port number: \"%s\"",
2762b948146SAndy Fiddaman 					    value);
2772b948146SAndy Fiddaman 					return (-1);
2784c87aefeSPatrick Mooney 				}
2792b948146SAndy Fiddaman 				sc->rfb_port = atoi(cp);
2802b948146SAndy Fiddaman 			} else if (*cp != '\0') {
2812b948146SAndy Fiddaman 				EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"",
2822b948146SAndy Fiddaman 				    value);
2832b948146SAndy Fiddaman 				return (-1);
2842b948146SAndy Fiddaman 			}
2852b948146SAndy Fiddaman 		} else {
2862b948146SAndy Fiddaman 			cp = strchr(value, ':');
2872b948146SAndy Fiddaman 			if (cp == NULL) {
2882b948146SAndy Fiddaman 				sc->rfb_port = atoi(value);
2894c87aefeSPatrick Mooney 			} else {
2902b948146SAndy Fiddaman 				sc->rfb_host = strndup(value, cp - value);
2912b948146SAndy Fiddaman 				cp++;
2922b948146SAndy Fiddaman 				if (*cp == '\0') {
2932b948146SAndy Fiddaman 					EPRINTLN(
2942b948146SAndy Fiddaman 					    "fbuf: Missing port number: \"%s\"",
2952b948146SAndy Fiddaman 					    value);
2962b948146SAndy Fiddaman 					return (-1);
2974c87aefeSPatrick Mooney 				}
2982b948146SAndy Fiddaman 				sc->rfb_port = atoi(cp);
2994c87aefeSPatrick Mooney 			}
3002b948146SAndy Fiddaman 		}
3012b948146SAndy Fiddaman 	}
3022b948146SAndy Fiddaman 
3034c87aefeSPatrick Mooney #ifndef __FreeBSD__
3042b948146SAndy Fiddaman 	sc->rfb_unix = get_config_value_node(nvl, "unix");
3054c87aefeSPatrick Mooney #endif
3062b948146SAndy Fiddaman 
3072b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "vga");
3082b948146SAndy Fiddaman 	if (value != NULL) {
3092b948146SAndy Fiddaman 		if (strcmp(value, "off") == 0) {
3102b948146SAndy Fiddaman 			sc->vga_enabled = 0;
3112b948146SAndy Fiddaman 		} else if (strcmp(value, "io") == 0) {
3122b948146SAndy Fiddaman 			sc->vga_enabled = 1;
3132b948146SAndy Fiddaman 			sc->vga_full = 0;
3142b948146SAndy Fiddaman 		} else if (strcmp(value, "on") == 0) {
3152b948146SAndy Fiddaman 			sc->vga_enabled = 1;
3162b948146SAndy Fiddaman 			sc->vga_full = 1;
3174c87aefeSPatrick Mooney 		} else {
3182b948146SAndy Fiddaman 			EPRINTLN("fbuf: Invalid vga setting: \"%s\"", value);
3192b948146SAndy Fiddaman 			return (-1);
3204c87aefeSPatrick Mooney 		}
3214c87aefeSPatrick Mooney 	}
3224c87aefeSPatrick Mooney 
3232b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "w");
3242b948146SAndy Fiddaman 	if (value != NULL) {
3252b948146SAndy Fiddaman 		sc->memregs.width = atoi(value);
3262b948146SAndy Fiddaman 		if (sc->memregs.width > COLS_MAX) {
3272b948146SAndy Fiddaman 			EPRINTLN("fbuf: width %d too large", sc->memregs.width);
3282b948146SAndy Fiddaman 			return (-1);
3292b948146SAndy Fiddaman 		}
3302b948146SAndy Fiddaman 		if (sc->memregs.width == 0)
3312b948146SAndy Fiddaman 			sc->memregs.width = 1920;
3322b948146SAndy Fiddaman 	}
3332b948146SAndy Fiddaman 
3342b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "h");
3352b948146SAndy Fiddaman 	if (value != NULL) {
3362b948146SAndy Fiddaman 		sc->memregs.height = atoi(value);
3372b948146SAndy Fiddaman 		if (sc->memregs.height > ROWS_MAX) {
3382b948146SAndy Fiddaman 			EPRINTLN("fbuf: height %d too large",
3392b948146SAndy Fiddaman 			    sc->memregs.height);
3402b948146SAndy Fiddaman 			return (-1);
3412b948146SAndy Fiddaman 		}
3422b948146SAndy Fiddaman 		if (sc->memregs.height == 0)
3432b948146SAndy Fiddaman 			sc->memregs.height = 1080;
3442b948146SAndy Fiddaman 	}
3452b948146SAndy Fiddaman 
3462b948146SAndy Fiddaman 	value = get_config_value_node(nvl, "password");
3472b948146SAndy Fiddaman 	if (value != NULL)
3482b948146SAndy Fiddaman 		sc->rfb_password = strdup(value);
3492b948146SAndy Fiddaman 
3502b948146SAndy Fiddaman 	return (0);
3514c87aefeSPatrick Mooney }
3524c87aefeSPatrick Mooney 
3534c87aefeSPatrick Mooney 
3544c87aefeSPatrick Mooney extern void vga_render(struct bhyvegc *gc, void *arg);
3554c87aefeSPatrick Mooney 
3564f3f3e9aSAndy Fiddaman static void
pci_fbuf_render(struct bhyvegc * gc,void * arg)3574c87aefeSPatrick Mooney pci_fbuf_render(struct bhyvegc *gc, void *arg)
3584c87aefeSPatrick Mooney {
3594c87aefeSPatrick Mooney 	struct pci_fbuf_softc *sc;
3604c87aefeSPatrick Mooney 
3614c87aefeSPatrick Mooney 	sc = arg;
3624c87aefeSPatrick Mooney 
3634c87aefeSPatrick Mooney 	if (sc->vga_full && sc->gc_image->vgamode) {
3644c87aefeSPatrick Mooney 		/* TODO: mode switching to vga and vesa should use the special
3654c87aefeSPatrick Mooney 		 *      EFI-bhyve protocol port.
3664c87aefeSPatrick Mooney 		 */
3674c87aefeSPatrick Mooney 		vga_render(gc, sc->vgasc);
3684c87aefeSPatrick Mooney 		return;
3694c87aefeSPatrick Mooney 	}
3704c87aefeSPatrick Mooney 	if (sc->gc_width != sc->memregs.width ||
3714c87aefeSPatrick Mooney 	    sc->gc_height != sc->memregs.height) {
3724c87aefeSPatrick Mooney 		bhyvegc_resize(gc, sc->memregs.width, sc->memregs.height);
3734c87aefeSPatrick Mooney 		sc->gc_width = sc->memregs.width;
3744c87aefeSPatrick Mooney 		sc->gc_height = sc->memregs.height;
3754c87aefeSPatrick Mooney 	}
3764c87aefeSPatrick Mooney }
3774c87aefeSPatrick Mooney 
3784c87aefeSPatrick Mooney static int
pci_fbuf_init(struct pci_devinst * pi,nvlist_t * nvl)379*32640292SAndy Fiddaman pci_fbuf_init(struct pci_devinst *pi, nvlist_t *nvl)
3804c87aefeSPatrick Mooney {
3816dc98349SAndy Fiddaman 	int error;
3824c87aefeSPatrick Mooney 	struct pci_fbuf_softc *sc;
3836dc98349SAndy Fiddaman 
3844c87aefeSPatrick Mooney 	if (fbuf_sc != NULL) {
385154972afSPatrick Mooney 		EPRINTLN("Only one frame buffer device is allowed.");
3864c87aefeSPatrick Mooney 		return (-1);
3874c87aefeSPatrick Mooney 	}
3884c87aefeSPatrick Mooney 
3894c87aefeSPatrick Mooney 	sc = calloc(1, sizeof(struct pci_fbuf_softc));
3904c87aefeSPatrick Mooney 
3914c87aefeSPatrick Mooney 	pi->pi_arg = sc;
3924c87aefeSPatrick Mooney 
3934c87aefeSPatrick Mooney 	/* initialize config space */
3944c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x40FB);
3954c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D);
3964c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY);
3974c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA);
3984c87aefeSPatrick Mooney 
399*32640292SAndy Fiddaman 	sc->fb_base = vm_create_devmem(pi->pi_vmctx, VM_FRAMEBUFFER,
400*32640292SAndy Fiddaman 	    "framebuffer", FB_SIZE);
4016dc98349SAndy Fiddaman 	if (sc->fb_base == MAP_FAILED) {
4026dc98349SAndy Fiddaman 		error = -1;
4036dc98349SAndy Fiddaman 		goto done;
4046dc98349SAndy Fiddaman 	}
4056dc98349SAndy Fiddaman 
4064c87aefeSPatrick Mooney 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ);
4074c87aefeSPatrick Mooney 	assert(error == 0);
4084c87aefeSPatrick Mooney 
4094c87aefeSPatrick Mooney 	error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, FB_SIZE);
4104c87aefeSPatrick Mooney 	assert(error == 0);
4114c87aefeSPatrick Mooney 
4124c87aefeSPatrick Mooney 	error = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS);
4134c87aefeSPatrick Mooney 	assert(error == 0);
4144c87aefeSPatrick Mooney 
4154c87aefeSPatrick Mooney 	sc->memregs.fbsize = FB_SIZE;
4164c87aefeSPatrick Mooney 	sc->memregs.width  = COLS_DEFAULT;
4174c87aefeSPatrick Mooney 	sc->memregs.height = ROWS_DEFAULT;
4184c87aefeSPatrick Mooney 	sc->memregs.depth  = 32;
4194c87aefeSPatrick Mooney 
4204c87aefeSPatrick Mooney 	sc->vga_enabled = 1;
4214c87aefeSPatrick Mooney 	sc->vga_full = 0;
4224c87aefeSPatrick Mooney 
4234c87aefeSPatrick Mooney 	sc->fsc_pi = pi;
4244c87aefeSPatrick Mooney 
4252b948146SAndy Fiddaman 	error = pci_fbuf_parse_config(sc, nvl);
4264c87aefeSPatrick Mooney 	if (error != 0)
4274c87aefeSPatrick Mooney 		goto done;
4284c87aefeSPatrick Mooney 
4294c87aefeSPatrick Mooney 	/* XXX until VGA rendering is enabled */
4304c87aefeSPatrick Mooney 	if (sc->vga_full != 0) {
431154972afSPatrick Mooney 		EPRINTLN("pci_fbuf: VGA rendering not enabled");
4321aa1f41fSAndy Fiddaman #ifndef __FreeBSD__
4331aa1f41fSAndy Fiddaman 		errno = ENOTSUP;
4341aa1f41fSAndy Fiddaman 		error = -1;
4351aa1f41fSAndy Fiddaman #endif
4364c87aefeSPatrick Mooney 		goto done;
4374c87aefeSPatrick Mooney 	}
4384c87aefeSPatrick Mooney 
439154972afSPatrick Mooney 	DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]",
4404c87aefeSPatrick Mooney 	        sc->fb_base, FB_SIZE));
4414c87aefeSPatrick Mooney 
4424c87aefeSPatrick Mooney 	console_init(sc->memregs.width, sc->memregs.height, sc->fb_base);
4434c87aefeSPatrick Mooney 	console_fb_register(pci_fbuf_render, sc);
4444c87aefeSPatrick Mooney 
4454c87aefeSPatrick Mooney 	if (sc->vga_enabled)
4464c87aefeSPatrick Mooney 		sc->vgasc = vga_init(!sc->vga_full);
4474c87aefeSPatrick Mooney 	sc->gc_image = console_get_image();
4484c87aefeSPatrick Mooney 
4494c87aefeSPatrick Mooney 	fbuf_sc = sc;
4504c87aefeSPatrick Mooney 
4514c87aefeSPatrick Mooney 	memset((void *)sc->fb_base, 0, FB_SIZE);
4524c87aefeSPatrick Mooney 
4534c87aefeSPatrick Mooney #ifdef __FreeBSD__
4544c87aefeSPatrick Mooney 	error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
4554c87aefeSPatrick Mooney #else
45637fc8a1fSAndy Fiddaman 	char *name;
45737fc8a1fSAndy Fiddaman 
45837fc8a1fSAndy Fiddaman 	(void) asprintf(&name, "%s (bhyve)", get_config_value("name"));
45937fc8a1fSAndy Fiddaman 
4604c87aefeSPatrick Mooney 	if (sc->rfb_unix != NULL) {
4611aa1f41fSAndy Fiddaman 		error = rfb_init((char *)sc->rfb_unix, -1, sc->rfb_wait,
46237fc8a1fSAndy Fiddaman 		    sc->rfb_password, name != NULL ? name : "bhyve");
4634c87aefeSPatrick Mooney 	} else {
4644c87aefeSPatrick Mooney 		error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait,
46537fc8a1fSAndy Fiddaman 		    sc->rfb_password, name != NULL ? name : "bhyve");
4664c87aefeSPatrick Mooney 	}
46737fc8a1fSAndy Fiddaman 	if (error != 0)
46837fc8a1fSAndy Fiddaman 		free(name);
4694c87aefeSPatrick Mooney #endif
4704c87aefeSPatrick Mooney done:
4714c87aefeSPatrick Mooney 	if (error)
4724c87aefeSPatrick Mooney 		free(sc);
4734c87aefeSPatrick Mooney 
4744c87aefeSPatrick Mooney 	return (error);
4754c87aefeSPatrick Mooney }
4764c87aefeSPatrick Mooney 
4774f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_fbuf = {
4784c87aefeSPatrick Mooney 	.pe_emu =	"fbuf",
4794c87aefeSPatrick Mooney 	.pe_init =	pci_fbuf_init,
4804c87aefeSPatrick Mooney 	.pe_barwrite =	pci_fbuf_write,
4812b948146SAndy Fiddaman 	.pe_barread =	pci_fbuf_read,
4822b948146SAndy Fiddaman 	.pe_baraddr =	pci_fbuf_baraddr,
4834c87aefeSPatrick Mooney };
4844c87aefeSPatrick Mooney PCI_EMUL_SET(pci_fbuf);
485