Tom Rini | 10e4779 | 2018-05-06 17:58:06 -0400 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 2 | /* |
| 3 | * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | #ifndef __FW_CFG__ |
| 7 | #define __FW_CFG__ |
| 8 | |
Miao Yan | c90a058 | 2016-01-20 01:57:04 -0800 | [diff] [blame] | 9 | #include <linux/list.h> |
| 10 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 11 | /* |
| 12 | * List of firmware configuration item selectors. The official source of truth |
| 13 | * for these is the QEMU source itself; see |
| 14 | * https://github.com/qemu/qemu/blob/master/hw/nvram/fw_cfg.c |
| 15 | */ |
| 16 | enum { |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 17 | FW_CFG_SIGNATURE = 0x00, |
| 18 | FW_CFG_ID = 0x01, |
| 19 | FW_CFG_UUID = 0x02, |
| 20 | FW_CFG_RAM_SIZE = 0x03, |
| 21 | FW_CFG_NOGRAPHIC = 0x04, |
| 22 | FW_CFG_NB_CPUS = 0x05, |
| 23 | FW_CFG_MACHINE_ID = 0x06, |
| 24 | FW_CFG_KERNEL_ADDR = 0x07, |
| 25 | FW_CFG_KERNEL_SIZE = 0x08, |
| 26 | FW_CFG_KERNEL_CMDLINE = 0x09, |
| 27 | FW_CFG_INITRD_ADDR = 0x0a, |
| 28 | FW_CFG_INITRD_SIZE = 0x0b, |
| 29 | FW_CFG_BOOT_DEVICE = 0x0c, |
| 30 | FW_CFG_NUMA = 0x0d, |
| 31 | FW_CFG_BOOT_MENU = 0x0e, |
| 32 | FW_CFG_MAX_CPUS = 0x0f, |
| 33 | FW_CFG_KERNEL_ENTRY = 0x10, |
| 34 | FW_CFG_KERNEL_DATA = 0x11, |
| 35 | FW_CFG_INITRD_DATA = 0x12, |
| 36 | FW_CFG_CMDLINE_ADDR = 0x13, |
| 37 | FW_CFG_CMDLINE_SIZE = 0x14, |
| 38 | FW_CFG_CMDLINE_DATA = 0x15, |
| 39 | FW_CFG_SETUP_ADDR = 0x16, |
| 40 | FW_CFG_SETUP_SIZE = 0x17, |
| 41 | FW_CFG_SETUP_DATA = 0x18, |
| 42 | FW_CFG_FILE_DIR = 0x19, |
| 43 | FW_CFG_FILE_FIRST = 0x20, |
| 44 | FW_CFG_WRITE_CHANNEL = 0x4000, |
| 45 | FW_CFG_ARCH_LOCAL = 0x8000, |
| 46 | FW_CFG_INVALID = 0xffff, |
| 47 | }; |
| 48 | |
Miao Yan | 3b68c52 | 2016-01-20 01:57:06 -0800 | [diff] [blame] | 49 | enum { |
| 50 | BIOS_LINKER_LOADER_COMMAND_ALLOCATE = 0x1, |
| 51 | BIOS_LINKER_LOADER_COMMAND_ADD_POINTER = 0x2, |
| 52 | BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3, |
| 53 | }; |
| 54 | |
| 55 | enum { |
| 56 | BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1, |
| 57 | BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2, |
| 58 | }; |
| 59 | |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 60 | #define FW_CFG_FILE_SLOTS 0x10 |
| 61 | #define FW_CFG_MAX_ENTRY (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS) |
| 62 | #define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) |
| 63 | |
| 64 | #define FW_CFG_MAX_FILE_PATH 56 |
Miao Yan | 3b68c52 | 2016-01-20 01:57:06 -0800 | [diff] [blame] | 65 | #define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 66 | |
| 67 | #define QEMU_FW_CFG_SIGNATURE (('Q' << 24) | ('E' << 16) | ('M' << 8) | 'U') |
| 68 | |
| 69 | #define FW_CFG_DMA_ERROR (1 << 0) |
| 70 | #define FW_CFG_DMA_READ (1 << 1) |
| 71 | #define FW_CFG_DMA_SKIP (1 << 2) |
| 72 | #define FW_CFG_DMA_SELECT (1 << 3) |
| 73 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 74 | /* Bit set in FW_CFG_ID response to indicate DMA interface availability. */ |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 75 | #define FW_CFG_DMA_ENABLED (1 << 1) |
| 76 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 77 | /* Structs read from FW_CFG_FILE_DIR. */ |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 78 | struct fw_cfg_file { |
| 79 | __be32 size; |
| 80 | __be16 select; |
| 81 | __be16 reserved; |
| 82 | char name[FW_CFG_MAX_FILE_PATH]; |
| 83 | }; |
| 84 | |
Miao Yan | c90a058 | 2016-01-20 01:57:04 -0800 | [diff] [blame] | 85 | struct fw_file { |
| 86 | struct fw_cfg_file cfg; /* firmware file information */ |
| 87 | unsigned long addr; /* firmware file in-memory address */ |
| 88 | struct list_head list; /* list node to link to fw_list */ |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 89 | }; |
| 90 | |
Miao Yan | 1dcb0f1 | 2016-05-22 19:37:11 -0700 | [diff] [blame] | 91 | struct fw_cfg_file_iter { |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 92 | struct list_head *entry, *end; /* structures to iterate file list */ |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 93 | }; |
| 94 | |
Miao Yan | 3b68c52 | 2016-01-20 01:57:06 -0800 | [diff] [blame] | 95 | struct bios_linker_entry { |
| 96 | __le32 command; |
| 97 | union { |
| 98 | /* |
| 99 | * COMMAND_ALLOCATE - allocate a table from @alloc.file |
| 100 | * subject to @alloc.align alignment (must be power of 2) |
| 101 | * and @alloc.zone (can be HIGH or FSEG) requirements. |
| 102 | * |
| 103 | * Must appear exactly once for each file, and before |
| 104 | * this file is referenced by any other command. |
| 105 | */ |
| 106 | struct { |
| 107 | char file[BIOS_LINKER_LOADER_FILESZ]; |
| 108 | __le32 align; |
| 109 | uint8_t zone; |
| 110 | } alloc; |
| 111 | |
| 112 | /* |
| 113 | * COMMAND_ADD_POINTER - patch the table (originating from |
| 114 | * @dest_file) at @pointer.offset, by adding a pointer to the |
| 115 | * table originating from @src_file. 1,2,4 or 8 byte unsigned |
| 116 | * addition is used depending on @pointer.size. |
| 117 | */ |
| 118 | struct { |
| 119 | char dest_file[BIOS_LINKER_LOADER_FILESZ]; |
| 120 | char src_file[BIOS_LINKER_LOADER_FILESZ]; |
| 121 | __le32 offset; |
| 122 | uint8_t size; |
| 123 | } pointer; |
| 124 | |
| 125 | /* |
| 126 | * COMMAND_ADD_CHECKSUM - calculate checksum of the range |
| 127 | * specified by @cksum_start and @cksum_length fields, |
| 128 | * and then add the value at @cksum.offset. |
| 129 | * Checksum simply sums -X for each byte X in the range |
| 130 | * using 8-bit math. |
| 131 | */ |
| 132 | struct { |
| 133 | char file[BIOS_LINKER_LOADER_FILESZ]; |
| 134 | __le32 offset; |
| 135 | __le32 start; |
| 136 | __le32 length; |
| 137 | } cksum; |
| 138 | |
| 139 | /* padding */ |
| 140 | char pad[124]; |
| 141 | }; |
| 142 | } __packed; |
| 143 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 144 | /* DMA transfer control data between UCLASS_QFW and QEMU. */ |
| 145 | struct qfw_dma { |
| 146 | __be32 control; |
| 147 | __be32 length; |
| 148 | __be64 address; |
| 149 | }; |
| 150 | |
| 151 | /* uclass per-device configuration information */ |
| 152 | struct qfw_dev { |
| 153 | struct udevice *dev; /* Transport device */ |
| 154 | bool dma_present; /* DMA interface usable? */ |
| 155 | struct list_head fw_list; /* Cached firmware file list */ |
| 156 | }; |
| 157 | |
| 158 | /* Ops used internally between UCLASS_QFW and its driver implementations. */ |
| 159 | struct dm_qfw_ops { |
| 160 | /** |
| 161 | * read_entry_io() - Read a firmware config entry using the regular |
| 162 | * IO interface for the platform (either PIO or MMIO) |
| 163 | * |
| 164 | * Supply %FW_CFG_INVALID as the entry to continue a previous read. In |
| 165 | * this case, no selector will be issued before reading. |
| 166 | * |
| 167 | * @dev: Device to use |
| 168 | * @entry: Firmware config entry number (e.g. %FW_CFG_SIGNATURE) |
| 169 | * @size: Number of bytes to read |
| 170 | * @address: Target location for read |
| 171 | */ |
| 172 | void (*read_entry_io)(struct udevice *dev, u16 entry, u32 size, |
| 173 | void *address); |
| 174 | |
| 175 | /** |
| 176 | * read_entry_dma() - Read a firmware config entry using the DMA |
| 177 | * interface |
| 178 | * |
| 179 | * Supply FW_CFG_INVALID as the entry to continue a previous read. In |
| 180 | * this case, no selector will be issued before reading. |
| 181 | * |
| 182 | * This method assumes DMA availability has already been confirmed. |
| 183 | * |
| 184 | * @dev: Device to use |
| 185 | * @dma: DMA transfer control struct |
| 186 | */ |
| 187 | void (*read_entry_dma)(struct udevice *dev, struct qfw_dma *dma); |
| 188 | }; |
| 189 | |
| 190 | #define dm_qfw_get_ops(dev) \ |
| 191 | ((struct dm_qfw_ops *)(dev)->driver->ops) |
| 192 | |
| 193 | /** |
| 194 | * qfw_register() - Called by a qfw driver after successful probe. |
| 195 | * @dev: Device registering itself with the uclass. |
| 196 | * |
| 197 | * Used internally by driver implementations on successful probe. |
| 198 | * |
| 199 | * Return: 0 on success, negative otherwise. |
| 200 | */ |
| 201 | int qfw_register(struct udevice *dev); |
| 202 | |
| 203 | struct udevice; |
| 204 | |
| 205 | /** |
| 206 | * qfw_get_dev() - Get QEMU firmware config device. |
| 207 | * @devp: Pointer to be filled with address of the qfw device. |
| 208 | * |
| 209 | * Gets the active QEMU firmware config device, for use with qfw_read_entry() |
| 210 | * and others. |
| 211 | * |
| 212 | * Return: 0 on success, -ENODEV if the device is not available. |
| 213 | */ |
| 214 | int qfw_get_dev(struct udevice **devp); |
| 215 | |
| 216 | /** |
| 217 | * qfw_read_entry() - Read a QEMU firmware config entry |
| 218 | * @dev: QFW device to use. |
| 219 | * @entry: Firmware config entry number (e.g. %FW_CFG_SIGNATURE). |
| 220 | * @size: Number of bytes to read. |
| 221 | * @address: Target location for read. |
| 222 | * |
| 223 | * Reads a QEMU firmware config entry using @dev. DMA will be used if the QEMU |
| 224 | * machine supports it, otherwise PIO/MMIO. |
| 225 | */ |
| 226 | void qfw_read_entry(struct udevice *dev, u16 entry, u32 size, void *address); |
| 227 | |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 228 | /** |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 229 | * qfw_read_firmware_list() - Read and cache the QEMU firmware config file |
| 230 | * list. |
| 231 | * @dev: QFW device to use. |
| 232 | * |
| 233 | * Reads the QEMU firmware config file list, caching it against @dev for later |
| 234 | * use with qfw_find_file(). |
| 235 | * |
| 236 | * If the list has already been read, does nothing and returns 0 (success). |
| 237 | * |
| 238 | * Return: 0 on success, -ENOMEM if unable to allocate. |
| 239 | */ |
| 240 | int qfw_read_firmware_list(struct udevice *dev); |
| 241 | |
| 242 | /** |
| 243 | * qfw_find_file() - Find a file by name in the QEMU firmware config file |
| 244 | * list. |
| 245 | * @dev: QFW device to use. |
| 246 | * @name: Name of file to locate (e.g. "etc/table-loader"). |
| 247 | * |
| 248 | * Finds a file by name in the QEMU firmware config file list cached against |
| 249 | * @dev. You must call qfw_read_firmware_list() successfully first for this to |
| 250 | * succeed. |
Miao Yan | 8a15383 | 2016-05-22 19:37:15 -0700 | [diff] [blame] | 251 | * |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 252 | * Return: Pointer to &struct fw_file if found, %NULL if not present. |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 253 | */ |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 254 | struct fw_file *qfw_find_file(struct udevice *dev, const char *name); |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 255 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 256 | /** |
| 257 | * qfw_online_cpus() - Get number of CPUs in system from QEMU firmware config. |
| 258 | * @dev: QFW device to use. |
| 259 | * |
| 260 | * Asks QEMU to report how many CPUs it is emulating for the machine. |
| 261 | * |
| 262 | * Return: Number of CPUs in the system. |
| 263 | */ |
| 264 | int qfw_online_cpus(struct udevice *dev); |
Tom Rini | bcb3c8d | 2016-05-06 10:40:22 -0400 | [diff] [blame] | 265 | |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 266 | /** |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 267 | * qfw_file_iter_init() - Start iterating cached firmware file list. |
| 268 | * @dev: QFW device to use. |
| 269 | * @iter: Iterator to be initialised. |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 270 | * |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 271 | * Starts iterating the cached firmware file list in @dev. You must call |
| 272 | * qfw_read_firmware_list() successfully first, otherwise you will always get |
| 273 | * an empty list. |
| 274 | * |
| 275 | * qfw_file_iter_init() returns the first &struct fw_file, but it may be |
| 276 | * invalid if the list is empty. Check that ``!qfw_file_iter_end(&iter)`` |
| 277 | * first. |
| 278 | * |
| 279 | * Return: The first &struct fw_file item in the firmware file list, if any. |
| 280 | * Only valid when qfw_file_iter_end() is not true after the call. |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 281 | */ |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 282 | struct fw_file *qfw_file_iter_init(struct udevice *dev, |
| 283 | struct fw_cfg_file_iter *iter); |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 284 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 285 | /** |
| 286 | * qfw_file_iter_next() - Iterate cached firmware file list. |
| 287 | * @iter: Iterator to use. |
| 288 | * |
| 289 | * Continues iterating the cached firmware file list in @dev. You must call |
| 290 | * qfw_file_iter_init() first to initialise it. Check that |
| 291 | * ``!qfw_file_iter_end(&iter)`` before using the return value of this |
| 292 | * function. |
| 293 | * |
| 294 | * Return: The next &struct fw_file item in the firmware file list. Only valid |
| 295 | * when qfw_file_iter_end() is not true after the call. |
| 296 | */ |
| 297 | struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter); |
Miao Yan | 1dcb0f1 | 2016-05-22 19:37:11 -0700 | [diff] [blame] | 298 | |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 299 | /** |
| 300 | * qfw_file_iter_end() - Check if iter is at end of list. |
| 301 | * @iter: Iterator to use. |
| 302 | * |
| 303 | * Checks whether or not the iterator is at its end position. If so, the |
| 304 | * qfw_file_iter_init() or qfw_file_iter_next() call that immediately preceded |
| 305 | * returned invalid data. |
| 306 | * |
| 307 | * Return: True if the iterator is at its end; false otherwise. |
| 308 | */ |
| 309 | bool qfw_file_iter_end(struct fw_cfg_file_iter *iter); |
Miao Yan | 73b7e18 | 2016-05-22 19:37:13 -0700 | [diff] [blame] | 310 | |
Simon Glass | 4c8243d | 2019-12-06 21:42:55 -0700 | [diff] [blame] | 311 | /** |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 312 | * qemu_cpu_fixup() - Fix up the CPUs for QEMU. |
Simon Glass | 4c8243d | 2019-12-06 21:42:55 -0700 | [diff] [blame] | 313 | * |
Asherah Connor | 4ffa95d | 2021-03-19 18:21:40 +1100 | [diff] [blame] | 314 | * Return: 0 on success, -ENODEV if no CPUs, -ENOMEM if out of memory, other < |
| 315 | * 0 on on other error. |
Simon Glass | 4c8243d | 2019-12-06 21:42:55 -0700 | [diff] [blame] | 316 | */ |
| 317 | int qemu_cpu_fixup(void); |
| 318 | |
Miao Yan | 58a3ce2 | 2016-01-07 01:32:00 -0800 | [diff] [blame] | 319 | #endif |