xref: /openbmc/qemu/hw/acpi/bios-linker-loader.c (revision a050901d)
109852232SMichael S. Tsirkin /* Dynamic linker/loader of ACPI tables
209852232SMichael S. Tsirkin  *
309852232SMichael S. Tsirkin  * Copyright (C) 2013 Red Hat Inc
409852232SMichael S. Tsirkin  *
509852232SMichael S. Tsirkin  * Author: Michael S. Tsirkin <mst@redhat.com>
609852232SMichael S. Tsirkin  *
709852232SMichael S. Tsirkin  * This program is free software; you can redistribute it and/or modify
809852232SMichael S. Tsirkin  * it under the terms of the GNU General Public License as published by
909852232SMichael S. Tsirkin  * the Free Software Foundation; either version 2 of the License, or
1009852232SMichael S. Tsirkin  * (at your option) any later version.
1109852232SMichael S. Tsirkin 
1209852232SMichael S. Tsirkin  * This program is distributed in the hope that it will be useful,
1309852232SMichael S. Tsirkin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1409852232SMichael S. Tsirkin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1509852232SMichael S. Tsirkin  * GNU General Public License for more details.
1609852232SMichael S. Tsirkin 
1709852232SMichael S. Tsirkin  * You should have received a copy of the GNU General Public License along
1809852232SMichael S. Tsirkin  * with this program; if not, see <http://www.gnu.org/licenses/>.
1909852232SMichael S. Tsirkin  */
2009852232SMichael S. Tsirkin 
21b6a0aa05SPeter Maydell #include "qemu/osdep.h"
2209852232SMichael S. Tsirkin #include "hw/acpi/bios-linker-loader.h"
2309852232SMichael S. Tsirkin #include "hw/nvram/fw_cfg.h"
2409852232SMichael S. Tsirkin 
2509852232SMichael S. Tsirkin #include "qemu/bswap.h"
2609852232SMichael S. Tsirkin 
27b54ca0c3SMichael S. Tsirkin /*
28b54ca0c3SMichael S. Tsirkin  * Linker/loader is a paravirtualized interface that passes commands to guest.
29b54ca0c3SMichael S. Tsirkin  * The commands can be used to request guest to
30b54ca0c3SMichael S. Tsirkin  * - allocate memory chunks and initialize them from QEMU FW CFG files
31b54ca0c3SMichael S. Tsirkin  * - link allocated chunks by storing pointer to one chunk into another
32b54ca0c3SMichael S. Tsirkin  * - calculate ACPI checksum of part of the chunk and store into same chunk
33b54ca0c3SMichael S. Tsirkin  */
3409852232SMichael S. Tsirkin #define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
3509852232SMichael S. Tsirkin 
3609852232SMichael S. Tsirkin struct BiosLinkerLoaderEntry {
3709852232SMichael S. Tsirkin     uint32_t command;
3809852232SMichael S. Tsirkin     union {
3909852232SMichael S. Tsirkin         /*
4009852232SMichael S. Tsirkin          * COMMAND_ALLOCATE - allocate a table from @alloc.file
4109852232SMichael S. Tsirkin          * subject to @alloc.align alignment (must be power of 2)
4209852232SMichael S. Tsirkin          * and @alloc.zone (can be HIGH or FSEG) requirements.
4309852232SMichael S. Tsirkin          *
4409852232SMichael S. Tsirkin          * Must appear exactly once for each file, and before
4509852232SMichael S. Tsirkin          * this file is referenced by any other command.
4609852232SMichael S. Tsirkin          */
4709852232SMichael S. Tsirkin         struct {
4809852232SMichael S. Tsirkin             char file[BIOS_LINKER_LOADER_FILESZ];
4909852232SMichael S. Tsirkin             uint32_t align;
5009852232SMichael S. Tsirkin             uint8_t zone;
5109852232SMichael S. Tsirkin         } alloc;
5209852232SMichael S. Tsirkin 
5309852232SMichael S. Tsirkin         /*
5409852232SMichael S. Tsirkin          * COMMAND_ADD_POINTER - patch the table (originating from
5509852232SMichael S. Tsirkin          * @dest_file) at @pointer.offset, by adding a pointer to the table
5609852232SMichael S. Tsirkin          * originating from @src_file. 1,2,4 or 8 byte unsigned
5709852232SMichael S. Tsirkin          * addition is used depending on @pointer.size.
5809852232SMichael S. Tsirkin          */
5909852232SMichael S. Tsirkin         struct {
6009852232SMichael S. Tsirkin             char dest_file[BIOS_LINKER_LOADER_FILESZ];
6109852232SMichael S. Tsirkin             char src_file[BIOS_LINKER_LOADER_FILESZ];
6209852232SMichael S. Tsirkin             uint32_t offset;
6309852232SMichael S. Tsirkin             uint8_t size;
6409852232SMichael S. Tsirkin         } pointer;
6509852232SMichael S. Tsirkin 
6609852232SMichael S. Tsirkin         /*
6709852232SMichael S. Tsirkin          * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
6809852232SMichael S. Tsirkin          * @cksum_start and @cksum_length fields,
6909852232SMichael S. Tsirkin          * and then add the value at @cksum.offset.
7009852232SMichael S. Tsirkin          * Checksum simply sums -X for each byte X in the range
7109852232SMichael S. Tsirkin          * using 8-bit math.
7209852232SMichael S. Tsirkin          */
7309852232SMichael S. Tsirkin         struct {
7409852232SMichael S. Tsirkin             char file[BIOS_LINKER_LOADER_FILESZ];
7509852232SMichael S. Tsirkin             uint32_t offset;
7609852232SMichael S. Tsirkin             uint32_t start;
7709852232SMichael S. Tsirkin             uint32_t length;
7809852232SMichael S. Tsirkin         } cksum;
7909852232SMichael S. Tsirkin 
80489886d1SBen Warren         /*
81489886d1SBen Warren          * COMMAND_WRITE_POINTER - write the fw_cfg file (originating from
82489886d1SBen Warren          * @dest_file) at @wr_pointer.offset, by adding a pointer to
83489886d1SBen Warren          * @src_offset within the table originating from @src_file.
84489886d1SBen Warren          * 1,2,4 or 8 byte unsigned addition is used depending on
85489886d1SBen Warren          * @wr_pointer.size.
86489886d1SBen Warren          */
87489886d1SBen Warren         struct {
88489886d1SBen Warren             char dest_file[BIOS_LINKER_LOADER_FILESZ];
89489886d1SBen Warren             char src_file[BIOS_LINKER_LOADER_FILESZ];
90489886d1SBen Warren             uint32_t dst_offset;
91489886d1SBen Warren             uint32_t src_offset;
92489886d1SBen Warren             uint8_t size;
93489886d1SBen Warren         } wr_pointer;
94489886d1SBen Warren 
9509852232SMichael S. Tsirkin         /* padding */
9609852232SMichael S. Tsirkin         char pad[124];
9709852232SMichael S. Tsirkin     };
9809852232SMichael S. Tsirkin } QEMU_PACKED;
9909852232SMichael S. Tsirkin typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
10009852232SMichael S. Tsirkin 
10109852232SMichael S. Tsirkin enum {
10209852232SMichael S. Tsirkin     BIOS_LINKER_LOADER_COMMAND_ALLOCATE          = 0x1,
10309852232SMichael S. Tsirkin     BIOS_LINKER_LOADER_COMMAND_ADD_POINTER       = 0x2,
10409852232SMichael S. Tsirkin     BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM      = 0x3,
105489886d1SBen Warren     BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER     = 0x4,
10609852232SMichael S. Tsirkin };
10709852232SMichael S. Tsirkin 
10809852232SMichael S. Tsirkin enum {
10909852232SMichael S. Tsirkin     BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
11009852232SMichael S. Tsirkin     BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
11109852232SMichael S. Tsirkin };
11209852232SMichael S. Tsirkin 
113b54ca0c3SMichael S. Tsirkin /*
114ad9671b8SIgor Mammedov  * BiosLinkerFileEntry:
115ad9671b8SIgor Mammedov  *
116ad9671b8SIgor Mammedov  * An internal type used for book-keeping file entries
117ad9671b8SIgor Mammedov  */
118ad9671b8SIgor Mammedov typedef struct BiosLinkerFileEntry {
119ad9671b8SIgor Mammedov     char *name; /* file name */
120ad9671b8SIgor Mammedov     GArray *blob; /* data accosiated with @name */
121ad9671b8SIgor Mammedov } BiosLinkerFileEntry;
122ad9671b8SIgor Mammedov 
123ad9671b8SIgor Mammedov /*
1240e9b9edaSIgor Mammedov  * bios_linker_loader_init: allocate a new linker object instance.
125b54ca0c3SMichael S. Tsirkin  *
126b54ca0c3SMichael S. Tsirkin  * After initialization, linker commands can be added, and will
1270e9b9edaSIgor Mammedov  * be stored in the linker.cmd_blob array.
128b54ca0c3SMichael S. Tsirkin  */
bios_linker_loader_init(void)1290e9b9edaSIgor Mammedov BIOSLinker *bios_linker_loader_init(void)
13009852232SMichael S. Tsirkin {
1310e9b9edaSIgor Mammedov     BIOSLinker *linker = g_new(BIOSLinker, 1);
1320e9b9edaSIgor Mammedov 
1330e9b9edaSIgor Mammedov     linker->cmd_blob = g_array_new(false, true /* clear */, 1);
134ad9671b8SIgor Mammedov     linker->file_list = g_array_new(false, true /* clear */,
135ad9671b8SIgor Mammedov                                     sizeof(BiosLinkerFileEntry));
1360e9b9edaSIgor Mammedov     return linker;
13709852232SMichael S. Tsirkin }
13809852232SMichael S. Tsirkin 
1398cc87c31SIgor Mammedov /* Free linker wrapper */
bios_linker_loader_cleanup(BIOSLinker * linker)1408cc87c31SIgor Mammedov void bios_linker_loader_cleanup(BIOSLinker *linker)
14109852232SMichael S. Tsirkin {
142ad9671b8SIgor Mammedov     int i;
143ad9671b8SIgor Mammedov     BiosLinkerFileEntry *entry;
1448cc87c31SIgor Mammedov 
1458cc87c31SIgor Mammedov     g_array_free(linker->cmd_blob, true);
1460e9b9edaSIgor Mammedov 
147ad9671b8SIgor Mammedov     for (i = 0; i < linker->file_list->len; i++) {
148ad9671b8SIgor Mammedov         entry = &g_array_index(linker->file_list, BiosLinkerFileEntry, i);
149ad9671b8SIgor Mammedov         g_free(entry->name);
150ad9671b8SIgor Mammedov     }
151ad9671b8SIgor Mammedov     g_array_free(linker->file_list, true);
1520e9b9edaSIgor Mammedov     g_free(linker);
15309852232SMichael S. Tsirkin }
15409852232SMichael S. Tsirkin 
155ad9671b8SIgor Mammedov static const BiosLinkerFileEntry *
bios_linker_find_file(const BIOSLinker * linker,const char * name)156ad9671b8SIgor Mammedov bios_linker_find_file(const BIOSLinker *linker, const char *name)
157ad9671b8SIgor Mammedov {
158ad9671b8SIgor Mammedov     int i;
159ad9671b8SIgor Mammedov     BiosLinkerFileEntry *entry;
160ad9671b8SIgor Mammedov 
161ad9671b8SIgor Mammedov     for (i = 0; i < linker->file_list->len; i++) {
162ad9671b8SIgor Mammedov         entry = &g_array_index(linker->file_list, BiosLinkerFileEntry, i);
163ad9671b8SIgor Mammedov         if (!strcmp(entry->name, name)) {
164ad9671b8SIgor Mammedov             return entry;
165ad9671b8SIgor Mammedov         }
166ad9671b8SIgor Mammedov     }
167ad9671b8SIgor Mammedov     return NULL;
168ad9671b8SIgor Mammedov }
169ad9671b8SIgor Mammedov 
170b54ca0c3SMichael S. Tsirkin /*
171c8389550SMarc-André Lureau  * board code must realize fw_cfg first, as a fixed device, before
172c8389550SMarc-André Lureau  * another device realize function call bios_linker_loader_can_write_pointer()
173c8389550SMarc-André Lureau  */
bios_linker_loader_can_write_pointer(void)174c8389550SMarc-André Lureau bool bios_linker_loader_can_write_pointer(void)
175c8389550SMarc-André Lureau {
176c8389550SMarc-André Lureau     FWCfgState *fw_cfg = fw_cfg_find();
177c8389550SMarc-André Lureau     return fw_cfg && fw_cfg_dma_enabled(fw_cfg);
178c8389550SMarc-André Lureau }
179c8389550SMarc-André Lureau 
180c8389550SMarc-André Lureau /*
181b54ca0c3SMichael S. Tsirkin  * bios_linker_loader_alloc: ask guest to load file into guest memory.
182b54ca0c3SMichael S. Tsirkin  *
1830e9b9edaSIgor Mammedov  * @linker: linker object instance
184ad9671b8SIgor Mammedov  * @file_name: name of the file blob to be loaded
185ad9671b8SIgor Mammedov  * @file_blob: pointer to blob corresponding to @file_name
186b54ca0c3SMichael S. Tsirkin  * @alloc_align: required minimal alignment in bytes. Must be a power of 2.
187b54ca0c3SMichael S. Tsirkin  * @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table)
188b54ca0c3SMichael S. Tsirkin  *
189b54ca0c3SMichael S. Tsirkin  * Note: this command must precede any other linker command using this file.
190b54ca0c3SMichael S. Tsirkin  */
bios_linker_loader_alloc(BIOSLinker * linker,const char * file_name,GArray * file_blob,uint32_t alloc_align,bool alloc_fseg)1910e9b9edaSIgor Mammedov void bios_linker_loader_alloc(BIOSLinker *linker,
192ad9671b8SIgor Mammedov                               const char *file_name,
193ad9671b8SIgor Mammedov                               GArray *file_blob,
19409852232SMichael S. Tsirkin                               uint32_t alloc_align,
19509852232SMichael S. Tsirkin                               bool alloc_fseg)
19609852232SMichael S. Tsirkin {
19709852232SMichael S. Tsirkin     BiosLinkerLoaderEntry entry;
198ad9671b8SIgor Mammedov     BiosLinkerFileEntry file = { g_strdup(file_name), file_blob};
19909852232SMichael S. Tsirkin 
200b54ca0c3SMichael S. Tsirkin     assert(!(alloc_align & (alloc_align - 1)));
201b54ca0c3SMichael S. Tsirkin 
202ad9671b8SIgor Mammedov     assert(!bios_linker_find_file(linker, file_name));
203ad9671b8SIgor Mammedov     g_array_append_val(linker->file_list, file);
204ad9671b8SIgor Mammedov 
20509852232SMichael S. Tsirkin     memset(&entry, 0, sizeof entry);
206ad9671b8SIgor Mammedov     strncpy(entry.alloc.file, file_name, sizeof entry.alloc.file - 1);
20709852232SMichael S. Tsirkin     entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE);
20809852232SMichael S. Tsirkin     entry.alloc.align = cpu_to_le32(alloc_align);
2091dbfd789SIgor Mammedov     entry.alloc.zone = alloc_fseg ? BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG :
2101dbfd789SIgor Mammedov                                     BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH;
21109852232SMichael S. Tsirkin 
21209852232SMichael S. Tsirkin     /* Alloc entries must come first, so prepend them */
2130e9b9edaSIgor Mammedov     g_array_prepend_vals(linker->cmd_blob, &entry, sizeof entry);
21409852232SMichael S. Tsirkin }
21509852232SMichael S. Tsirkin 
216b54ca0c3SMichael S. Tsirkin /*
21728213cb6SIgor Mammedov  * bios_linker_loader_add_checksum: ask guest to add checksum of ACPI
21828213cb6SIgor Mammedov  * table in the specified file at the specified offset.
219b54ca0c3SMichael S. Tsirkin  *
220b54ca0c3SMichael S. Tsirkin  * Checksum calculation simply sums -X for each byte X in the range
221b54ca0c3SMichael S. Tsirkin  * using 8-bit math (i.e. ACPI checksum).
222b54ca0c3SMichael S. Tsirkin  *
2230e9b9edaSIgor Mammedov  * @linker: linker object instance
224b54ca0c3SMichael S. Tsirkin  * @file: file that includes the checksum to be calculated
225b54ca0c3SMichael S. Tsirkin  *        and the data to be checksummed
22628213cb6SIgor Mammedov  * @start_offset, @size: range of data in the file to checksum,
22728213cb6SIgor Mammedov  *                       relative to the start of file blob
22828213cb6SIgor Mammedov  * @checksum_offset: location of the checksum to be patched within file blob,
22928213cb6SIgor Mammedov  *                   relative to the start of file blob
230b54ca0c3SMichael S. Tsirkin  */
bios_linker_loader_add_checksum(BIOSLinker * linker,const char * file_name,unsigned start_offset,unsigned size,unsigned checksum_offset)231ad9671b8SIgor Mammedov void bios_linker_loader_add_checksum(BIOSLinker *linker, const char *file_name,
23228213cb6SIgor Mammedov                                      unsigned start_offset, unsigned size,
23328213cb6SIgor Mammedov                                      unsigned checksum_offset)
23409852232SMichael S. Tsirkin {
23509852232SMichael S. Tsirkin     BiosLinkerLoaderEntry entry;
236ad9671b8SIgor Mammedov     const BiosLinkerFileEntry *file = bios_linker_find_file(linker, file_name);
237b54ca0c3SMichael S. Tsirkin 
23828213cb6SIgor Mammedov     assert(file);
23928213cb6SIgor Mammedov     assert(start_offset < file->blob->len);
240ad9671b8SIgor Mammedov     assert(start_offset + size <= file->blob->len);
24128213cb6SIgor Mammedov     assert(checksum_offset >= start_offset);
24228213cb6SIgor Mammedov     assert(checksum_offset + 1 <= start_offset + size);
24309852232SMichael S. Tsirkin 
24428213cb6SIgor Mammedov     *(file->blob->data + checksum_offset) = 0;
24509852232SMichael S. Tsirkin     memset(&entry, 0, sizeof entry);
246ad9671b8SIgor Mammedov     strncpy(entry.cksum.file, file_name, sizeof entry.cksum.file - 1);
24709852232SMichael S. Tsirkin     entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM);
248b54ca0c3SMichael S. Tsirkin     entry.cksum.offset = cpu_to_le32(checksum_offset);
249b54ca0c3SMichael S. Tsirkin     entry.cksum.start = cpu_to_le32(start_offset);
25009852232SMichael S. Tsirkin     entry.cksum.length = cpu_to_le32(size);
25109852232SMichael S. Tsirkin 
2520e9b9edaSIgor Mammedov     g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
25309852232SMichael S. Tsirkin }
25409852232SMichael S. Tsirkin 
255b54ca0c3SMichael S. Tsirkin /*
2564678124bSIgor Mammedov  * bios_linker_loader_add_pointer: ask guest to patch address in
2574678124bSIgor Mammedov  * destination file with a pointer to source file
258b54ca0c3SMichael S. Tsirkin  *
2590e9b9edaSIgor Mammedov  * @linker: linker object instance
260b54ca0c3SMichael S. Tsirkin  * @dest_file: destination file that must be changed
2614678124bSIgor Mammedov  * @dst_patched_offset: location within destination file blob to be patched
2624678124bSIgor Mammedov  *                      with the pointer to @src_file+@src_offset (i.e. source
2634678124bSIgor Mammedov  *                      blob allocated in guest memory + @src_offset), in bytes
2644678124bSIgor Mammedov  * @dst_patched_offset_size: size of the pointer to be patched
2654678124bSIgor Mammedov  *                      at @dst_patched_offset in @dest_file blob, in bytes
266b54ca0c3SMichael S. Tsirkin  * @src_file: source file who's address must be taken
2674678124bSIgor Mammedov  * @src_offset: location within source file blob to which
2684678124bSIgor Mammedov  *              @dest_file+@dst_patched_offset will point to after
2694678124bSIgor Mammedov  *              firmware's executed ADD_POINTER command
270b54ca0c3SMichael S. Tsirkin  */
bios_linker_loader_add_pointer(BIOSLinker * linker,const char * dest_file,uint32_t dst_patched_offset,uint8_t dst_patched_size,const char * src_file,uint32_t src_offset)2710e9b9edaSIgor Mammedov void bios_linker_loader_add_pointer(BIOSLinker *linker,
27209852232SMichael S. Tsirkin                                     const char *dest_file,
2734678124bSIgor Mammedov                                     uint32_t dst_patched_offset,
2744678124bSIgor Mammedov                                     uint8_t dst_patched_size,
27509852232SMichael S. Tsirkin                                     const char *src_file,
2764678124bSIgor Mammedov                                     uint32_t src_offset)
27709852232SMichael S. Tsirkin {
2784678124bSIgor Mammedov     uint64_t le_src_offset;
27909852232SMichael S. Tsirkin     BiosLinkerLoaderEntry entry;
2804678124bSIgor Mammedov     const BiosLinkerFileEntry *dst_file =
2814678124bSIgor Mammedov         bios_linker_find_file(linker, dest_file);
2824678124bSIgor Mammedov     const BiosLinkerFileEntry *source_file =
2834678124bSIgor Mammedov         bios_linker_find_file(linker, src_file);
284b54ca0c3SMichael S. Tsirkin 
285*22132828SLiam Merwick     assert(dst_file);
286*22132828SLiam Merwick     assert(source_file);
2874678124bSIgor Mammedov     assert(dst_patched_offset < dst_file->blob->len);
2884678124bSIgor Mammedov     assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
2894678124bSIgor Mammedov     assert(src_offset < source_file->blob->len);
29009852232SMichael S. Tsirkin 
29109852232SMichael S. Tsirkin     memset(&entry, 0, sizeof entry);
29209852232SMichael S. Tsirkin     strncpy(entry.pointer.dest_file, dest_file,
29309852232SMichael S. Tsirkin             sizeof entry.pointer.dest_file - 1);
29409852232SMichael S. Tsirkin     strncpy(entry.pointer.src_file, src_file,
29509852232SMichael S. Tsirkin             sizeof entry.pointer.src_file - 1);
29609852232SMichael S. Tsirkin     entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
2974678124bSIgor Mammedov     entry.pointer.offset = cpu_to_le32(dst_patched_offset);
2984678124bSIgor Mammedov     entry.pointer.size = dst_patched_size;
2994678124bSIgor Mammedov     assert(dst_patched_size == 1 || dst_patched_size == 2 ||
3004678124bSIgor Mammedov            dst_patched_size == 4 || dst_patched_size == 8);
3014678124bSIgor Mammedov 
3024678124bSIgor Mammedov     le_src_offset = cpu_to_le64(src_offset);
3034678124bSIgor Mammedov     memcpy(dst_file->blob->data + dst_patched_offset,
3044678124bSIgor Mammedov            &le_src_offset, dst_patched_size);
30509852232SMichael S. Tsirkin 
3060e9b9edaSIgor Mammedov     g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
30709852232SMichael S. Tsirkin }
308489886d1SBen Warren 
309489886d1SBen Warren /*
310489886d1SBen Warren  * bios_linker_loader_write_pointer: ask guest to write a pointer to the
311489886d1SBen Warren  * source file into the destination file, and write it back to QEMU via
312489886d1SBen Warren  * fw_cfg DMA.
313489886d1SBen Warren  *
314489886d1SBen Warren  * @linker: linker object instance
315489886d1SBen Warren  * @dest_file: destination file that must be written
316489886d1SBen Warren  * @dst_patched_offset: location within destination file blob to be patched
317489886d1SBen Warren  *                      with the pointer to @src_file, in bytes
318489886d1SBen Warren  * @dst_patched_offset_size: size of the pointer to be patched
319489886d1SBen Warren  *                      at @dst_patched_offset in @dest_file blob, in bytes
320489886d1SBen Warren  * @src_file: source file who's address must be taken
321489886d1SBen Warren  * @src_offset: location within source file blob to which
322489886d1SBen Warren  *              @dest_file+@dst_patched_offset will point to after
323489886d1SBen Warren  *              firmware's executed WRITE_POINTER command
324489886d1SBen Warren  */
bios_linker_loader_write_pointer(BIOSLinker * linker,const char * dest_file,uint32_t dst_patched_offset,uint8_t dst_patched_size,const char * src_file,uint32_t src_offset)325489886d1SBen Warren void bios_linker_loader_write_pointer(BIOSLinker *linker,
326489886d1SBen Warren                                     const char *dest_file,
327489886d1SBen Warren                                     uint32_t dst_patched_offset,
328489886d1SBen Warren                                     uint8_t dst_patched_size,
329489886d1SBen Warren                                     const char *src_file,
330489886d1SBen Warren                                     uint32_t src_offset)
331489886d1SBen Warren {
332489886d1SBen Warren     BiosLinkerLoaderEntry entry;
333489886d1SBen Warren     const BiosLinkerFileEntry *source_file =
334489886d1SBen Warren         bios_linker_find_file(linker, src_file);
335489886d1SBen Warren 
336489886d1SBen Warren     assert(source_file);
337489886d1SBen Warren     assert(src_offset < source_file->blob->len);
338489886d1SBen Warren     memset(&entry, 0, sizeof entry);
339489886d1SBen Warren     strncpy(entry.wr_pointer.dest_file, dest_file,
340489886d1SBen Warren             sizeof entry.wr_pointer.dest_file - 1);
341489886d1SBen Warren     strncpy(entry.wr_pointer.src_file, src_file,
342489886d1SBen Warren             sizeof entry.wr_pointer.src_file - 1);
343489886d1SBen Warren     entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER);
344489886d1SBen Warren     entry.wr_pointer.dst_offset = cpu_to_le32(dst_patched_offset);
345489886d1SBen Warren     entry.wr_pointer.src_offset = cpu_to_le32(src_offset);
346489886d1SBen Warren     entry.wr_pointer.size = dst_patched_size;
347489886d1SBen Warren     assert(dst_patched_size == 1 || dst_patched_size == 2 ||
348489886d1SBen Warren            dst_patched_size == 4 || dst_patched_size == 8);
349489886d1SBen Warren 
350489886d1SBen Warren     g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
351489886d1SBen Warren }
352