1/*
2Copyright (c) 2013, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/**
29*
30* @file debug_sym.c
31*
32* @brief The usermode process which implements displays the messages.
33*
34****************************************************************************/
35
36// ---- Include Files -------------------------------------------------------
37
38#include "interface/vcos/vcos.h"
39
40#include <errno.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <fcntl.h>
44#include <string.h>
45#if defined(WIN32)
46# include <io.h>
47#elif defined(__CYGWIN__)
48# include <sys/mman.h>
49#else
50# include <sys/mman.h>
51# include <sys/ioctl.h>
52# include <vc_mem.h>
53#endif
54
55#include "debug_sym.h"
56#include "vc_debug_sym.h"
57
58
59// ---- Public Variables ----------------------------------------------------
60// ---- Private Constants and Types -----------------------------------------
61
62#define MAX_VC_SIZE 8 /* a sanity upper bound on memory size */
63
64#ifndef PAGE_SIZE
65# if defined(__CYGWIN__)
66# define PAGE_SIZE 65536 /* Cygwin mmap requires rounding to SYSTEM_INFO.dwAllocationGranularity */
67# else
68# define PAGE_SIZE 4096
69# endif
70#endif
71#ifndef PAGE_MASK
72# define PAGE_MASK (~(PAGE_SIZE - 1))
73#endif
74
75// Offset within the videocore memory map to get the address of the symbol
76// table.
77#define VC_SYMBOL_BASE_OFFSET VC_DEBUG_HEADER_OFFSET
78
79struct opaque_vc_mem_access_handle_t
80{
81 int memFd;
82 int memFdBase; /* The VideoCore address mapped to offset 0 of memFd */
83 VC_MEM_ADDR_T vcMemBase; /* The VideoCore address of the start of the loaded image */
84 VC_MEM_ADDR_T vcMemLoad; /* The VideoCore address of the start of the code image */
85 VC_MEM_ADDR_T vcMemEnd; /* The VideoCore address of the end of the loaded image */
86 VC_MEM_SIZE_T vcMemSize; /* The amount of memory used by the loaded image */
87 VC_MEM_ADDR_T vcMemPhys; /* The VideoCore memory physical address */
88
89 VC_MEM_ADDR_T vcSymbolTableOffset;
90 unsigned numSymbols;
91 VC_DEBUG_SYMBOL_T *symbol;
92 int use_vc_mem; /* using mmap-ed memory rather than real file */
93};
94
95#if 1
96 #define DBG( fmt, ... ) vcos_log_trace( "%s: " fmt, __FUNCTION__, ##__VA_ARGS__ )
97 #define ERR( fmt, ... ) vcos_log_error( "%s: " fmt, __FUNCTION__, ##__VA_ARGS__ )
98#else
99 #define DBG( fmt, ... ) fprintf( stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ )
100 #define ERR( fmt, ... ) fprintf( stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ )
101#endif
102
103typedef enum
104{
105 READ_MEM,
106 WRITE_MEM,
107} MEM_OP_T;
108
109#if defined( WIN32 )
110#define open _open
111#define close _close
112#define O_SYNC 0
113#endif
114
115// ---- Private Variables ---------------------------------------------------
116
117#define VCOS_LOG_CATEGORY (&debug_sym_log_category)
118static VCOS_LOG_CAT_T debug_sym_log_category;
119
120// ---- Private Function Prototypes -----------------------------------------
121
122// ---- Functions -----------------------------------------------------------
123
124/****************************************************************************
125*
126* Get access to the videocore memory space. Returns zero if the memory was
127* opened successfully.
128*
129***************************************************************************/
130
131int OpenVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T *vcHandlePtr )
132{
133 return OpenVideoCoreMemoryFile( NULL, vcHandlePtr );
134}
135
136/****************************************************************************
137*
138* Get access to the videocore memory space. Returns zero if the memory was
139* opened successfully.
140*
141***************************************************************************/
142
143struct fb_dmacopy {
144 void *dst;
145 uint32_t src;
146 uint32_t length;
147};
148#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy)
149
150static int vc_mem_copy(void *dst, uint32_t src, uint32_t length)
151{
152 const char *filename = "/dev/fb0";
153 int memFd;
154 struct fb_dmacopy ioparam;
155
156 ioparam.dst = dst;
157 ioparam.src = src;
158 ioparam.length = length;
159
160 if (( memFd = open( filename, O_RDWR | O_SYNC )) < 0 )
161 {
162 ERR( "Unable to open '%s': %s(%d)\n", filename, strerror( errno ), errno );
163 return -errno;
164 }
165
166 if ( ioctl( memFd, FBIODMACOPY, &ioparam ) != 0 )
167 {
168 close( memFd );
169 return -errno;
170 }
171 close( memFd );
172 return 0;
173}
174
175int OpenVideoCoreMemoryFile( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr )
176{
177 return OpenVideoCoreMemoryFileWithOffset( filename, vcHandlePtr, 0 );
178}
179
180int OpenVideoCoreMemoryFileWithOffset( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr, size_t loadOffset )
181{
182 int rc = 0;
183 VC_MEM_ACCESS_HANDLE_T newHandle;
184 VC_DEBUG_SYMBOL_T debug_sym;
185 VC_MEM_ADDR_T symAddr;
186 size_t symTableSize;
187 unsigned symIdx;
188
189 struct
190 {
191 VC_DEBUG_HEADER_T header;
192 VC_DEBUG_PARAMS_T params;
193
194 } vc_dbg;
195
196 vcos_log_register( "debug_sym", &debug_sym_log_category );
197
198 if (( newHandle = calloc( 1, sizeof( *newHandle ))) == NULL )
199 {
200 return -ENOMEM;
201 }
202
203 if ( filename == NULL )
204 {
205 newHandle->use_vc_mem = 1;
206 filename = "/dev/vc-mem";
207 }
208 else
209 {
210 newHandle->use_vc_mem = 0;
211 }
212
213 if (( newHandle->memFd = open( filename, ( newHandle->use_vc_mem ? O_RDWR : O_RDONLY ) | O_SYNC )) < 0 )
214 {
215 ERR( "Unable to open '%s': %s(%d)\n", filename, strerror( errno ), errno );
216 free(newHandle);
217 return -errno;
218 }
219 DBG( "Opened %s memFd = %d", filename, newHandle->memFd );
220
221 if ( newHandle->use_vc_mem )
222 {
223 newHandle->memFdBase = 0;
224
225#if defined(WIN32) || defined(__CYGWIN__)
226#define VC_MEM_SIZE (128 * 1024 * 1024)
227 newHandle->vcMemSize = VC_MEM_SIZE;
228 newHandle->vcMemBase = 0;
229 newHandle->vcMemLoad = 0;
230 newHandle->vcMemPhys = 0;
231#else
232 if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_SIZE, &newHandle->vcMemSize ) != 0 )
233 {
234 ERR( "Failed to get memory size via ioctl: %s(%d)\n",
235 strerror( errno ), errno );
236 free(newHandle);
237 return -errno;
238 }
239 if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_BASE, &newHandle->vcMemBase ) != 0 )
240 {
241 ERR( "Failed to get memory base via ioctl: %s(%d)\n",
242 strerror( errno ), errno );
243 free(newHandle);
244 return -errno;
245 }
246 if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_LOAD, &newHandle->vcMemLoad ) != 0 )
247 {
248 ERR( "Failed to get memory load via ioctl: %s(%d)\n",
249 strerror( errno ), errno );
250 /* Backward compatibility. */
251 newHandle->vcMemLoad = newHandle->vcMemBase;
252 }
253 if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_PHYS_ADDR, &newHandle->vcMemPhys ) != 0 )
254 {
255 ERR( "Failed to get memory physical address via ioctl: %s(%d)\n",
256 strerror( errno ), errno );
257 free(newHandle);
258 return -errno;
259 }
260#endif
261 }
262 else
263 {
264 off_t len = lseek( newHandle->memFd, 0, SEEK_END );
265 if ( len < 0 )
266 {
267 ERR( "Failed to seek to end of file: %s(%d)\n", strerror( errno ), errno );
268 free(newHandle);
269 return -errno;
270 }
271 newHandle->vcMemPhys = 0;
272 newHandle->vcMemSize = len;
273 newHandle->vcMemBase = 0;
274 newHandle->vcMemLoad = loadOffset;
275 newHandle->memFdBase = 0;
276 }
277
278 DBG( "vcMemSize = %08x", newHandle->vcMemSize );
279 DBG( "vcMemBase = %08x", newHandle->vcMemBase );
280 DBG( "vcMemLoad = %08x", newHandle->vcMemLoad );
281 DBG( "vcMemPhys = %08x", newHandle->vcMemPhys );
282
283 newHandle->vcMemEnd = newHandle->vcMemBase + newHandle->vcMemSize - 1;
284
285 // See if we can detect the symbol table
286 if ( !ReadVideoCoreMemory( newHandle,
287 &newHandle->vcSymbolTableOffset,
288 newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET,
289 sizeof( newHandle->vcSymbolTableOffset )))
290 {
291 ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET );
292 rc = -EIO;
293 goto err_exit;
294 }
295
296 // When reading from a file, the VC binary is read into a buffer and the effective base is 0.
297 // But that may not be the actual base address the binary is intended to be loaded to. The
298 // following reads the debug header to find out what the actual base address is.
299 if( !newHandle->use_vc_mem )
300 {
301 // Read the complete debug header
302 if ( !ReadVideoCoreMemory( newHandle,
303 &vc_dbg,
304 newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET,
305 sizeof( vc_dbg )))
306 {
307 ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET );
308 rc = -EIO;
309 goto err_exit;
310 }
311 // The vc_dbg header gives the "base" address of the VC binary,
312 // which debug_sym calls the "load" address, so we need to adjust
313 // it by loadOffset to find the base of the whole memory dump file
314 newHandle->memFdBase = vc_dbg.params.vcMemBase - loadOffset;
315 newHandle->vcMemBase = vc_dbg.params.vcMemBase - loadOffset;
316 newHandle->vcMemLoad = vc_dbg.params.vcMemBase;
317 newHandle->vcMemEnd = newHandle->memFdBase + newHandle->vcMemSize - 1;
318
319 DBG( "Updated from debug header:" );
320 DBG( "vcMemSize = %08x", newHandle->vcMemSize );
321 DBG( "vcMemBase = %08x", newHandle->vcMemBase );
322 DBG( "vcMemLoad = %08x", newHandle->vcMemLoad );
323 DBG( "vcMemPhys = %08x", newHandle->vcMemPhys );
324 }
325
326 DBG( "vcSymbolTableOffset = 0x%08x", newHandle->vcSymbolTableOffset );
327
328 // Make sure that the pointer points into the first few megabytes of
329 // the memory space.
330 if ( (newHandle->vcSymbolTableOffset - newHandle->vcMemLoad) > ( MAX_VC_SIZE * 1024 * 1024 ))
331 {
332 ERR( "newHandle->vcSymbolTableOffset (0x%x - 0x%x) > %dMB\n", newHandle->vcSymbolTableOffset, newHandle->vcMemLoad, MAX_VC_SIZE );
333 rc = -EIO;
334 goto err_exit;
335 }
336
337 // Make a pass to count how many symbols there are.
338
339 symAddr = newHandle->vcSymbolTableOffset;
340 newHandle->numSymbols = 0;
341 do
342 {
343 if ( !ReadVideoCoreMemory( newHandle,
344 &debug_sym,
345 symAddr,
346 sizeof( debug_sym )))
347 {
348 ERR( "ReadVideoCoreMemory @ symAddr(0x%08x) failed\n", symAddr );
349 rc = -EIO;
350 goto err_exit;
351 }
352
353 newHandle->numSymbols++;
354
355 DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu",
356 newHandle->numSymbols,
357 debug_sym.label,
358 debug_sym.addr,
359 debug_sym.size );
360
361 if ( newHandle->numSymbols > 1024 )
362 {
363 // Something isn't sane.
364
365 ERR( "numSymbols (%d) > 1024 - looks wrong\n", newHandle->numSymbols );
366 rc = -EIO;
367 goto err_exit;
368 }
369 symAddr += sizeof( debug_sym );
370
371 } while ( debug_sym.label != 0 );
372 newHandle->numSymbols--;
373
374 DBG( "Detected %d symbols", newHandle->numSymbols );
375
376 // Allocate some memory to hold the symbols, and read them in.
377
378 symTableSize = newHandle->numSymbols * sizeof( debug_sym );
379 if (( newHandle->symbol = malloc( symTableSize )) == NULL )
380 {
381 rc = -ENOMEM;
382 goto err_exit;
383 }
384 if ( !ReadVideoCoreMemory( newHandle,
385 newHandle->symbol,
386 newHandle->vcSymbolTableOffset,
387 symTableSize ))
388 {
389 ERR( "ReadVideoCoreMemory @ newHandle->vcSymbolTableOffset(0x%08x) failed\n", newHandle->vcSymbolTableOffset );
390 rc = -EIO;
391 goto err_exit;
392 }
393
394 // The names of the symbols are pointers in videocore space. We want
395 // to have them available locally, so we make copies and fixup
396 // the pointer.
397
398 for ( symIdx = 0; symIdx < newHandle->numSymbols; symIdx++ )
399 {
400 VC_DEBUG_SYMBOL_T *sym;
401 char symName[ 256 ];
402
403 sym = &newHandle->symbol[ symIdx ];
404
405 DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu",
406 symIdx,
407 sym->label,
408 sym->addr,
409 sym->size );
410
411 if ( !ReadVideoCoreMemory( newHandle,
412 symName,
413 TO_VC_MEM_ADDR(sym->label),
414 sizeof( symName )))
415 {
416 ERR( "ReadVideoCoreMemory @ sym->label(0x%08x) failed\n", TO_VC_MEM_ADDR(sym->label) );
417 rc = -EIO;
418 goto err_exit;
419 }
420 symName[ sizeof( symName ) - 1 ] = '\0';
421 sym->label = vcos_strdup( symName );
422
423 DBG( "Symbol %d (@0x%p): label: '%s' addr: 0x%08x size: %zu",
424 symIdx,
425 sym,
426 sym->label,
427 sym->addr,
428 sym->size );
429 }
430
431 *vcHandlePtr = newHandle;
432 return 0;
433
434err_exit:
435 close( newHandle->memFd );
436 free( newHandle );
437
438 return rc;
439}
440
441/****************************************************************************
442*
443* Returns the number of symbols which were detected.
444*
445***************************************************************************/
446
447unsigned NumVideoCoreSymbols( VC_MEM_ACCESS_HANDLE_T vcHandle )
448{
449 return vcHandle->numSymbols;
450}
451
452/****************************************************************************
453*
454* Returns the name, address and size of the i'th symbol.
455*
456***************************************************************************/
457
458int GetVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, unsigned idx, char *labelBuf, size_t labelBufSize, VC_MEM_ADDR_T *vcMemAddr, size_t *vcMemSize )
459{
460 VC_DEBUG_SYMBOL_T *sym;
461
462 if ( idx >= vcHandle->numSymbols )
463 {
464 return -EINVAL;
465 }
466 sym = &vcHandle->symbol[ idx ];
467
468 strncpy( labelBuf, sym->label, labelBufSize );
469 labelBuf[labelBufSize - 1] = '\0';
470
471 if ( vcMemAddr != NULL )
472 {
473 *vcMemAddr = (VC_MEM_ADDR_T)sym->addr;
474 }
475 if ( vcMemSize != NULL )
476 {
477 *vcMemSize = sym->size;
478 }
479
480 return 0;
481}
482
483/****************************************************************************
484*
485* Looks up the named, symbol. If the symbol is found, it's value and size
486* are returned.
487*
488* Returns true if the lookup was successful.
489*
490***************************************************************************/
491
492int LookupVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, VC_MEM_ADDR_T *vcMemAddr, size_t *vcMemSize )
493{
494 unsigned idx;
495 char symName[ 64 ];
496 VC_MEM_ADDR_T symAddr = 0;
497 size_t symSize = 0;
498
499 for ( idx = 0; idx < vcHandle->numSymbols; idx++ )
500 {
501 GetVideoCoreSymbol( vcHandle, idx, symName, sizeof( symName ), &symAddr, &symSize );
502 if ( strcmp( symbol, symName ) == 0 )
503 {
504 if ( vcMemAddr != NULL )
505 {
506 *vcMemAddr = symAddr;
507 }
508 if ( vcMemSize != 0 )
509 {
510 *vcMemSize = symSize;
511 }
512
513 DBG( "%s found, addr = 0x%08x size = %zu", symbol, symAddr, symSize );
514 return 1;
515 }
516 }
517
518 if ( vcMemAddr != NULL )
519 {
520 *vcMemAddr = 0;
521 }
522 if ( vcMemSize != 0 )
523 {
524 *vcMemSize = 0;
525 }
526 DBG( "%s not found", symbol );
527 return 0;
528}
529
530/****************************************************************************
531*
532* Looks up the named, symbol. If the symbol is found, and it's size is equal
533* to the sizeof a uint32_t, then true is returned.
534*
535***************************************************************************/
536
537int LookupVideoCoreUInt32Symbol( VC_MEM_ACCESS_HANDLE_T vcHandle,
538 const char *symbol,
539 VC_MEM_ADDR_T *vcMemAddr )
540{
541 size_t vcMemSize;
542
543 if ( !LookupVideoCoreSymbol( vcHandle, symbol, vcMemAddr, &vcMemSize ))
544 {
545 return 0;
546 }
547
548 if ( vcMemSize != sizeof( uint32_t ))
549 {
550 ERR( "Symbol: '%s' has a size of %zu, expecting %zu", symbol, vcMemSize, sizeof( uint32_t ));
551 return 0;
552 }
553 return 1;
554}
555
556/****************************************************************************
557*
558* Does Reads or Writes on the videocore memory.
559*
560***************************************************************************/
561
562static int AccessVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle,
563 MEM_OP_T mem_op,
564 void *buf,
565 VC_MEM_ADDR_T vcMemAddr,
566 size_t numBytes )
567{
568 VC_MEM_ADDR_T origVcMemAddr = vcMemAddr;
569 DBG( "%s %zu bytes @ 0x%08x", mem_op == WRITE_MEM ? "Write" : "Read", numBytes, vcMemAddr );
570
571 /*
572 * Since we'll be passed videocore pointers, we need to deal with the high bits.
573 *
574 * We need to strip off the high 2 bits to convert to a physical address, except
575 * for when the high 3 bits are equal to 011, which means that it corresponds to
576 * a peripheral and isn't accessible.
577 */
578
579 if ( IS_ALIAS_PERIPHERAL( vcMemAddr ))
580 {
581 // This is a peripheral address.
582
583 ERR( "Can't access peripheral address 0x%08x", vcMemAddr );
584 return 0;
585 }
586 vcMemAddr = TO_VC_MEM_ADDR(ALIAS_NORMAL( vcMemAddr ));
587
588 #if 0
589 if ( (vcMemAddr < vcHandle->vcMemBase) ||
590 (vcMemAddr > vcHandle->vcMemEnd) )
591 {
592 ERR( "Memory address 0x%08x is outside range 0x%08x-0x%08x", vcMemAddr,
593 vcHandle->vcMemBase, vcHandle->vcMemEnd );
594 return 0;
595 }
596 #endif
597 if (( vcMemAddr + numBytes - 1) > vcHandle->vcMemEnd )
598 {
599 ERR( "Memory address 0x%08x + numBytes 0x%08zx is > memory end 0x%08x",
600 vcMemAddr, numBytes, vcHandle->vcMemEnd );
601 return 0;
602 }
603
604 vcMemAddr -= vcHandle->memFdBase;
605
606#if defined( WIN32 )
607 if ( mem_op != READ_MEM )
608 {
609 ERR( "Only reads are supported" );
610 return 0;
611 }
612 if ( _lseek( vcHandle->memFd, vcMemAddr, SEEK_SET ) < 0 )
613 {
614 ERR( "_lseek position 0x%08x failed", vcMemAddr );
615 return 0;
616 }
617 if ( _read( vcHandle->memFd, buf, numBytes ) < 0 )
618 {
619 ERR( "_read failed: %s(%d)", strerror( errno ), errno );
620 return 0;
621 }
622#else
623 // DMA allows memory to be accessed above 1008M and is more coherent so try this first
624 if (mem_op == READ_MEM && vcHandle->use_vc_mem)
625 {
626 DBG( "AccessVideoCoreMemory: %p, %x, %d", buf, origVcMemAddr, numBytes );
627 int s = vc_mem_copy(buf, (uint32_t)origVcMemAddr, numBytes);
628 if (s == 0)
629 return 1;
630 }
631
632 {
633 uint8_t *mapAddr;
634 size_t mapSize;
635 size_t memOffset;
636 off_t vcMapAddr;
637 int mmap_prot;
638
639 if ( mem_op == WRITE_MEM )
640 {
641 mmap_prot = PROT_WRITE;
642 }
643 else
644 {
645 mmap_prot = PROT_READ;
646 }
647
648 // We can only map pages on 4K boundaries, so round the address down and the size up.
649
650 memOffset = vcMemAddr & ~PAGE_MASK;
651
652 vcMapAddr = vcMemAddr & PAGE_MASK;
653
654 mapSize = ( memOffset + numBytes + PAGE_SIZE - 1 ) & PAGE_MASK;
655 if (( mapAddr = mmap( 0, mapSize, mmap_prot, MAP_SHARED, vcHandle->memFd, vcMapAddr )) == MAP_FAILED )
656 {
657 ERR( "mmap failed: %s(%d)", strerror( errno ), errno );
658 return 0;
659 }
660 if ( mem_op == WRITE_MEM )
661 {
662 memcpy( mapAddr + memOffset, buf, numBytes );
663 }
664 else
665 {
666 memcpy( buf, mapAddr + memOffset, numBytes );
667 }
668
669 munmap( mapAddr, mapSize );
670 }
671#endif
672
673 return 1;
674}
675
676
677/****************************************************************************
678*
679* Reads 'numBytes' from the videocore memory starting at 'vcMemAddr'. The
680* results are stored in 'buf'.
681*
682* Returns true if the read was successful.
683*
684***************************************************************************/
685
686int ReadVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle, void *buf, VC_MEM_ADDR_T vcMemAddr, size_t numBytes )
687{
688 return AccessVideoCoreMemory( vcHandle, READ_MEM, buf, vcMemAddr, numBytes );
689}
690
691/****************************************************************************
692*
693* Reads 'numBytes' from the videocore memory starting at 'vcMemAddr'. The
694* results are stored in 'buf'.
695*
696* Returns true if the read was successful.
697*
698***************************************************************************/
699
700int ReadVideoCoreMemoryBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, void *buf, size_t bufSize )
701{
702 VC_MEM_ADDR_T vcMemAddr;
703 size_t vcMemSize;
704
705 if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize ))
706 {
707 ERR( "Symbol not found: '%s'", symbol );
708 return 0;
709 }
710
711 if ( vcMemSize > bufSize )
712 {
713 vcMemSize = bufSize;
714 }
715
716 if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize ))
717 {
718 ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr );
719 return 0;
720 }
721 return 1;
722}
723
724/****************************************************************************
725*
726* Looks up a symbol and reads the contents into a user supplied buffer.
727*
728* Returns true if the read was successful.
729*
730***************************************************************************/
731
732int ReadVideoCoreStringBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle,
733 const char *symbol,
734 char *buf,
735 size_t bufSize )
736{
737 VC_MEM_ADDR_T vcMemAddr;
738 size_t vcMemSize;
739
740 if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize ))
741 {
742 ERR( "Symbol not found: '%s'", symbol );
743 return 0;
744 }
745
746 if ( vcMemSize > bufSize )
747 {
748 vcMemSize = bufSize;
749 }
750
751 if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize ))
752 {
753 ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr );
754 return 0;
755 }
756
757 // Make sure that the result is null-terminated
758
759 buf[vcMemSize-1] = '\0';
760 return 1;
761}
762
763/****************************************************************************
764*
765* Writes 'numBytes' into the videocore memory starting at 'vcMemAddr'. The
766* data is taken from 'buf'.
767*
768* Returns true if the write was successful.
769*
770***************************************************************************/
771
772int WriteVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle,
773 void *buf,
774 VC_MEM_ADDR_T vcMemAddr,
775 size_t numBytes )
776{
777 return AccessVideoCoreMemory( vcHandle, WRITE_MEM, buf, vcMemAddr, numBytes );
778}
779
780/****************************************************************************
781*
782* Closes the memory space opened previously via OpenVideoCoreMemory.
783*
784***************************************************************************/
785
786void CloseVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle )
787{
788 unsigned i;
789 if ( vcHandle->symbol )
790 for ( i = 0; i < vcHandle->numSymbols; i++ )
791 free( (char *)vcHandle->symbol[i].label );
792 free( vcHandle->symbol );
793
794 if ( vcHandle->memFd >= 0 )
795 close( vcHandle->memFd );
796
797 free( vcHandle );
798}
799
800/****************************************************************************
801*
802* Returns the base address of the videocore memory space.
803*
804***************************************************************************/
805
806VC_MEM_ADDR_T GetVideoCoreMemoryBase( VC_MEM_ACCESS_HANDLE_T vcHandle )
807{
808 return vcHandle->vcMemBase;
809}
810
811/****************************************************************************
812*
813* Returns the size of the videocore memory space.
814*
815***************************************************************************/
816
817VC_MEM_SIZE_T GetVideoCoreMemorySize( VC_MEM_ACCESS_HANDLE_T vcHandle )
818{
819 return vcHandle->vcMemSize;
820}
821
822/****************************************************************************
823*
824* Returns the videocore memory physical address.
825*
826***************************************************************************/
827
828VC_MEM_ADDR_T GetVideoCoreMemoryPhysicalAddress( VC_MEM_ACCESS_HANDLE_T vcHandle )
829{
830 return vcHandle->vcMemPhys;
831}
832
833