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