4 * @brief Handy DriverGen functions are located here.
6 * @author Copyright (C) 2004 - 2010 CERN. Georgievskiy Yury <ygeorgie@cern.ch>
8 * @date Created on 27/02/2004
10 * @section license_sec License
11 * Released under the GPL
14 #include <sys/mman.h> /* for mmap cruft */
15 #include "driverGen.h"
19 * @brief Constructs a string representation of an integer.
21 * @param val -- value to convert
22 * @param base -- base of the value [2 - 16]
24 * Different based are possible (at least was tested for 2, 10, 16).
26 * @return pointer to the string with converted value - if succeed.
27 * @return NULL - if fails.
29 char *itoa(int val
, int base
)
31 static char buf
[34] = { 0 };
33 int sign
= (val
< 0) ? sign
= -val
: val
;
35 /* check if the base is valid */
36 if (base
< 2 || base
> 16)
39 /* base 16 and base 2 cases */
40 if (base
== 16 || base
== 2) {
41 unsigned int hval
= val
;
42 unsigned int hbase
= base
;
44 *out
= "0123456789abcdef"[hval
% hbase
];
49 if (base
== 16) /* apply 0x prefix */
50 *out
-- = 'x', *out
= '0';
57 /* for all remaining bases */
59 *out
= "0123456789abcdef"[sign
% base
];
64 if (val
< 0 && base
== 10) /* apply negative sign only for base 10 */
73 * @brief Convert a string to lower case.
75 * @param string -- string to convert.
79 void StrToLower(char *string
)
83 while (string
[++i
] != '\0')
84 string
[i
] = (char)tolower(string
[i
]);
88 * @brief Convert a string to upper case.
90 * @param string -- string to convert
94 void StrToUpper(char *string
)
98 while (string
[++i
] != '\0')
99 string
[i
] = (char)toupper(string
[i
]);
103 * @brief Service function for debug purposes.
105 * @param reginfo -- register description
106 * @param regNum -- register amount
110 void PrintoutRegInfo(RegisterDef_t
* reginfo
, int regNum
)
114 for (cntr
= 0; cntr
< regNum
; cntr
++) {
115 printf("----- [%03d] %s -----\n\tblock %d\n\toffset %#x\n"
116 "\tdepth %d (%#x)\n--------------------\n",
117 cntr
, reginfo
[cntr
].name
, reginfo
[cntr
].blockP
->blockID
,
118 reginfo
[cntr
].offset
, reginfo
[cntr
].depth
,
119 reginfo
[cntr
].depth
);
125 * @brief How many registers does block has
127 * @param reg -- first register in the block
129 * @return register amount
131 static int calc_block_reg_amount(RegisterDef_t
*reg
)
134 int bid
= reg
->blockP
->blockID
;
136 while (bid
== reg
->blockP
->blockID
) {
148 * @brief Get block size in bytes.
150 * @param reg -- first register in the block
151 * @param type -- driver (DRIVER_FT) or simulator (SIM_FT)
153 * Calculate block size, depending on the type (driver/simulator).
154 * If driver -- gaps are taken into account.
155 * If simulator -- there will be no gaps.
157 * @return block size in bytes
159 int calc_block_size(RegisterDef_t
*reg
, int type
)
163 int ram
= calc_block_reg_amount(reg
);
165 /* for simulator -- count size without gaps */
166 if (type
== SIM_FT
) {
167 for (i
= 0; i
< ram
; i
++) {
168 bsz
+= ((reg
[i
].depth
) ? reg
[i
].depth
: 1) *
171 } else { /* count gaps only for real driver */
172 reg
= ®
[ram
-1]; /* last block register */
173 bsz
= reg
->offset
+ ((reg
->depth
) ? reg
->depth
: 1)
182 * @brief Find out how many gaps does block has.
184 * @param reg -- first register in the block
188 int calc_block_gap_amount(RegisterDef_t
*reg
)
193 int ram
= calc_block_reg_amount(reg
);
198 for (i
= 1, preg
= ®
[i
-1], reg
= ®
[1]; i
< ram
;
199 i
++, reg
++, preg
++) {
200 addr
= preg
->offset
+ ((preg
->depth
) ? preg
->depth
: 1)
202 if (reg
->offset
- addr
)
210 * @brief Set block size and block register amount information.
212 * @param regs -- register descr
214 * This function is called after we get and check all info from the DB
215 * in order to set missing information blocks, namely:
216 * 1. block size for the real driver (gap sizes are taken into account)
217 * 2. block size for driver simulator (gaps are not considered)
218 * 3. number of registers in the block.
220 void set_extra_block_data(RegisterDef_t
*regs
)
226 ram
= calc_block_reg_amount(regs
);
227 ptr
= ®s
[ram
-1]; /* 'last register' detection */
228 regs
->blockP
->blksz_drvr
= calc_block_size(regs
, DRIVER_FT
);
229 regs
->blockP
->blksz_sim
= calc_block_size(regs
, SIM_FT
);
230 regs
->blockP
->reg_am
= ram
;
231 regs
+= ram
; /* move to the first register of next block */
232 } while (!ptr
->last
);
235 /*! @name BE <-> LE convertion
241 typeof(x) __val = (x); \
242 __endian(&(__val), &(__x), sizeof(__x)); \
248 * @brief Converts Device Info Table from BE to LE
250 * @param src -- source. Device info table to convert
251 * @param dst -- destanation. If not NULL - converted table goes here.
252 * If NULL - @ref src will be used as destanation.
254 * Info file stores all data in the BE format. It should be converted it LE
255 * in order to be able to use it.
258 * If dsc is NULL - current info table (in @ref src parameter) will be
261 * @return pointer to LE-converted info table
263 DevInfo_t
* convert_dit(DevInfo_t
*src
, DevInfo_t
*dsc
)
266 DevInfo_t
*res
= (dsc
)?dsc
:src
; /* where results will go */
269 res
->addr1
.baseAddr
= _ENDIAN(src
->addr1
.baseAddr
);
270 res
->addr1
.range
= _ENDIAN(src
->addr1
.range
);
271 res
->addr1
.increment
= _ENDIAN(src
->addr1
.increment
);
272 res
->addr1
.dpSize
= _ENDIAN(src
->addr1
.dpSize
);
273 res
->addr1
.addrModif
= _ENDIAN(src
->addr1
.addrModif
);
276 res
->addr2
.baseAddr
= _ENDIAN(src
->addr2
.baseAddr
);
277 res
->addr2
.range
= _ENDIAN(src
->addr2
.range
);
278 res
->addr2
.increment
= _ENDIAN(src
->addr2
.increment
);
279 res
->addr2
.dpSize
= _ENDIAN(src
->addr2
.dpSize
);
280 res
->addr2
.addrModif
= _ENDIAN(src
->addr2
.addrModif
);
282 res
->mtn
= _ENDIAN(src
->mtn
);
283 res
->mlun
= _ENDIAN(src
->mlun
);
284 res
->debugFlag
= _ENDIAN(src
->debugFlag
);
285 /* 'opaque' is char */
286 res
->iLevel
= _ENDIAN(src
->iLevel
);
287 res
->iVector
= _ENDIAN(src
->iVector
);
288 res
->iVectorInc
= _ENDIAN(src
->iVectorInc
);
289 res
->chan
= _ENDIAN(src
->chan
);
290 res
->chrindex
= _ENDIAN(src
->chrindex
);
291 res
->gen_date
= _ENDIAN(src
->gen_date
);
292 /* 'dg_vers' is char */
293 res
->regAmount
= _ENDIAN(src
->regAmount
);
295 for (i
= 0; i
< res
->regAmount
; i
++) {
296 res
->regDesc
[i
].regId
= _ENDIAN(src
->regDesc
[i
].regId
);
297 /* 'regName' is char */
298 /* 'busType' is char */
299 res
->regDesc
[i
].regType
= _ENDIAN(src
->regDesc
[i
].regType
);
300 res
->regDesc
[i
].regSize
= _ENDIAN(src
->regDesc
[i
].regSize
);
302 res
->regDesc
[i
].bid
= _ENDIAN(src
->regDesc
[i
].bid
);
303 res
->regDesc
[i
].regOffset
= _ENDIAN(src
->regDesc
[i
].regOffset
);
304 res
->regDesc
[i
].regDepth
= _ENDIAN(src
->regDesc
[i
].regDepth
);
305 res
->regDesc
[i
].regtl
= _ENDIAN(src
->regDesc
[i
].regtl
);
306 res
->regDesc
[i
].regar
= _ENDIAN(src
->regDesc
[i
].regar
);
307 res
->regDesc
[i
].rwIoctlOpNum
= _ENDIAN(src
->regDesc
[i
].rwIoctlOpNum
);
310 res
->maxRegSz
= _ENDIAN(src
->maxRegSz
);
311 res
->blkAmount
= _ENDIAN(src
->blkAmount
);
313 for (i
= 0; i
< res
->blkAmount
; i
++) {
314 res
->blkDesc
[i
].block
= _ENDIAN(src
->blkDesc
[i
].block
);
315 res
->blkDesc
[i
].blkBaseAddr
= _ENDIAN(src
->blkDesc
[i
].blkBaseAddr
);
316 res
->blkDesc
[i
].offset
= _ENDIAN(src
->blkDesc
[i
].offset
);
317 res
->blkDesc
[i
].blksz_drvr
= _ENDIAN(src
->blkDesc
[i
].blksz_drvr
);
318 res
->blkDesc
[i
].blksz_sim
= _ENDIAN(src
->blkDesc
[i
].blksz_sim
);
319 res
->blkDesc
[i
].reg_am
= _ENDIAN(src
->blkDesc
[i
].reg_am
);
322 /* 'checksum' is char */
328 * @brief Open info file with DataBase module description.
330 * Returned pointer should be freed by the caller afterwards!
332 * @param fNm -- info file name to open
333 * Note, that info file is a Big Endian encoded.
335 * @return pointer -- if everything is OK.
336 * NOTE. Should be freed by the caller afterwards.
337 * @return NULL -- failed
339 DevInfo_t
* read_info_file(char *fNm
)
343 DevInfo_t
*devD
, *dit
; /* device data from the info file */
345 if ((fd
= open(fNm
, O_RDONLY
)) < 0) {
353 devD
= mmap(0, fSz
, PROT_READ
, MAP_SHARED
, fd
, 0);
354 if (devD
== MAP_FAILED
) {
360 close(fd
); /* we don't need it anymore */
362 dit
= calloc(1, sizeof(*dit
));
363 /* copy it locally */
364 memmove(dit
, devD
, sizeof(*devD
));
368 convert_dit(dit
, NULL
); /* convert to BE */
374 * @brief Exploit driver .info file
376 * @param info table to printout.
378 * Useful for debug purposes. User can check if info file contains
384 void exploit_info_file(DevInfo_t
* info
)
387 AddrInfo_t
*aiptr
= &(info
->addr1
);
388 REGDESC
*rdp
= info
->regDesc
;
389 BLKDESC
*bdp
= info
->blkDesc
;
391 printf("\n%s.info file data:\n\n", TranslationGetSysLower());
393 printf("+---- general info -----------\n");
394 printf("| 'mtn' => %d\n", info
->mtn
);
395 printf("| 'mlun' => 0x%x\n", info
->mlun
);
396 printf("| 'debugFlag' => 0x%X\n", info
->debugFlag
);
397 printf("| 'opaque' => '%s'\n", info
->opaque
);
398 printf("| 'iLevel' => %d\n", info
->iLevel
);
399 printf("| 'iVector' => %d\n", info
->iVector
);
400 printf("| 'iVectorInc' => %d\n", info
->iVectorInc
);
401 printf("| 'chan' => %d\n", info
->chan
);
402 printf("| 'chrindex' => %d\n", info
->chrindex
);
403 printf("| 'gen_date' => %ld\n", info
->gen_date
);
404 printf("| 'dg_vers' => '%s'\n", info
->dg_vers
);
405 printf("| 'regAmount' => %d\n", info
->regAmount
);
406 printf("| 'maxRegSz' => %d\n", info
->maxRegSz
);
407 printf("| 'blkAmount' => %d\n", info
->blkAmount
);
408 printf("| 'checksum' => %d\n", info
->checksum
);
409 printf("+-----------------------------\n\n");
411 /* 2 address space info */
412 for (cntr
= 0; cntr
< 2; cntr
++) {
413 printf("+-----------------------------\n");
414 printf("| Addr[%d].baseAddr => 0x%lx\n", cntr
,
416 printf("| Addr[%d].range => 0x%x\n", cntr
, aiptr
->range
);
417 printf("| Addr[%d].increment => 0x%x\n", cntr
,
419 printf("| Addr[%d].dpSize => %d\n", cntr
, aiptr
->dpSize
);
420 printf("| Addr[%d].addrModif => 0x%x\n", cntr
,
422 printf("+-----------------------------\n\n");
427 for (cntr
= 0; cntr
< info
->blkAmount
; cntr
++) {
428 printf("+---------------------------------------------\n");
429 printf("| Blk[%d].block => %d\n", cntr
, bdp
[cntr
].block
);
430 printf("| Blk[%d].blkBaseAddr => %d\n", cntr
,
431 bdp
[cntr
].blkBaseAddr
);
432 printf("| Blk[%d].offset => 0x%lX\n", cntr
,
434 printf("| Blk[%d].blksz_drvr => %d bytes\n", cntr
,
435 bdp
[cntr
].blksz_drvr
);
436 printf("| Blk[%d].blksz_sim => %d bytes\n", cntr
,
437 bdp
[cntr
].blksz_sim
);
438 printf("| Blk[%d].reg_am => %d\n", cntr
,
441 printf("+---------------------------------------------\n\n");
444 /* all registers info */
445 for (cntr
= 0; cntr
< info
->regAmount
; cntr
++) {
446 printf("+---------------------------------------------\n");
447 printf("| Reg[%d].regId => %d\n", cntr
, rdp
[cntr
].regId
);
448 printf("| Reg[%d].regName => %s\n", cntr
,
450 printf("| Reg[%d].busType => %s\n", cntr
,
452 printf("| Reg[%d].regType => %s (%d)\n", cntr
,
453 (rdp
[cntr
].regType
==
454 RT_REAL
) ? "RT_REAL" : (rdp
[cntr
].regType
==
455 RT_EXTR
) ? "RT_EXTR" :
456 "RT_SRVS", rdp
[cntr
].regType
);
457 printf("| Reg[%d].regSize => %d\n", cntr
,
459 printf("| Reg[%d].b_a => %s\n", cntr
, rdp
[cntr
].b_a
);
460 printf("| Reg[%d].bid => %d\n", cntr
, rdp
[cntr
].bid
);
461 printf("| Reg[%d].regOffset => 0x%X\n", cntr
,
462 rdp
[cntr
].regOffset
);
463 printf("| Reg[%d].regDepth => %d\n", cntr
,
465 printf("| Reg[%d].regtl => %d\n", cntr
, rdp
[cntr
].regtl
);
466 printf("| Reg[%d].regar => %d\n", cntr
, rdp
[cntr
].regar
);
467 printf("| Reg[%d].rwIoctlOpNum => 0x%x\n", cntr
,
468 rdp
[cntr
].rwIoctlOpNum
);
469 printf("+---------------------------------------------\n\n");
474 char* get_info_fn(void)
476 static char ifn
[MAX_STR
] = { 0 };
478 if (ifn
[0]) /* already initialized */
481 snprintf(ifn
, sizeof(ifn
), "%s/object_%s/%s.info", get_msd(NULL
),
482 TranslationGetSysLower(), TranslationGetSysLower());
487 char* get_xml_fn(void)
489 static char xfn
[MAX_STR
] = { 0 };
491 if (xfn
[0]) /* already initialized */
494 snprintf(xfn
, sizeof(xfn
), "%s/object_%s/%s.xml", get_msd(NULL
),
495 TranslationGetSysLower(), TranslationGetModName());