12cf9911fSPeter Grehan /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3ce80faa4SMarcelo Araujo * 42cf9911fSPeter Grehan * Copyright (c) 2015 Nahanni Systems, Inc. 52cf9911fSPeter Grehan * All rights reserved. 62cf9911fSPeter Grehan * 72cf9911fSPeter Grehan * Redistribution and use in source and binary forms, with or without 82cf9911fSPeter Grehan * modification, are permitted provided that the following conditions 92cf9911fSPeter Grehan * are met: 102cf9911fSPeter Grehan * 1. Redistributions of source code must retain the above copyright 112cf9911fSPeter Grehan * notice, this list of conditions and the following disclaimer. 122cf9911fSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 132cf9911fSPeter Grehan * notice, this list of conditions and the following disclaimer in the 142cf9911fSPeter Grehan * documentation and/or other materials provided with the distribution. 152cf9911fSPeter Grehan * 162cf9911fSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 172cf9911fSPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 182cf9911fSPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 192cf9911fSPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 202cf9911fSPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 212cf9911fSPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 222cf9911fSPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 232cf9911fSPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 242cf9911fSPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 252cf9911fSPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 262cf9911fSPeter Grehan * SUCH DAMAGE. 272cf9911fSPeter Grehan */ 282cf9911fSPeter Grehan 292cf9911fSPeter Grehan #include <sys/types.h> 302cf9911fSPeter Grehan #include <sys/mman.h> 312cf9911fSPeter Grehan 322cf9911fSPeter Grehan #include <machine/vmm.h> 33483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 342cf9911fSPeter Grehan #include <vmmapi.h> 352cf9911fSPeter Grehan 362cf9911fSPeter Grehan #include <stdio.h> 372cf9911fSPeter Grehan #include <stdlib.h> 382cf9911fSPeter Grehan #include <string.h> 392cf9911fSPeter Grehan 402cf9911fSPeter Grehan #include <errno.h> 412cf9911fSPeter Grehan #include <unistd.h> 422cf9911fSPeter Grehan 432cf9911fSPeter Grehan #include "bhyvegc.h" 442cf9911fSPeter Grehan #include "bhyverun.h" 45621b5090SJohn Baldwin #include "config.h" 46332eff95SVincenzo Maffione #include "debug.h" 472cf9911fSPeter Grehan #include "console.h" 482cf9911fSPeter Grehan #include "pci_emul.h" 492cf9911fSPeter Grehan #include "rfb.h" 5061429b49SMark Johnston #ifdef __amd64__ 5161429b49SMark Johnston #include "amd64/vga.h" 5261429b49SMark Johnston #endif 532cf9911fSPeter Grehan 542cf9911fSPeter Grehan /* 552cf9911fSPeter Grehan * bhyve Framebuffer device emulation. 562cf9911fSPeter Grehan * BAR0 points to the current mode information. 572cf9911fSPeter Grehan * BAR1 is the 32-bit framebuffer address. 582cf9911fSPeter Grehan * 5960bfcbd6SGleb Smirnoff * -s <b>,fbuf,wait,vga=on|io|off,rfb=<ip>:port,w=width,h=height 602cf9911fSPeter Grehan */ 612cf9911fSPeter Grehan 622cf9911fSPeter Grehan static int fbuf_debug = 1; 632cf9911fSPeter Grehan #define DEBUG_INFO 1 642cf9911fSPeter Grehan #define DEBUG_VERBOSE 4 65332eff95SVincenzo Maffione #define DPRINTF(level, params) if (level <= fbuf_debug) PRINTLN params 662cf9911fSPeter Grehan 672cf9911fSPeter Grehan 682cf9911fSPeter Grehan #define KB (1024UL) 692cf9911fSPeter Grehan #define MB (1024 * 1024UL) 702cf9911fSPeter Grehan 712cf9911fSPeter Grehan #define DMEMSZ 128 722cf9911fSPeter Grehan 73fb51ddb2SRobert Wing #define FB_SIZE (32*MB) 742cf9911fSPeter Grehan 75fb51ddb2SRobert Wing #define COLS_MAX 3840 76fb51ddb2SRobert Wing #define ROWS_MAX 2160 772cf9911fSPeter Grehan 782cf9911fSPeter Grehan #define COLS_DEFAULT 1024 792cf9911fSPeter Grehan #define ROWS_DEFAULT 768 802cf9911fSPeter Grehan 812cf9911fSPeter Grehan #define COLS_MIN 640 822cf9911fSPeter Grehan #define ROWS_MIN 480 832cf9911fSPeter Grehan 842cf9911fSPeter Grehan struct pci_fbuf_softc { 852cf9911fSPeter Grehan struct pci_devinst *fsc_pi; 862cf9911fSPeter Grehan struct { 872cf9911fSPeter Grehan uint32_t fbsize; 882cf9911fSPeter Grehan uint16_t width; 892cf9911fSPeter Grehan uint16_t height; 902cf9911fSPeter Grehan uint16_t depth; 912cf9911fSPeter Grehan uint16_t refreshrate; 922cf9911fSPeter Grehan uint8_t reserved[116]; 932cf9911fSPeter Grehan } __packed memregs; 942cf9911fSPeter Grehan 952cf9911fSPeter Grehan /* rfb server */ 962cf9911fSPeter Grehan char *rfb_host; 97f4d34383SMarcelo Araujo char *rfb_password; 982cf9911fSPeter Grehan int rfb_port; 992cf9911fSPeter Grehan int rfb_wait; 1005a347e3bSPeter Grehan int vga_enabled; 1015a347e3bSPeter Grehan int vga_full; 1022cf9911fSPeter Grehan 1032cf9911fSPeter Grehan uint32_t fbaddr; 1042cf9911fSPeter Grehan char *fb_base; 1052cf9911fSPeter Grehan uint16_t gc_width; 1062cf9911fSPeter Grehan uint16_t gc_height; 1072cf9911fSPeter Grehan void *vgasc; 1082cf9911fSPeter Grehan struct bhyvegc_image *gc_image; 1092cf9911fSPeter Grehan }; 1102cf9911fSPeter Grehan 1112cf9911fSPeter Grehan static struct pci_fbuf_softc *fbuf_sc; 1122cf9911fSPeter Grehan 1132cf9911fSPeter Grehan #define PCI_FBUF_MSI_MSGS 4 1142cf9911fSPeter Grehan 1152cf9911fSPeter Grehan static void 1166a284cacSJohn Baldwin pci_fbuf_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size, 11798d920d9SMark Johnston uint64_t value) 1182cf9911fSPeter Grehan { 1192cf9911fSPeter Grehan struct pci_fbuf_softc *sc; 1202cf9911fSPeter Grehan uint8_t *p; 1212cf9911fSPeter Grehan 1222cf9911fSPeter Grehan assert(baridx == 0); 1232cf9911fSPeter Grehan 1242cf9911fSPeter Grehan sc = pi->pi_arg; 1252cf9911fSPeter Grehan 1262cf9911fSPeter Grehan DPRINTF(DEBUG_VERBOSE, 127cbd7ddcfSRebecca Cran ("fbuf wr: offset 0x%lx, size: %d, value: 0x%lx", 1282cf9911fSPeter Grehan offset, size, value)); 1292cf9911fSPeter Grehan 1302cf9911fSPeter Grehan if (offset + size > DMEMSZ) { 1312cf9911fSPeter Grehan printf("fbuf: write too large, offset %ld size %d\n", 1322cf9911fSPeter Grehan offset, size); 1332cf9911fSPeter Grehan return; 1342cf9911fSPeter Grehan } 1352cf9911fSPeter Grehan 1362cf9911fSPeter Grehan p = (uint8_t *)&sc->memregs + offset; 1372cf9911fSPeter Grehan 1382cf9911fSPeter Grehan switch (size) { 1392cf9911fSPeter Grehan case 1: 1402cf9911fSPeter Grehan *p = value; 1412cf9911fSPeter Grehan break; 1422cf9911fSPeter Grehan case 2: 1432cf9911fSPeter Grehan *(uint16_t *)p = value; 1442cf9911fSPeter Grehan break; 1452cf9911fSPeter Grehan case 4: 1462cf9911fSPeter Grehan *(uint32_t *)p = value; 1472cf9911fSPeter Grehan break; 1482cf9911fSPeter Grehan case 8: 1492cf9911fSPeter Grehan *(uint64_t *)p = value; 1502cf9911fSPeter Grehan break; 1512cf9911fSPeter Grehan default: 1522cf9911fSPeter Grehan printf("fbuf: write unknown size %d\n", size); 1532cf9911fSPeter Grehan break; 1542cf9911fSPeter Grehan } 1552cf9911fSPeter Grehan 1562cf9911fSPeter Grehan if (!sc->gc_image->vgamode && sc->memregs.width == 0 && 1572cf9911fSPeter Grehan sc->memregs.height == 0) { 158332eff95SVincenzo Maffione DPRINTF(DEBUG_INFO, ("switching to VGA mode")); 1592cf9911fSPeter Grehan sc->gc_image->vgamode = 1; 1602cf9911fSPeter Grehan sc->gc_width = 0; 1612cf9911fSPeter Grehan sc->gc_height = 0; 1622cf9911fSPeter Grehan } else if (sc->gc_image->vgamode && sc->memregs.width != 0 && 1632cf9911fSPeter Grehan sc->memregs.height != 0) { 164332eff95SVincenzo Maffione DPRINTF(DEBUG_INFO, ("switching to VESA mode")); 1652cf9911fSPeter Grehan sc->gc_image->vgamode = 0; 1662cf9911fSPeter Grehan } 1672cf9911fSPeter Grehan } 1682cf9911fSPeter Grehan 16937045dfaSMark Johnston static uint64_t 1706a284cacSJohn Baldwin pci_fbuf_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size) 1712cf9911fSPeter Grehan { 1722cf9911fSPeter Grehan struct pci_fbuf_softc *sc; 1732cf9911fSPeter Grehan uint8_t *p; 1742cf9911fSPeter Grehan uint64_t value; 1752cf9911fSPeter Grehan 1762cf9911fSPeter Grehan assert(baridx == 0); 1772cf9911fSPeter Grehan 1782cf9911fSPeter Grehan sc = pi->pi_arg; 1792cf9911fSPeter Grehan 1802cf9911fSPeter Grehan 1812cf9911fSPeter Grehan if (offset + size > DMEMSZ) { 1822cf9911fSPeter Grehan printf("fbuf: read too large, offset %ld size %d\n", 1832cf9911fSPeter Grehan offset, size); 1842cf9911fSPeter Grehan return (0); 1852cf9911fSPeter Grehan } 1862cf9911fSPeter Grehan 1872cf9911fSPeter Grehan p = (uint8_t *)&sc->memregs + offset; 1882cf9911fSPeter Grehan value = 0; 1892cf9911fSPeter Grehan switch (size) { 1902cf9911fSPeter Grehan case 1: 1912cf9911fSPeter Grehan value = *p; 1922cf9911fSPeter Grehan break; 1932cf9911fSPeter Grehan case 2: 1942cf9911fSPeter Grehan value = *(uint16_t *)p; 1952cf9911fSPeter Grehan break; 1962cf9911fSPeter Grehan case 4: 1972cf9911fSPeter Grehan value = *(uint32_t *)p; 1982cf9911fSPeter Grehan break; 1992cf9911fSPeter Grehan case 8: 2002cf9911fSPeter Grehan value = *(uint64_t *)p; 2012cf9911fSPeter Grehan break; 2022cf9911fSPeter Grehan default: 2032cf9911fSPeter Grehan printf("fbuf: read unknown size %d\n", size); 2042cf9911fSPeter Grehan break; 2052cf9911fSPeter Grehan } 2062cf9911fSPeter Grehan 2072cf9911fSPeter Grehan DPRINTF(DEBUG_VERBOSE, 208cbd7ddcfSRebecca Cran ("fbuf rd: offset 0x%lx, size: %d, value: 0x%lx", 2092cf9911fSPeter Grehan offset, size, value)); 2102cf9911fSPeter Grehan 2112cf9911fSPeter Grehan return (value); 2122cf9911fSPeter Grehan } 2132cf9911fSPeter Grehan 214f8a6ec2dSD Scott Phillips static void 2156a284cacSJohn Baldwin pci_fbuf_baraddr(struct pci_devinst *pi, int baridx, int enabled, 2166a284cacSJohn Baldwin uint64_t address) 217f8a6ec2dSD Scott Phillips { 218f8a6ec2dSD Scott Phillips struct pci_fbuf_softc *sc; 219f8a6ec2dSD Scott Phillips int prot; 220f8a6ec2dSD Scott Phillips 221f8a6ec2dSD Scott Phillips if (baridx != 1) 222f8a6ec2dSD Scott Phillips return; 223f8a6ec2dSD Scott Phillips 224f8a6ec2dSD Scott Phillips sc = pi->pi_arg; 2255085153aSCorvin Köhne if (!enabled) { 2266a284cacSJohn Baldwin if (vm_munmap_memseg(pi->pi_vmctx, sc->fbaddr, FB_SIZE) != 0) 227f8a6ec2dSD Scott Phillips EPRINTLN("pci_fbuf: munmap_memseg failed"); 228f8a6ec2dSD Scott Phillips sc->fbaddr = 0; 2295085153aSCorvin Köhne } else { 230f8a6ec2dSD Scott Phillips prot = PROT_READ | PROT_WRITE; 2316a284cacSJohn Baldwin if (vm_mmap_memseg(pi->pi_vmctx, address, VM_FRAMEBUFFER, 0, 2326a284cacSJohn Baldwin FB_SIZE, prot) != 0) 233f8a6ec2dSD Scott Phillips EPRINTLN("pci_fbuf: mmap_memseg failed"); 234*85707cfdSPierre Pronchery else 235f8a6ec2dSD Scott Phillips sc->fbaddr = address; 236f8a6ec2dSD Scott Phillips } 237f8a6ec2dSD Scott Phillips } 238f8a6ec2dSD Scott Phillips 239f8a6ec2dSD Scott Phillips 2402cf9911fSPeter Grehan static int 241621b5090SJohn Baldwin pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl) 2422cf9911fSPeter Grehan { 243621b5090SJohn Baldwin const char *value; 244621b5090SJohn Baldwin char *cp; 2452cf9911fSPeter Grehan 246621b5090SJohn Baldwin sc->rfb_wait = get_config_bool_node_default(nvl, "wait", false); 2472cf9911fSPeter Grehan 248621b5090SJohn Baldwin /* Prefer "rfb" to "tcp". */ 249621b5090SJohn Baldwin value = get_config_value_node(nvl, "rfb"); 250621b5090SJohn Baldwin if (value == NULL) 251621b5090SJohn Baldwin value = get_config_value_node(nvl, "tcp"); 252621b5090SJohn Baldwin if (value != NULL) { 2538883128bSBjoern A. Zeeb /* 2548883128bSBjoern A. Zeeb * IPv4 -- host-ip:port 2558883128bSBjoern A. Zeeb * IPv6 -- [host-ip%zone]:port 256621b5090SJohn Baldwin * XXX for now port is mandatory for IPv4. 2578883128bSBjoern A. Zeeb */ 258621b5090SJohn Baldwin if (value[0] == '[') { 259621b5090SJohn Baldwin cp = strchr(value + 1, ']'); 260621b5090SJohn Baldwin if (cp == NULL || cp == value + 1) { 261621b5090SJohn Baldwin EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"", 262621b5090SJohn Baldwin value); 263621b5090SJohn Baldwin return (-1); 2648883128bSBjoern A. Zeeb } 265621b5090SJohn Baldwin sc->rfb_host = strndup(value + 1, cp - (value + 1)); 266621b5090SJohn Baldwin cp++; 267621b5090SJohn Baldwin if (*cp == ':') { 268621b5090SJohn Baldwin cp++; 269621b5090SJohn Baldwin if (*cp == '\0') { 270621b5090SJohn Baldwin EPRINTLN( 271621b5090SJohn Baldwin "fbuf: Missing port number: \"%s\"", 272621b5090SJohn Baldwin value); 273621b5090SJohn Baldwin return (-1); 274621b5090SJohn Baldwin } 275621b5090SJohn Baldwin sc->rfb_port = atoi(cp); 276621b5090SJohn Baldwin } else if (*cp != '\0') { 277621b5090SJohn Baldwin EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"", 278621b5090SJohn Baldwin value); 279621b5090SJohn Baldwin return (-1); 280621b5090SJohn Baldwin } 2818883128bSBjoern A. Zeeb } else { 282621b5090SJohn Baldwin cp = strchr(value, ':'); 283621b5090SJohn Baldwin if (cp == NULL) { 284621b5090SJohn Baldwin sc->rfb_port = atoi(value); 2855a347e3bSPeter Grehan } else { 286621b5090SJohn Baldwin sc->rfb_host = strndup(value, cp - value); 287621b5090SJohn Baldwin cp++; 288621b5090SJohn Baldwin if (*cp == '\0') { 289621b5090SJohn Baldwin EPRINTLN( 290621b5090SJohn Baldwin "fbuf: Missing port number: \"%s\"", 291621b5090SJohn Baldwin value); 292621b5090SJohn Baldwin return (-1); 2935a347e3bSPeter Grehan } 294621b5090SJohn Baldwin sc->rfb_port = atoi(cp); 295621b5090SJohn Baldwin } 2962cf9911fSPeter Grehan } 2972cf9911fSPeter Grehan } 2982cf9911fSPeter Grehan 299621b5090SJohn Baldwin value = get_config_value_node(nvl, "vga"); 300621b5090SJohn Baldwin if (value != NULL) { 301621b5090SJohn Baldwin if (strcmp(value, "off") == 0) { 302621b5090SJohn Baldwin sc->vga_enabled = 0; 303621b5090SJohn Baldwin } else if (strcmp(value, "io") == 0) { 304621b5090SJohn Baldwin sc->vga_enabled = 1; 305621b5090SJohn Baldwin sc->vga_full = 0; 306621b5090SJohn Baldwin } else if (strcmp(value, "on") == 0) { 307621b5090SJohn Baldwin sc->vga_enabled = 1; 308621b5090SJohn Baldwin sc->vga_full = 1; 309621b5090SJohn Baldwin } else { 310621b5090SJohn Baldwin EPRINTLN("fbuf: Invalid vga setting: \"%s\"", value); 311621b5090SJohn Baldwin return (-1); 312621b5090SJohn Baldwin } 313621b5090SJohn Baldwin } 314621b5090SJohn Baldwin 315621b5090SJohn Baldwin value = get_config_value_node(nvl, "w"); 3160600b575SRobert Wing if (value != NULL) 3170600b575SRobert Wing sc->memregs.width = strtol(value, NULL, 10); 318621b5090SJohn Baldwin 319621b5090SJohn Baldwin value = get_config_value_node(nvl, "h"); 3200600b575SRobert Wing if (value != NULL) 3210600b575SRobert Wing sc->memregs.height = strtol(value, NULL, 10); 3220600b575SRobert Wing 3230600b575SRobert Wing if (sc->memregs.width > COLS_MAX || 3240600b575SRobert Wing sc->memregs.height > ROWS_MAX) { 3250600b575SRobert Wing EPRINTLN("fbuf: max resolution is %ux%u", COLS_MAX, ROWS_MAX); 326621b5090SJohn Baldwin return (-1); 327621b5090SJohn Baldwin } 3280600b575SRobert Wing if (sc->memregs.width < COLS_MIN || 3290600b575SRobert Wing sc->memregs.height < ROWS_MIN) { 3300600b575SRobert Wing EPRINTLN("fbuf: minimum resolution is %ux%u", 3310600b575SRobert Wing COLS_MIN, ROWS_MIN); 3320600b575SRobert Wing return (-1); 333621b5090SJohn Baldwin } 334621b5090SJohn Baldwin 335621b5090SJohn Baldwin value = get_config_value_node(nvl, "password"); 336621b5090SJohn Baldwin if (value != NULL) 337621b5090SJohn Baldwin sc->rfb_password = strdup(value); 338621b5090SJohn Baldwin 339621b5090SJohn Baldwin return (0); 3402cf9911fSPeter Grehan } 3412cf9911fSPeter Grehan 34237045dfaSMark Johnston static void 3432cf9911fSPeter Grehan pci_fbuf_render(struct bhyvegc *gc, void *arg) 3442cf9911fSPeter Grehan { 3452cf9911fSPeter Grehan struct pci_fbuf_softc *sc; 3462cf9911fSPeter Grehan 3472cf9911fSPeter Grehan sc = arg; 3482cf9911fSPeter Grehan 3495a347e3bSPeter Grehan if (sc->vga_full && sc->gc_image->vgamode) { 3502cf9911fSPeter Grehan /* TODO: mode switching to vga and vesa should use the special 3512cf9911fSPeter Grehan * EFI-bhyve protocol port. 3522cf9911fSPeter Grehan */ 3532cf9911fSPeter Grehan vga_render(gc, sc->vgasc); 3542cf9911fSPeter Grehan return; 3552cf9911fSPeter Grehan } 3562cf9911fSPeter Grehan if (sc->gc_width != sc->memregs.width || 3572cf9911fSPeter Grehan sc->gc_height != sc->memregs.height) { 3582cf9911fSPeter Grehan bhyvegc_resize(gc, sc->memregs.width, sc->memregs.height); 3592cf9911fSPeter Grehan sc->gc_width = sc->memregs.width; 3602cf9911fSPeter Grehan sc->gc_height = sc->memregs.height; 3612cf9911fSPeter Grehan } 3622cf9911fSPeter Grehan } 3632cf9911fSPeter Grehan 3642cf9911fSPeter Grehan static int 3656a284cacSJohn Baldwin pci_fbuf_init(struct pci_devinst *pi, nvlist_t *nvl) 3662cf9911fSPeter Grehan { 3675085153aSCorvin Köhne int error; 3682cf9911fSPeter Grehan struct pci_fbuf_softc *sc; 3692cf9911fSPeter Grehan 3702cf9911fSPeter Grehan if (fbuf_sc != NULL) { 371332eff95SVincenzo Maffione EPRINTLN("Only one frame buffer device is allowed."); 3722cf9911fSPeter Grehan return (-1); 3732cf9911fSPeter Grehan } 3742cf9911fSPeter Grehan 3752cf9911fSPeter Grehan sc = calloc(1, sizeof(struct pci_fbuf_softc)); 3762cf9911fSPeter Grehan 3772cf9911fSPeter Grehan pi->pi_arg = sc; 3782cf9911fSPeter Grehan 3792cf9911fSPeter Grehan /* initialize config space */ 3802cf9911fSPeter Grehan pci_set_cfgdata16(pi, PCIR_DEVICE, 0x40FB); 3812cf9911fSPeter Grehan pci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D); 3822cf9911fSPeter Grehan pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY); 3832cf9911fSPeter Grehan pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA); 3842cf9911fSPeter Grehan 3856a284cacSJohn Baldwin sc->fb_base = vm_create_devmem(pi->pi_vmctx, VM_FRAMEBUFFER, 3866a284cacSJohn Baldwin "framebuffer", FB_SIZE); 3875085153aSCorvin Köhne if (sc->fb_base == MAP_FAILED) { 3885085153aSCorvin Köhne error = -1; 3895085153aSCorvin Köhne goto done; 3905085153aSCorvin Köhne } 3915085153aSCorvin Köhne 3922cf9911fSPeter Grehan error = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ); 3932cf9911fSPeter Grehan assert(error == 0); 3942cf9911fSPeter Grehan 3952cf9911fSPeter Grehan error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, FB_SIZE); 3962cf9911fSPeter Grehan assert(error == 0); 3972cf9911fSPeter Grehan 3982cf9911fSPeter Grehan error = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS); 3992cf9911fSPeter Grehan assert(error == 0); 4002cf9911fSPeter Grehan 4012cf9911fSPeter Grehan sc->memregs.fbsize = FB_SIZE; 4022cf9911fSPeter Grehan sc->memregs.width = COLS_DEFAULT; 4032cf9911fSPeter Grehan sc->memregs.height = ROWS_DEFAULT; 4042cf9911fSPeter Grehan sc->memregs.depth = 32; 4052cf9911fSPeter Grehan 4065a347e3bSPeter Grehan sc->vga_enabled = 1; 4075a347e3bSPeter Grehan sc->vga_full = 0; 4085a347e3bSPeter Grehan 4092cf9911fSPeter Grehan sc->fsc_pi = pi; 4102cf9911fSPeter Grehan 411621b5090SJohn Baldwin error = pci_fbuf_parse_config(sc, nvl); 4122cf9911fSPeter Grehan if (error != 0) 4132cf9911fSPeter Grehan goto done; 4142cf9911fSPeter Grehan 4155a347e3bSPeter Grehan /* XXX until VGA rendering is enabled */ 4165a347e3bSPeter Grehan if (sc->vga_full != 0) { 417332eff95SVincenzo Maffione EPRINTLN("pci_fbuf: VGA rendering not enabled"); 4185a347e3bSPeter Grehan goto done; 4195a347e3bSPeter Grehan } 4205a347e3bSPeter Grehan 421332eff95SVincenzo Maffione DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]", 4222cf9911fSPeter Grehan sc->fb_base, FB_SIZE)); 4232cf9911fSPeter Grehan 4242cf9911fSPeter Grehan console_init(sc->memregs.width, sc->memregs.height, sc->fb_base); 4252cf9911fSPeter Grehan console_fb_register(pci_fbuf_render, sc); 4262cf9911fSPeter Grehan 4275a347e3bSPeter Grehan if (sc->vga_enabled) 4285a347e3bSPeter Grehan sc->vgasc = vga_init(!sc->vga_full); 4292cf9911fSPeter Grehan sc->gc_image = console_get_image(); 4302cf9911fSPeter Grehan 4312cf9911fSPeter Grehan fbuf_sc = sc; 4322cf9911fSPeter Grehan 4332cf9911fSPeter Grehan memset((void *)sc->fb_base, 0, FB_SIZE); 4342cf9911fSPeter Grehan 435f4d34383SMarcelo Araujo error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password); 4362cf9911fSPeter Grehan done: 4372cf9911fSPeter Grehan if (error) 4382cf9911fSPeter Grehan free(sc); 4392cf9911fSPeter Grehan 4402cf9911fSPeter Grehan return (error); 4412cf9911fSPeter Grehan } 4422cf9911fSPeter Grehan 443483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 444483d953aSJohn Baldwin static int 445483d953aSJohn Baldwin pci_fbuf_snapshot(struct vm_snapshot_meta *meta) 446483d953aSJohn Baldwin { 447483d953aSJohn Baldwin int ret; 448483d953aSJohn Baldwin 449483d953aSJohn Baldwin SNAPSHOT_BUF_OR_LEAVE(fbuf_sc->fb_base, FB_SIZE, meta, ret, err); 450483d953aSJohn Baldwin 451483d953aSJohn Baldwin err: 452483d953aSJohn Baldwin return (ret); 453483d953aSJohn Baldwin } 454483d953aSJohn Baldwin #endif 455483d953aSJohn Baldwin 45637045dfaSMark Johnston static const struct pci_devemu pci_fbuf = { 4572cf9911fSPeter Grehan .pe_emu = "fbuf", 4582cf9911fSPeter Grehan .pe_init = pci_fbuf_init, 4592cf9911fSPeter Grehan .pe_barwrite = pci_fbuf_write, 460483d953aSJohn Baldwin .pe_barread = pci_fbuf_read, 461f8a6ec2dSD Scott Phillips .pe_baraddr = pci_fbuf_baraddr, 462483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 463483d953aSJohn Baldwin .pe_snapshot = pci_fbuf_snapshot, 464483d953aSJohn Baldwin #endif 4652cf9911fSPeter Grehan }; 4662cf9911fSPeter Grehan PCI_EMUL_SET(pci_fbuf); 467