1284539Sneel/*- 2284539Sneel * Copyright (c) 2015 Neel Natu <neel@freebsd.org> 3284539Sneel * All rights reserved. 4284539Sneel * 5284539Sneel * Redistribution and use in source and binary forms, with or without 6284539Sneel * modification, are permitted provided that the following conditions 7284539Sneel * are met: 8284539Sneel * 1. Redistributions of source code must retain the above copyright 9284539Sneel * notice, this list of conditions and the following disclaimer. 10284539Sneel * 2. Redistributions in binary form must reproduce the above copyright 11284539Sneel * notice, this list of conditions and the following disclaimer in the 12284539Sneel * documentation and/or other materials provided with the distribution. 13284539Sneel * 14284539Sneel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 15284539Sneel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16284539Sneel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17284539Sneel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18284539Sneel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19284539Sneel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20284539Sneel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21284539Sneel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22284539Sneel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23284539Sneel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24284539Sneel * SUCH DAMAGE. 25284539Sneel */ 26284539Sneel 27284539Sneel#include <sys/param.h> 28284539Sneel__FBSDID("$FreeBSD: releng/10.3/usr.sbin/bhyve/bootrom.c 295124 2016-02-01 14:56:11Z grehan $"); 29284539Sneel 30284539Sneel#include <sys/types.h> 31284539Sneel#include <sys/mman.h> 32284539Sneel#include <sys/stat.h> 33284539Sneel 34284539Sneel#include <machine/vmm.h> 35284539Sneel 36284539Sneel#include <errno.h> 37284539Sneel#include <fcntl.h> 38284539Sneel#include <stdio.h> 39284539Sneel#include <string.h> 40284539Sneel#include <unistd.h> 41284539Sneel#include <stdbool.h> 42284539Sneel 43284539Sneel#include <vmmapi.h> 44284539Sneel#include "bhyverun.h" 45284539Sneel#include "bootrom.h" 46284539Sneel 47284539Sneel#define MAX_BOOTROM_SIZE (16 * 1024 * 1024) /* 16 MB */ 48284539Sneel 49284539Sneelint 50284539Sneelbootrom_init(struct vmctx *ctx, const char *romfile) 51284539Sneel{ 52284539Sneel struct stat sbuf; 53284539Sneel vm_paddr_t gpa; 54284539Sneel ssize_t rlen; 55284539Sneel char *ptr; 56284539Sneel int fd, i, rv, prot; 57284539Sneel 58284539Sneel rv = -1; 59284539Sneel fd = open(romfile, O_RDONLY); 60284539Sneel if (fd < 0) { 61284539Sneel fprintf(stderr, "Error opening bootrom \"%s\": %s\n", 62284539Sneel romfile, strerror(errno)); 63284539Sneel goto done; 64284539Sneel } 65284539Sneel 66284539Sneel if (fstat(fd, &sbuf) < 0) { 67284539Sneel fprintf(stderr, "Could not fstat bootrom file \"%s\": %s\n", 68284539Sneel romfile, strerror(errno)); 69284539Sneel goto done; 70284539Sneel } 71284539Sneel 72284539Sneel /* 73284539Sneel * Limit bootrom size to 16MB so it doesn't encroach into reserved 74284539Sneel * MMIO space (e.g. APIC, HPET, MSI). 75284539Sneel */ 76284539Sneel if (sbuf.st_size > MAX_BOOTROM_SIZE || sbuf.st_size < PAGE_SIZE) { 77284539Sneel fprintf(stderr, "Invalid bootrom size %ld\n", sbuf.st_size); 78284539Sneel goto done; 79284539Sneel } 80284539Sneel 81284539Sneel if (sbuf.st_size & PAGE_MASK) { 82284539Sneel fprintf(stderr, "Bootrom size %ld is not a multiple of the " 83284539Sneel "page size\n", sbuf.st_size); 84284539Sneel goto done; 85284539Sneel } 86284539Sneel 87284539Sneel ptr = vm_create_devmem(ctx, VM_BOOTROM, "bootrom", sbuf.st_size); 88284539Sneel if (ptr == MAP_FAILED) 89284539Sneel goto done; 90284539Sneel 91284539Sneel /* Map the bootrom into the guest address space */ 92284539Sneel prot = PROT_READ | PROT_EXEC; 93284539Sneel gpa = (1ULL << 32) - sbuf.st_size; 94284539Sneel if (vm_mmap_memseg(ctx, gpa, VM_BOOTROM, 0, sbuf.st_size, prot) != 0) 95284539Sneel goto done; 96284539Sneel 97284539Sneel /* Read 'romfile' into the guest address space */ 98284539Sneel for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) { 99284539Sneel rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE); 100284539Sneel if (rlen != PAGE_SIZE) { 101284539Sneel fprintf(stderr, "Incomplete read of page %d of bootrom " 102284539Sneel "file %s: %ld bytes\n", i, romfile, rlen); 103284539Sneel goto done; 104284539Sneel } 105284539Sneel } 106284539Sneel rv = 0; 107284539Sneeldone: 108284539Sneel if (fd >= 0) 109284539Sneel close(fd); 110284539Sneel return (rv); 111284539Sneel} 112