static int setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) { char *ptr; int error, flags; /* Map 'len' bytes starting at 'gpa' in the guest address space */ error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL); if (error) return (error); flags = MAP_SHARED | MAP_FIXED; if ((ctx->memflags & VM_MEM_F_INCORE) == 0) flags |= MAP_NOCORE; /* mmap into the process address space on the host */ ptr = mmap(base + gpa, len, PROT_RW, flags, ctx->fd, gpa); if (ptr == MAP_FAILED) return (-1); return (0); }
static int pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) { int error, prot; struct pci_fbuf_softc *sc; if (fbuf_sc != NULL) { fprintf(stderr, "Only one frame buffer device is allowed.\n"); return (-1); } sc = calloc(1, sizeof(struct pci_fbuf_softc)); pi->pi_arg = sc; /* initialize config space */ pci_set_cfgdata16(pi, PCIR_DEVICE, 0x40FB); pci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY); pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA); error = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ); assert(error == 0); error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, FB_SIZE); assert(error == 0); error = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS); assert(error == 0); sc->fbaddr = pi->pi_bar[1].addr; sc->memregs.fbsize = FB_SIZE; sc->memregs.width = COLS_DEFAULT; sc->memregs.height = ROWS_DEFAULT; sc->memregs.depth = 32; sc->fsc_pi = pi; error = pci_fbuf_parse_opts(sc, opts); if (error != 0) goto done; sc->fb_base = vm_create_devmem(ctx, VM_FRAMEBUFFER, "framebuffer", FB_SIZE); if (sc->fb_base == MAP_FAILED) { error = -1; goto done; } DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]\r\n", sc->fb_base, FB_SIZE)); /* * Map the framebuffer into the guest address space. * XXX This may fail if the BAR is different than a prior * run. In this case flag the error. This will be fixed * when a change_memseg api is available. */ prot = PROT_READ | PROT_WRITE; if (vm_mmap_memseg(ctx, sc->fbaddr, VM_FRAMEBUFFER, 0, FB_SIZE, prot) != 0) { fprintf(stderr, "pci_fbuf: mapseg failed - try deleting VM and restarting\n"); error = -1; goto done; } console_init(sc->memregs.width, sc->memregs.height, sc->fb_base); console_fb_register(pci_fbuf_render, sc); sc->vgasc = vga_init(!sc->use_vga); sc->gc_image = console_get_image(); fbuf_sc = sc; memset((void *)sc->fb_base, 0, FB_SIZE); error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait); done: if (error) free(sc); return (error); }
int bootrom_init(struct vmctx *ctx, const char *romfile) { struct stat sbuf; vm_paddr_t gpa; ssize_t rlen; char *ptr; int fd, i, rv, prot; rv = -1; fd = open(romfile, O_RDONLY); if (fd < 0) { fprintf(stderr, "Error opening bootrom \"%s\": %s\n", romfile, strerror(errno)); goto done; } if (fstat(fd, &sbuf) < 0) { fprintf(stderr, "Could not fstat bootrom file \"%s\": %s\n", romfile, strerror(errno)); goto done; } /* * Limit bootrom size to 16MB so it doesn't encroach into reserved * MMIO space (e.g. APIC, HPET, MSI). */ if (sbuf.st_size > MAX_BOOTROM_SIZE || sbuf.st_size < PAGE_SIZE) { fprintf(stderr, "Invalid bootrom size %ld\n", sbuf.st_size); goto done; } if (sbuf.st_size & PAGE_MASK) { fprintf(stderr, "Bootrom size %ld is not a multiple of the " "page size\n", sbuf.st_size); goto done; } ptr = vm_create_devmem(ctx, VM_BOOTROM, "bootrom", sbuf.st_size); if (ptr == MAP_FAILED) goto done; /* Map the bootrom into the guest address space */ prot = PROT_READ | PROT_EXEC; gpa = (1ULL << 32) - sbuf.st_size; if (vm_mmap_memseg(ctx, gpa, VM_BOOTROM, 0, sbuf.st_size, prot) != 0) goto done; /* Read 'romfile' into the guest address space */ for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) { rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE); if (rlen != PAGE_SIZE) { fprintf(stderr, "Incomplete read of page %d of bootrom " "file %s: %ld bytes\n", i, romfile, rlen); goto done; } } rv = 0; done: if (fd >= 0) close(fd); return (rv); }