1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> 4 */ 5 6 #include <common.h> 7 #include <command.h> 8 #include <errno.h> 9 #include <malloc.h> 10 #include <qfw.h> 11 #include <asm/io.h> 12 #ifdef CONFIG_GENERATE_ACPI_TABLE 13 #include <asm/tables.h> 14 #endif 15 #include <linux/list.h> 16 17 static bool fwcfg_present; 18 static bool fwcfg_dma_present; 19 static struct fw_cfg_arch_ops *fwcfg_arch_ops; 20 21 static LIST_HEAD(fw_list); 22 23 #ifdef CONFIG_GENERATE_ACPI_TABLE 24 /* 25 * This function allocates memory for ACPI tables 26 * 27 * @entry : BIOS linker command entry which tells where to allocate memory 28 * (either high memory or low memory) 29 * @addr : The address that should be used for low memory allcation. If the 30 * memory allocation request is 'ZONE_HIGH' then this parameter will 31 * be ignored. 32 * @return: 0 on success, or negative value on failure 33 */ 34 static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) 35 { 36 uint32_t size, align; 37 struct fw_file *file; 38 unsigned long aligned_addr; 39 40 align = le32_to_cpu(entry->alloc.align); 41 /* align must be power of 2 */ 42 if (align & (align - 1)) { 43 printf("error: wrong alignment %u\n", align); 44 return -EINVAL; 45 } 46 47 file = qemu_fwcfg_find_file(entry->alloc.file); 48 if (!file) { 49 printf("error: can't find file %s\n", entry->alloc.file); 50 return -ENOENT; 51 } 52 53 size = be32_to_cpu(file->cfg.size); 54 55 /* 56 * ZONE_HIGH means we need to allocate from high memory, since 57 * malloc space is already at the end of RAM, so we directly use it. 58 * If allocation zone is ZONE_FSEG, then we use the 'addr' passed 59 * in which is low memory 60 */ 61 if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { 62 aligned_addr = (unsigned long)memalign(align, size); 63 if (!aligned_addr) { 64 printf("error: allocating resource\n"); 65 return -ENOMEM; 66 } 67 } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) { 68 aligned_addr = ALIGN(*addr, align); 69 } else { 70 printf("error: invalid allocation zone\n"); 71 return -EINVAL; 72 } 73 74 debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", 75 file->cfg.name, size, entry->alloc.zone, align, aligned_addr); 76 77 qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), 78 size, (void *)aligned_addr); 79 file->addr = aligned_addr; 80 81 /* adjust address for low memory allocation */ 82 if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) 83 *addr = (aligned_addr + size); 84 85 return 0; 86 } 87 88 /* 89 * This function patches ACPI tables previously loaded 90 * by bios_linker_allocate() 91 * 92 * @entry : BIOS linker command entry which tells how to patch 93 * ACPI tables 94 * @return: 0 on success, or negative value on failure 95 */ 96 static int bios_linker_add_pointer(struct bios_linker_entry *entry) 97 { 98 struct fw_file *dest, *src; 99 uint32_t offset = le32_to_cpu(entry->pointer.offset); 100 uint64_t pointer = 0; 101 102 dest = qemu_fwcfg_find_file(entry->pointer.dest_file); 103 if (!dest || !dest->addr) 104 return -ENOENT; 105 src = qemu_fwcfg_find_file(entry->pointer.src_file); 106 if (!src || !src->addr) 107 return -ENOENT; 108 109 debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n", 110 dest->addr, src->addr, offset, entry->pointer.size, pointer); 111 112 memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size); 113 pointer = le64_to_cpu(pointer); 114 pointer += (unsigned long)src->addr; 115 pointer = cpu_to_le64(pointer); 116 memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size); 117 118 return 0; 119 } 120 121 /* 122 * This function updates checksum fields of ACPI tables previously loaded 123 * by bios_linker_allocate() 124 * 125 * @entry : BIOS linker command entry which tells where to update ACPI table 126 * checksums 127 * @return: 0 on success, or negative value on failure 128 */ 129 static int bios_linker_add_checksum(struct bios_linker_entry *entry) 130 { 131 struct fw_file *file; 132 uint8_t *data, cksum = 0; 133 uint8_t *cksum_start; 134 135 file = qemu_fwcfg_find_file(entry->cksum.file); 136 if (!file || !file->addr) 137 return -ENOENT; 138 139 data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset)); 140 cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start)); 141 cksum = table_compute_checksum(cksum_start, 142 le32_to_cpu(entry->cksum.length)); 143 *data = cksum; 144 145 return 0; 146 } 147 148 /* This function loads and patches ACPI tables provided by QEMU */ 149 ulong write_acpi_tables(ulong addr) 150 { 151 int i, ret = 0; 152 struct fw_file *file; 153 struct bios_linker_entry *table_loader; 154 struct bios_linker_entry *entry; 155 uint32_t size; 156 157 /* make sure fw_list is loaded */ 158 ret = qemu_fwcfg_read_firmware_list(); 159 if (ret) { 160 printf("error: can't read firmware file list\n"); 161 return addr; 162 } 163 164 file = qemu_fwcfg_find_file("etc/table-loader"); 165 if (!file) { 166 printf("error: can't find etc/table-loader\n"); 167 return addr; 168 } 169 170 size = be32_to_cpu(file->cfg.size); 171 if ((size % sizeof(*entry)) != 0) { 172 printf("error: table-loader maybe corrupted\n"); 173 return addr; 174 } 175 176 table_loader = malloc(size); 177 if (!table_loader) { 178 printf("error: no memory for table-loader\n"); 179 return addr; 180 } 181 182 qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), 183 size, table_loader); 184 185 for (i = 0; i < (size / sizeof(*entry)); i++) { 186 entry = table_loader + i; 187 switch (le32_to_cpu(entry->command)) { 188 case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: 189 ret = bios_linker_allocate(entry, &addr); 190 if (ret) 191 goto out; 192 break; 193 case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: 194 ret = bios_linker_add_pointer(entry); 195 if (ret) 196 goto out; 197 break; 198 case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: 199 ret = bios_linker_add_checksum(entry); 200 if (ret) 201 goto out; 202 break; 203 default: 204 break; 205 } 206 } 207 208 out: 209 if (ret) { 210 struct fw_cfg_file_iter iter; 211 for (file = qemu_fwcfg_file_iter_init(&iter); 212 !qemu_fwcfg_file_iter_end(&iter); 213 file = qemu_fwcfg_file_iter_next(&iter)) { 214 if (file->addr) { 215 free((void *)file->addr); 216 file->addr = 0; 217 } 218 } 219 } 220 221 free(table_loader); 222 return addr; 223 } 224 225 ulong acpi_get_rsdp_addr(void) 226 { 227 struct fw_file *file; 228 229 file = qemu_fwcfg_find_file("etc/acpi/rsdp"); 230 return file->addr; 231 } 232 #endif 233 234 /* Read configuration item using fw_cfg PIO interface */ 235 static void qemu_fwcfg_read_entry_pio(uint16_t entry, 236 uint32_t size, void *address) 237 { 238 debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", 239 entry, size, address); 240 241 return fwcfg_arch_ops->arch_read_pio(entry, size, address); 242 } 243 244 /* Read configuration item using fw_cfg DMA interface */ 245 static void qemu_fwcfg_read_entry_dma(uint16_t entry, 246 uint32_t size, void *address) 247 { 248 struct fw_cfg_dma_access dma; 249 250 dma.length = cpu_to_be32(size); 251 dma.address = cpu_to_be64((uintptr_t)address); 252 dma.control = cpu_to_be32(FW_CFG_DMA_READ); 253 254 /* 255 * writting FW_CFG_INVALID will cause read operation to resume at 256 * last offset, otherwise read will start at offset 0 257 */ 258 if (entry != FW_CFG_INVALID) 259 dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16)); 260 261 barrier(); 262 263 debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", 264 entry, size, address, be32_to_cpu(dma.control)); 265 266 fwcfg_arch_ops->arch_read_dma(&dma); 267 } 268 269 bool qemu_fwcfg_present(void) 270 { 271 return fwcfg_present; 272 } 273 274 bool qemu_fwcfg_dma_present(void) 275 { 276 return fwcfg_dma_present; 277 } 278 279 void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address) 280 { 281 if (fwcfg_dma_present) 282 qemu_fwcfg_read_entry_dma(entry, length, address); 283 else 284 qemu_fwcfg_read_entry_pio(entry, length, address); 285 } 286 287 int qemu_fwcfg_online_cpus(void) 288 { 289 uint16_t nb_cpus; 290 291 if (!fwcfg_present) 292 return -ENODEV; 293 294 qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus); 295 296 return le16_to_cpu(nb_cpus); 297 } 298 299 int qemu_fwcfg_read_firmware_list(void) 300 { 301 int i; 302 uint32_t count; 303 struct fw_file *file; 304 struct list_head *entry; 305 306 /* don't read it twice */ 307 if (!list_empty(&fw_list)) 308 return 0; 309 310 qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count); 311 if (!count) 312 return 0; 313 314 count = be32_to_cpu(count); 315 for (i = 0; i < count; i++) { 316 file = malloc(sizeof(*file)); 317 if (!file) { 318 printf("error: allocating resource\n"); 319 goto err; 320 } 321 qemu_fwcfg_read_entry(FW_CFG_INVALID, 322 sizeof(struct fw_cfg_file), &file->cfg); 323 file->addr = 0; 324 list_add_tail(&file->list, &fw_list); 325 } 326 327 return 0; 328 329 err: 330 list_for_each(entry, &fw_list) { 331 file = list_entry(entry, struct fw_file, list); 332 free(file); 333 } 334 335 return -ENOMEM; 336 } 337 338 struct fw_file *qemu_fwcfg_find_file(const char *name) 339 { 340 struct list_head *entry; 341 struct fw_file *file; 342 343 list_for_each(entry, &fw_list) { 344 file = list_entry(entry, struct fw_file, list); 345 if (!strcmp(file->cfg.name, name)) 346 return file; 347 } 348 349 return NULL; 350 } 351 352 struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) 353 { 354 iter->entry = fw_list.next; 355 return list_entry((struct list_head *)iter->entry, 356 struct fw_file, list); 357 } 358 359 struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) 360 { 361 iter->entry = ((struct list_head *)iter->entry)->next; 362 return list_entry((struct list_head *)iter->entry, 363 struct fw_file, list); 364 } 365 366 bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) 367 { 368 return iter->entry == &fw_list; 369 } 370 371 void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) 372 { 373 uint32_t qemu; 374 uint32_t dma_enabled; 375 376 fwcfg_present = false; 377 fwcfg_dma_present = false; 378 fwcfg_arch_ops = NULL; 379 380 if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) 381 return; 382 fwcfg_arch_ops = ops; 383 384 qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); 385 if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) 386 fwcfg_present = true; 387 388 if (fwcfg_present) { 389 qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); 390 if (dma_enabled & FW_CFG_DMA_ENABLED) 391 fwcfg_dma_present = true; 392 } 393 } 394