xref: /aosp_15_r20/external/intel-media-driver/media_softlet/agnostic/common/vp/cm_fc_ld/PatchInfoReader.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
1 /*
2 * Copyright (c) 2019, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 // PatchInfo reader.
23 //
24 
25 #include <cassert>
26 #include <cstddef>
27 #include <map>
28 
29 #include "PatchInfo.h"
30 #include "PatchInfoRecord.h"
31 #include "PatchInfoReader.h"
32 
33 namespace {
34 
35 class PatchInfoReader {
36   const char *Data;
37   std::size_t Size;
38   unsigned ShEntries;
39 
40   const cm::patch::PInfoSectionHdr *Sh;
41 
42   // All symbol tables are merged into a single one.
43   std::map<unsigned, cm::patch::Symbol *> SymbolTable;
44 
45   typedef std::map<unsigned, cm::patch::Binary *> BinarySectionMapTy;
46   typedef std::map<unsigned, bool> SymbolTableSectionMapTy;
47   BinarySectionMapTy BinarySectionMap;
48   SymbolTableSectionMapTy SymbolTableSectionMap;
49 
50 public:
PatchInfoReader(const char * B,std::size_t S)51   PatchInfoReader(const char *B, std::size_t S) : Data(B), Size(S), ShEntries(0){Sh = nullptr;}
52 
53   bool read(cm::patch::Collection &C);
54 
55 protected:
56   bool readHeader(cm::patch::Collection &C);
57   bool readSections(cm::patch::Collection &C);
58 
59   bool readDummySection(cm::patch::Collection &C, unsigned n);
60   bool readUnknownSection(cm::patch::Collection &C, unsigned n);
61   bool readBinarySection(cm::patch::Collection &C, unsigned n);
62   bool readRelocationSection(cm::patch::Collection &C, unsigned n);
63   bool readSymbolTableSection(cm::patch::Collection &C, unsigned n);
64   bool readStringTableSection(cm::patch::Collection &C, unsigned n);
65   bool readInitRegAccessTableSection(cm::patch::Collection &C, unsigned n);
66   bool readFiniRegAccessTableSection(cm::patch::Collection &C, unsigned n);
67   bool readTokenTableSection(cm::patch::Collection &C, unsigned n);
68 
69   bool readRegisterAccessTableSection(cm::patch::Collection &C, unsigned n,
70                                       cm::patch::PInfo_U16 ShType);
71 
isValidSection(unsigned n)72   bool isValidSection(unsigned n) {
73     if (n >= ShEntries)
74       return false;
75     if (!Sh ||
76         Sh[n].ShOffset >= Size ||
77         Sh[n].ShOffset + Sh[n].ShSize > Size)
78       return false;
79     return true;
80   }
isValidSectionOfType(unsigned n,cm::patch::PInfo_U16 ShType)81   bool isValidSectionOfType(unsigned n, cm::patch::PInfo_U16 ShType) {
82     if (!isValidSection(n))
83       return false;
84     return Sh[n].ShType == ShType;
85   }
86 
getString(unsigned ShIdx,unsigned Idx)87   const char *getString(unsigned ShIdx, unsigned Idx) {
88     const char *StringTable = Data + Sh[ShIdx].ShOffset;
89     return StringTable + Idx;
90   }
91 
92   std::pair<BinarySectionMapTy::iterator, bool>
93       getOrReadBinarySection(cm::patch::Collection &C, unsigned n);
94 
95   std::pair<SymbolTableSectionMapTy::iterator, bool>
96       getOrReadSymbolTableSection(cm::patch::Collection &C, unsigned n);
97 };
98 
99 } // End anonymous namespace
100 
readPatchInfo(const char * Buf,std::size_t Sz,cm::patch::Collection & C)101 bool readPatchInfo(const char *Buf, std::size_t Sz, cm::patch::Collection &C) {
102   PatchInfoReader R(Buf, Sz);
103   return R.read(C);
104 }
105 
read(cm::patch::Collection & C)106 bool PatchInfoReader::read(cm::patch::Collection &C) {
107   return readHeader(C) || readSections(C);
108 }
109 
readHeader(cm::patch::Collection & C)110 bool PatchInfoReader::readHeader(cm::patch::Collection &C) {
111   if (Size < sizeof(cm::patch::PInfoHdr))
112     return true;
113 
114   const cm::patch::PInfoHdr *H =
115     reinterpret_cast<const cm::patch::PInfoHdr *>(Data);
116   if (!H->checkMagic())
117     return true;
118   if (H->Version != cm::patch::PV_0)
119     return true;
120   if (!H->isValidPlatform())
121     return true;
122   if (H->ShOffset >= Size)
123     return true;
124   if (H->ShOffset + H->ShNum * sizeof(cm::patch::PInfoSectionHdr) > Size)
125     return true;
126 
127   if (C.getPlatform() != cm::patch::PP_NONE && C.getPlatform() != H->Platform)
128     return true;
129 
130   C.setPlatform(H->Platform);
131 
132   Sh = reinterpret_cast<const cm::patch::PInfoSectionHdr *>(Data + H->ShOffset);
133   ShEntries = H->ShNum;
134 
135   return false;
136 }
137 
138 std::pair<PatchInfoReader::BinarySectionMapTy::iterator, bool>
getOrReadBinarySection(cm::patch::Collection & C,unsigned n)139 PatchInfoReader::getOrReadBinarySection(cm::patch::Collection &C, unsigned n) {
140   auto BI = BinarySectionMap.end();
141   if (!readBinarySection(C, n)) {
142     BI = BinarySectionMap.find(n);
143     assert(BI != BinarySectionMap.end());
144   }
145   return std::make_pair(BI, BI == BinarySectionMap.end());
146 }
147 
148 std::pair<PatchInfoReader::SymbolTableSectionMapTy::iterator, bool>
getOrReadSymbolTableSection(cm::patch::Collection & C,unsigned n)149 PatchInfoReader::getOrReadSymbolTableSection(cm::patch::Collection &C,
150                                              unsigned n) {
151   auto SI = SymbolTableSectionMap.end();
152   if (!readSymbolTableSection(C, n)) {
153     SI = SymbolTableSectionMap.find(n);
154     assert(SI != SymbolTableSectionMap.end());
155   }
156   return std::make_pair(SI, SI == SymbolTableSectionMap.end());
157 }
158 
readSections(cm::patch::Collection & C)159 bool PatchInfoReader::readSections(cm::patch::Collection &C) {
160   if (!Sh)
161     return true;
162 
163   for (unsigned n = 0; n != ShEntries; ++n) {
164 
165     switch (Sh[n].ShType) {
166     case cm::patch::PSHT_NONE:
167       if (readDummySection(C, n)) return true;
168       break;
169     case cm::patch::PSHT_BINARY:
170       if (readBinarySection(C, n)) return true;
171       break;
172     case cm::patch::PSHT_REL:
173       if (readRelocationSection(C, n)) return true;
174       break;
175     case cm::patch::PSHT_SYMTAB:
176       if (readSymbolTableSection(C, n)) return true;
177       break;
178     case cm::patch::PSHT_STRTAB:
179       if (readStringTableSection(C, n)) return true;
180       break;
181     case cm::patch::PSHT_INITREGTAB:
182       if (readInitRegAccessTableSection(C, n)) return true;
183       break;
184     case cm::patch::PSHT_FINIREGTAB:
185       if (readFiniRegAccessTableSection(C, n)) return true;
186       break;
187     case cm::patch::PSHT_TOKTAB:
188       if (readTokenTableSection(C, n)) return true;
189       break;
190     default:
191       if (readUnknownSection(C, n)) return true;
192       break;
193     }
194   }
195 
196   return false;
197 }
198 
readDummySection(cm::patch::Collection & C,unsigned n)199 bool PatchInfoReader::readDummySection(cm::patch::Collection &C, unsigned n) {
200   if (!isValidSectionOfType(n, cm::patch::PSHT_NONE)) return true;
201   return false;
202 }
203 
readBinarySection(cm::patch::Collection & C,unsigned n)204 bool PatchInfoReader::readBinarySection(cm::patch::Collection &C, unsigned n) {
205   // Skip if this binary section is ready read.
206   if (BinarySectionMap.count(n))
207     return false;
208 
209   // Bail out if it's not an valid binary section.
210   if (!isValidSectionOfType(n, cm::patch::PSHT_BINARY))
211     return true;
212 
213   const char *Buf = nullptr;
214   std::size_t Sz = Sh[n].ShSize;
215   if (Sz)
216     Buf = Data + Sh[n].ShOffset;
217   cm::patch::Binary *Bin = C.addBinary(Buf, Sz);
218   BinarySectionMap.insert(std::make_pair(n, Bin));
219 
220   return false;
221 }
222 
readRelocationSection(cm::patch::Collection & C,unsigned n)223 bool PatchInfoReader::readRelocationSection(cm::patch::Collection &C,
224                                             unsigned n) {
225   // Skip if this relocation section is already read.
226   if (!isValidSectionOfType(n, cm::patch::PSHT_REL))
227     return true;
228 
229   bool Ret;
230 
231   BinarySectionMapTy::iterator BI;
232   std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
233   if (Ret)
234     return true;
235   cm::patch::Binary *Bin = BI->second;
236 
237   SymbolTableSectionMapTy::iterator SI;
238   std::tie(SI, Ret) = getOrReadSymbolTableSection(C, Sh[n].ShLink);
239   if (Ret)
240     return true;
241 
242   // Scan through relocations.
243   std::size_t Sz = Sh[n].ShSize;
244   const cm::patch::PInfoRelocation *Rel =
245     reinterpret_cast<const cm::patch::PInfoRelocation *>(Data + Sh[n].ShOffset);
246   for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRelocation)) {
247     auto I = SymbolTable.find(Rel[i].RelSym);
248     if (I == SymbolTable.end())
249       return true;
250     cm::patch::Symbol *S = I->second;
251     Bin->addReloc(Rel[i].RelAddr, S);
252   }
253 
254   return false;
255 }
256 
readSymbolTableSection(cm::patch::Collection & C,unsigned n)257 bool PatchInfoReader::readSymbolTableSection(cm::patch::Collection &C,
258                                             unsigned n) {
259   // Skip if this section is ready read.
260   if (SymbolTableSectionMap.count(n))
261     return false;
262 
263   // Bail out if it's an invalid section.
264   if (!isValidSectionOfType(n, cm::patch::PSHT_SYMTAB))
265     return true;
266 
267   // Read string table.
268   unsigned ShIdx = Sh[n].ShLink;
269   if (readStringTableSection(C, ShIdx))
270     return true;
271 
272   // Scan through the symbol table.
273   const cm::patch::PInfoSymbol *Sym =
274     reinterpret_cast<const cm::patch::PInfoSymbol *>(Data + Sh[n].ShOffset);
275   std::size_t Sz = Sh[n].ShSize;
276   for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoSymbol)) {
277     // Skip unamed symbol.
278     unsigned StrIdx = Sym[i].SymName;
279     if (!StrIdx)
280       continue;
281     const char *Name = getString(ShIdx, StrIdx);
282     cm::patch::Binary *Bin = nullptr;
283     unsigned Ndx = Sym[i].SymShndx;
284     if (Ndx) {
285       // Only support binary section so far.
286       bool Ret;
287       BinarySectionMapTy::iterator BI;
288       std::tie(BI, Ret) = getOrReadBinarySection(C, Ndx);
289       if (Ret)
290         return true;
291       Bin = BI->second;
292     }
293     cm::patch::Symbol *S = C.getSymbol(Name);
294     if (Bin)
295       while (S && !S->isUnresolved()) {
296         // In case a symbol has multiple definitions (due to combining a single
297         // kernel multiple times), rename the conflicting one.
298         Name = C.getUniqueName(Name);
299         S = C.getSymbol(Name);
300       }
301     S = C.addSymbol(Name);
302     if (Bin && S->isUnresolved()) {
303       S->setBinary(Bin);
304       S->setAddr(Sym[i].SymValue);
305       S->setExtra(Sym[i].SymExtra);
306     }
307     // Assume there's just one symbol table section per patch info.
308     SymbolTable.insert(std::make_pair(i, S));
309   }
310   SymbolTableSectionMap.insert(std::make_pair(n, true));
311 
312   return false;
313 }
314 
readStringTableSection(cm::patch::Collection & C,unsigned n)315 bool PatchInfoReader::readStringTableSection(cm::patch::Collection &C,
316                                              unsigned n) {
317   if (!isValidSectionOfType(n, cm::patch::PSHT_STRTAB))
318     return true;
319   return false;
320 }
321 
322 
323 bool
readRegisterAccessTableSection(cm::patch::Collection & C,unsigned n,cm::patch::PInfo_U16 ShType)324 PatchInfoReader::readRegisterAccessTableSection(cm::patch::Collection &C,
325                                                 unsigned n,
326                                                 cm::patch::PInfo_U16 ShType) {
327   if (!isValidSectionOfType(n, ShType))
328     return true;
329 
330   BinarySectionMapTy::iterator BI;
331   bool Ret;
332   std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
333   if (Ret)
334     return true;
335   cm::patch::Binary *Bin = BI->second;
336 
337   // Scan through register accesses.
338   std::size_t Sz = Sh[n].ShSize;
339   const cm::patch::PInfoRegAccess *Acc =
340     reinterpret_cast<const cm::patch::PInfoRegAccess *>(Data + Sh[n].ShOffset);
341   switch (ShType) {
342   default:
343     return true;
344   case cm::patch::PSHT_INITREGTAB:
345     for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRegAccess))
346       Bin->addInitRegAccess(Acc[i].RegAccAddr, Acc[i].RegAccRegNo,
347                             Acc[i].RegAccDUT);
348     break;
349   case cm::patch::PSHT_FINIREGTAB:
350     for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRegAccess))
351       Bin->addFiniRegAccess(Acc[i].RegAccAddr, Acc[i].RegAccRegNo,
352                             Acc[i].RegAccDUT);
353     break;
354   }
355 
356   return false;
357 }
358 
readInitRegAccessTableSection(cm::patch::Collection & C,unsigned n)359 bool PatchInfoReader::readInitRegAccessTableSection(cm::patch::Collection &C,
360                                                     unsigned n) {
361 
362   return readRegisterAccessTableSection(C, n, cm::patch::PSHT_INITREGTAB);
363 }
364 
readFiniRegAccessTableSection(cm::patch::Collection & C,unsigned n)365 bool PatchInfoReader::readFiniRegAccessTableSection(cm::patch::Collection &C,
366                                                     unsigned n) {
367   return readRegisterAccessTableSection(C, n, cm::patch::PSHT_FINIREGTAB);
368 }
369 
readTokenTableSection(cm::patch::Collection & C,unsigned n)370 bool PatchInfoReader::readTokenTableSection(cm::patch::Collection &C,
371                                             unsigned n) {
372   if (!isValidSectionOfType(n, cm::patch::PSHT_TOKTAB))
373     return true;
374 
375   BinarySectionMapTy::iterator BI;
376   bool Ret;
377   std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
378   if (Ret)
379     return true;
380   cm::patch::Binary *Bin = BI->second;
381 
382   // Scan through tokens.
383   std::size_t Sz = Sh[n].ShSize;
384   const cm::patch::PInfoToken *Tok =
385     reinterpret_cast<const cm::patch::PInfoToken *>(Data + Sh[n].ShOffset);
386   for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoToken))
387     Bin->addToken(Tok[i].TokenNo);
388 
389   return false;
390 }
391 
392 
readUnknownSection(cm::patch::Collection & C,unsigned n)393 bool PatchInfoReader::readUnknownSection(cm::patch::Collection &C, unsigned n) {
394   if (!isValidSection(n))
395     return true;
396   return false;
397 }
398