bootrom.c (4c87aefe8930bd07275b8dd2e96ea5f24d93a52e) | bootrom.c (154972aff898a787b38af3bab5b8d754b5a42447) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2015 Neel Natu <neel@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 21 unchanged lines hidden (view full) --- 30__FBSDID("$FreeBSD$"); 31 32#include <sys/types.h> 33#include <sys/mman.h> 34#include <sys/stat.h> 35 36#include <machine/vmm.h> 37 | 1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2015 Neel Natu <neel@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 21 unchanged lines hidden (view full) --- 30__FBSDID("$FreeBSD$"); 31 32#include <sys/types.h> 33#include <sys/mman.h> 34#include <sys/stat.h> 35 36#include <machine/vmm.h> 37 |
38#include <err.h> |
|
38#include <errno.h> 39#include <fcntl.h> 40#include <stdio.h> 41#include <string.h> 42#include <unistd.h> 43#include <stdbool.h> 44 45#include <vmmapi.h> 46#include "bhyverun.h" 47#include "bootrom.h" | 39#include <errno.h> 40#include <fcntl.h> 41#include <stdio.h> 42#include <string.h> 43#include <unistd.h> 44#include <stdbool.h> 45 46#include <vmmapi.h> 47#include "bhyverun.h" 48#include "bootrom.h" |
49#include "debug.h" |
|
48 | 50 |
49#define MAX_BOOTROM_SIZE (16 * 1024 * 1024) /* 16 MB */ | 51#define BOOTROM_SIZE (16 * 1024 * 1024) /* 16 MB */ |
50 | 52 |
53/* 54 * ROM region is 16 MB at the top of 4GB ("low") memory. 55 * 56 * The size is limited so it doesn't encroach into reserved MMIO space (e.g., 57 * APIC, HPET, MSI). 58 * 59 * It is allocated in page-multiple blocks on a first-come first-serve basis, 60 * from high to low, during initialization, and does not change at runtime. 61 */ 62static char *romptr; /* Pointer to userspace-mapped bootrom region. */ 63static vm_paddr_t gpa_base; /* GPA of low end of region. */ 64static vm_paddr_t gpa_allocbot; /* Low GPA of free region. */ 65static vm_paddr_t gpa_alloctop; /* High GPA, minus 1, of free region. */ 66 67void 68init_bootrom(struct vmctx *ctx) 69{ 70 romptr = vm_create_devmem(ctx, VM_BOOTROM, "bootrom", BOOTROM_SIZE); 71 if (romptr == MAP_FAILED) 72 err(4, "%s: vm_create_devmem", __func__); 73 gpa_base = (1ULL << 32) - BOOTROM_SIZE; 74 gpa_allocbot = gpa_base; 75 gpa_alloctop = (1ULL << 32) - 1; 76} 77 |
|
51int | 78int |
52bootrom_init(struct vmctx *ctx, const char *romfile) | 79bootrom_alloc(struct vmctx *ctx, size_t len, int prot, int flags, 80 char **region_out, uint64_t *gpa_out) |
53{ | 81{ |
54 struct stat sbuf; | 82 static const int bootrom_valid_flags = BOOTROM_ALLOC_TOP; 83 |
55 vm_paddr_t gpa; | 84 vm_paddr_t gpa; |
85 vm_ooffset_t segoff; 86 87 if (flags & ~bootrom_valid_flags) { 88 warnx("%s: Invalid flags: %x", __func__, 89 flags & ~bootrom_valid_flags); 90 return (EINVAL); 91 } 92 if (prot & ~_PROT_ALL) { 93 warnx("%s: Invalid protection: %x", __func__, 94 prot & ~_PROT_ALL); 95 return (EINVAL); 96 } 97 98 if (len == 0 || len > BOOTROM_SIZE) { 99 warnx("ROM size %zu is invalid", len); 100 return (EINVAL); 101 } 102 if (len & PAGE_MASK) { 103 warnx("ROM size %zu is not a multiple of the page size", 104 len); 105 return (EINVAL); 106 } 107 108 if (flags & BOOTROM_ALLOC_TOP) { 109 gpa = (gpa_alloctop - len) + 1; 110 if (gpa < gpa_allocbot) { 111 warnx("No room for %zu ROM in bootrom region", len); 112 return (ENOMEM); 113 } 114 } else { 115 gpa = gpa_allocbot; 116 if (gpa > (gpa_alloctop - len) + 1) { 117 warnx("No room for %zu ROM in bootrom region", len); 118 return (ENOMEM); 119 } 120 } 121 122 segoff = gpa - gpa_base; 123 if (vm_mmap_memseg(ctx, gpa, VM_BOOTROM, segoff, len, prot) != 0) { 124 int serrno = errno; 125 warn("%s: vm_mmap_mapseg", __func__); 126 return (serrno); 127 } 128 129 if (flags & BOOTROM_ALLOC_TOP) 130 gpa_alloctop = gpa - 1; 131 else 132 gpa_allocbot = gpa + len; 133 134 *region_out = romptr + segoff; 135 if (gpa_out != NULL) 136 *gpa_out = gpa; 137 return (0); 138} 139 140int 141bootrom_loadrom(struct vmctx *ctx, const char *romfile) 142{ 143 struct stat sbuf; |
|
56 ssize_t rlen; 57 char *ptr; | 144 ssize_t rlen; 145 char *ptr; |
58 int fd, i, rv, prot; | 146 int fd, i, rv; |
59 60 rv = -1; 61 fd = open(romfile, O_RDONLY); 62 if (fd < 0) { | 147 148 rv = -1; 149 fd = open(romfile, O_RDONLY); 150 if (fd < 0) { |
63 fprintf(stderr, "Error opening bootrom \"%s\": %s\n", | 151 EPRINTLN("Error opening bootrom \"%s\": %s", |
64 romfile, strerror(errno)); 65 goto done; 66 } 67 68 if (fstat(fd, &sbuf) < 0) { | 152 romfile, strerror(errno)); 153 goto done; 154 } 155 156 if (fstat(fd, &sbuf) < 0) { |
69 fprintf(stderr, "Could not fstat bootrom file \"%s\": %s\n", | 157 EPRINTLN("Could not fstat bootrom file \"%s\": %s", |
70 romfile, strerror(errno)); 71 goto done; 72 } 73 | 158 romfile, strerror(errno)); 159 goto done; 160 } 161 |
74 /* 75 * Limit bootrom size to 16MB so it doesn't encroach into reserved 76 * MMIO space (e.g. APIC, HPET, MSI). 77 */ 78 if (sbuf.st_size > MAX_BOOTROM_SIZE || sbuf.st_size < PAGE_SIZE) { 79 fprintf(stderr, "Invalid bootrom size %ld\n", sbuf.st_size); 80 goto done; 81 } 82 83 if (sbuf.st_size & PAGE_MASK) { 84 fprintf(stderr, "Bootrom size %ld is not a multiple of the " 85 "page size\n", sbuf.st_size); 86 goto done; 87 } 88 89 ptr = vm_create_devmem(ctx, VM_BOOTROM, "bootrom", sbuf.st_size); 90 if (ptr == MAP_FAILED) 91 goto done; 92 | |
93 /* Map the bootrom into the guest address space */ | 162 /* Map the bootrom into the guest address space */ |
94 prot = PROT_READ | PROT_EXEC; 95 gpa = (1ULL << 32) - sbuf.st_size; 96 if (vm_mmap_memseg(ctx, gpa, VM_BOOTROM, 0, sbuf.st_size, prot) != 0) | 163 if (bootrom_alloc(ctx, sbuf.st_size, PROT_READ | PROT_EXEC, 164 BOOTROM_ALLOC_TOP, &ptr, NULL) != 0) |
97 goto done; 98 99 /* Read 'romfile' into the guest address space */ 100 for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) { 101 rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE); 102 if (rlen != PAGE_SIZE) { | 165 goto done; 166 167 /* Read 'romfile' into the guest address space */ 168 for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) { 169 rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE); 170 if (rlen != PAGE_SIZE) { |
103 fprintf(stderr, "Incomplete read of page %d of bootrom " 104 "file %s: %ld bytes\n", i, romfile, rlen); | 171 EPRINTLN("Incomplete read of page %d of bootrom " 172 "file %s: %ld bytes", i, romfile, rlen); |
105 goto done; 106 } 107 } 108 rv = 0; 109done: 110 if (fd >= 0) 111 close(fd); 112 return (rv); 113} | 173 goto done; 174 } 175 } 176 rv = 0; 177done: 178 if (fd >= 0) 179 close(fd); 180 return (rv); 181} |