0

I need to read the Asynchronous External Memory Interface (AEMIF) using a TMS320DM368 in an embedded linux environment on custom HW. I don't actually have the hardware yet so I am testing the vala code (below) on a Leopardboard 368. The 1st AEMIF is used by the bootloader to read nand flash. My code is trying to use the 2nd AEMIF to read SRAM that is not on the Leopardboard but will be on the custom HW. I suspect the segmentation fault is caused by the fact that I am trying to access protected memory. The actual custom HW will have several M of SRAM that needs to be read but I am trying to get this test code to read read 256 bytes. How can I fix the segmentation fault caused by the test code below? Do I need to add a driver to the kernel? I'd rather not mess with the kernel if possible. Is there an embedded-linux method to configure or declare certain address ranges as unprotected?

uint8 * source = (uint8 *)0x04000000; // AEMIF Data (CE1)
uint32 * pA2CR = (uint32 *)0x01D10014; // AEMIF 2 Config Reg (CS3 space)
const uint32 READ_SETUP = 1; // Read setup: EMIF clock cycles - 1
*pA2CR = (READ_SETUP << 13);
const size_t size = 256;
var dest = new uint8[size];
memset(dest, 0, size);
memcpy(dest, source, size);
jacknad
  • 13,483
  • 40
  • 124
  • 194
  • 2
    The segfault may not be a protection violation, but simply access to user memory that is not mapped to physical memory. A short-term solution is to `mmap()` a file in place of the SRAM. Note that `mmap()` can be provided with a virtual address to use or will return a virtual address. BTW if you have "custom HW", then you will have to "mess with the kernel". Also see http://stackoverflow.com/questions/11500291/access-nor-memory-from-userspace/12138057#12138057 – sawdust Sep 11 '12 at 20:56
  • @sawdust The custom HW is nearly identical to the Leopoardboard, this SRAM IF may be the one and only departure. If I have to change the kernel I will. – jacknad Sep 11 '12 at 21:02
  • 1
    Just a few little notes from the Vala side of things: you don't need the memset (Vala will initialize new buffers to 0 for you). Also, it would probably be easier to just do something like `unowned uint8[] source = (uint8[]) 0x04000000;`, then you could just use array slicing to get the data you want (e.g., `var dest = source[0:256];`). You really almost never need to use raw pointers in Vala, although some bindings (notably libxml2 and posix) will tempt you to do so. – nemequ Sep 11 '12 at 21:20
  • What are you exactly trying to do? Access a memory address that's not on your device? or try to mock access to it? – auselen Sep 11 '12 at 21:36
  • @auselen External memory access. The external device is actually an FPGA programmed to look like a dual port SRAM. The DM368 needs to read it but does not need to write to it. The AEMIF on the DM368 is ideal for this, it is how the DM368 reads the NAND flash during boot. – jacknad Sep 11 '12 at 21:52
  • 1
    So this address exist on device? On a Linux based system whenever I need to access a physical address I use devmem2. This can help you to check if you can access the address and write similar code. (you can find a copy of it here: http://elinux.org/images/a/aa/Devmem2.c) – auselen Sep 11 '12 at 21:57
  • 3
    The Linux kernel doesn't allow user process to just go and change any physical memory location you want. You either need to write a device driver, or memory map in the I/O range for the device (if your kernel supports that). But doing the latter is problematic, as there's no good way to control access to the I/O area. So you could collide with something else that's going on and cause all kinds of issues. You should really be doing this from the kernel. – John Szakmeister Sep 12 '12 at 00:52
  • Unfortunately some embedded programmers consider the protections that Linux offer as hindrances that need to be either dismantled or worked around. If your embedded product truly has a restricted user interface (e.g. a manual/visual control panel) and stable FW, then hacks like `devmen2.c` probably won't compromise security. But if your product also has electronic interfaces such as a serial console and/or a network interface, then every effort should be made to maintain the Linux security concepts as @jszakmeister mentions. – sawdust Sep 12 '12 at 01:53
  • @sawdust Yes. The user interface is restricted to USB and only responds to custom commands. – jacknad Sep 12 '12 at 11:20
  • BTW instead of hardcoding the start address and length of this memory region, the elegant method is to parametrize these values. Even better if you probe the HW for these values, in U-Boot before the MMU is enabled. I've also used a U_Boot environment variable to override the probe results. See http://stackoverflow.com/questions/11580285/pass-large-amount-of-binary-data-from-u-boot-to-linux-kernel/12137511#12137511 – sawdust Sep 12 '12 at 18:40

1 Answers1

2

I am not familiar with DM386, but I used to work on DM6446. In DM6446, but I expect it to be the same also on DM368, physical addresses are remapped.

I don't know your scenario, but I think you could write a driver using the miscdevice and offer support for read and write operation to your userspace program.

In my kernel modules I use the IO_ADDRESS macro to do the remapping and to access the registers. To give you an example:

#define REG_PINMUX1     (*((volatile unsigned long *) (IO_ADDRESS(PINMUX1))))

and then in the code I have commands like

REG_PINMUX0 &= ~(0x01000000);

So I think you're getting segfault because you have a wrong pointer. And trying to access hw registers from a userspace program without a kernel module is not imho a good strategy.

Ottavio Campana
  • 4,088
  • 5
  • 31
  • 58