Forum Discussion
uClinux .data segment in SDRAM?
For a number of reasons, I'd like to run my kernel in SRAM but allocate data memory (i.e. socket buffers) in SDRAM. This seems possible with a NIOS 'Hello World' application, or the like, but these options aren't readily apparent when creating a kernel project in Eclipse. Is there a config file I can tweak, or other steps to be performed to accomplish putting .DATA in SDRAM? I've considered actually rewriting appropriate allocation routines in the kernel, but that feels very dangerous. Any help would be appreciated.
Thanks in advance, Ryan22 Replies
- Altera_Forum
Honored Contributor
If my understanding is right, you want to put kernel image (text, data and bss) in sram, while make the entire sdram system memory. There is a lot of work to do in order to achieve this, including,
1. change the core to move the reset address to 0x20 off the start of sram (as opposed to adram). 2. define nasys_program_mem as start of sram (as opposed to sdram) 3. Modification of the kernel linker script and setup_arch function. You might be able to bypass this if there is no holes in the address space between sram and sdram (in other words, sdram starts immediately after sram). ... I did not try this. Good luck, - Altera_Forum
Honored Contributor
Thanks for the response Wentao,
<div class='quotetop'>QUOTE </div> --- Quote Start --- If my understanding is right, you want to put kernel image (text, data and bss) in sram, while make the entire sdram system memory[/b] --- Quote End --- No, this is not quite what I'm going for. Let me explain further. Currently, I have 16MB of onboard SRAM and up to 1GB of SDRAM. My entire kernel and user-level code runs completely in SRAM at the moment. I can explicitly address and store data in SDRAM from my code (but all OS-allocated memory is in SRAM). Basically, the problem here is that I want to be able to DMA data directly from SDRAM to ethernet; with my current setup, this cannot be done, because all kernel data structures are allocated in SRAM. So, calling a socket send() with an SDRAM buffer results in a copy from SDRAM to the SRAM socket buffer. I _think_ this can be mitigated by moving the kernel .DATA and .BSS segments to SDRAM. Another option is to modify the kernel to allocate socket buffers in SDRAM, but I forsee problems with this. I can edit the kernel linker script to put .DATA and .BSS in sdram. But, my SDRAM sits at 0x0 to 0x3FFFFFFF, with SRAM beginning at 0x40000000. I'm guessing this is a problem as well, as my kernel linked this way will not boot. Hope this makes more sense. Ryan - Altera_Forum
Honored Contributor
<div class='quotetop'>QUOTE </div>
--- Quote Start --- No, this is not quite what I'm going for[/b] --- Quote End --- sorry. <div class='quotetop'>QUOTE </div> --- Quote Start --- I _think_ this can be mitigated by moving the kernel .DATA and .BSS segments to SDRAM[/b] --- Quote End --- sure you can go this way. Please note you also need to modify the bootstrap code (arch/nios2nommu/kernel/head.S) to copy .DATA section into a different place than immediately following .TEXT. <div class='quotetop'>QUOTE </div> --- Quote Start --- Another option is to modify the kernel to allocate socket buffers in SDRAM, but I forsee problems with this[/b] --- Quote End --- Can you tell me what problem you foresee? Currently the DMA zone is empty, you can put all your sdram into that zone and just remember to specify GFP_DMA when your driver wants memory. You don't need to change the memory management part of the kernel. I think this is easier than the first solution. To add sdram to dma zone, you need to modify function paging_init in file arch/nios2nommu/mm/init.c. Good luck. Let me know if there are problems, wentao Microtronix - Altera_Forum
Honored Contributor
Thanks Wentao, your second idea sounds perfect.
<div class='quotetop'>QUOTE </div> --- Quote Start --- Can you tell me what problem you foresee?[/b] --- Quote End --- The only real problem I saw with modifying the kernel was the fact that I'm no kernel expert, and it _basically_ works now http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/smile.gif . But your explanation definitely seems simple enough. <div class='quotetop'>QUOTE </div> --- Quote Start --- Currently the DMA zone is empty, you can put all your sdram into that zone and just remember to specify GFP_DMA when your driver wants memory.[/b] --- Quote End --- From cursory inspection of init.c -- where exactly can I tell the kernel that ZONE_DMA begins at 0x0? I see in paging_init where to specify size -- and it works, but gives me chunks of SRAM right now -- I just can't find where the zone structure offsets are defined. Thanks again for all the help, Ryan - Altera_Forum
Honored Contributor
The function free_area_init assumes the starting address is PAGE_OFFSET. You need to change the definition of PAGE_OFFSET to 0 (the minimum of the starting addresses of all your memory devices) in file include/asm-niosnommu/page.h.
Tell me if you have problems - Altera_Forum
Honored Contributor
Hi Wentao, thanks again,
I tried your suggestions, and I get a 'page allocation failure' on boot. I've pasted the boot output below. Currently, I'm setting PAGE_OFFSET to 0 and zones_size[ZONE_DMA] to 64M >> PAGE_SHIFT. Also, zones_size[ZONE_NORMAL] is being set to (end_mem - PAGE_OFFSET)>>PAGE_SHIFT. Is this correct? Thanks in advance, Ryan uClinux/Nios II Altera Nios II support © 2004 Microtronix Datacom Ltd. KERNEL -> TEXT=0x40000000-0x40132b9c DATA=0x40132ba0-0x40160000 BSS=0x40179350-0 x4017937d KERNEL -> MEM=0x4017a000-0x41000000 STACK=0x41000000-0x41000000 setup_arch: No persistant network settings signature at 43FF0000 Built 1 zonelists Kernel command line: root=/dev/mtdblock0 ro PID hash table entries: 4096 (order: 12, 65536 bytes) Dentry cache hash table entries: 262144 (order: 8, 1048576 bytes) Inode-cache hash table entries: 131072 (order: 7, 524288 bytes) Mem_init: start=4017a000, end=41000000 Memory available: 4608k/16384k RAM, 0k/0k ROM (1226k kernel code, 281k data) Mount-cache hash table entries: 512 (order: 0, 4096 bytes) NET: Registered protocol family 16 Serial: JTAG UART driver $Revision: 1.3 $ ttyJ0 at MMIO 0xc4000808 (irq = 0) is a jtag_uart RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize smc_probe: 75000 Khz Nios SMSC LAN91C111 Driver (v2.1), (Linux Kernel 2.6) eth0: SMC91C11xFD(rev:1) at 0x4400a000 IRQ:2 MEMSIZE:8192b NOWAIT:0 ADDR: 00:07: ed:00:00:00 smc_probe: 75000 Khz Nios Using anticipatory io scheduler Microtronix map: Found 1 x16 devices at 0x0 in 16-bit bank Amd/Fujitsu Extended Query Table at 0x0040 Microtronix map: CFI does not contain boot bank location. Assuming top. number of CFI chips: 1 cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness. cmdlinepart partition parsing not available RedBoot partition parsing not available Using Microtronix development partition definition Creating 2 MTD partitions on "Microtronix map": 0x00200000-0x00800000 : "romfs" 0x00000000-0x00200000 : "loader/kernel" NET: Registered protocol family 2 IP: routing cache hash table of 8192 buckets, 64Kbytes swapper: page allocation failure. order:10, mode:0x20 Stack from 40bd1ef0:<0> <0> 0000000a<0> 4002dbe8<0> 00000020<0> 00000000<0> 00000001<0> deadbeef< 0> deadbeef<0> deadbeef<0> <0> deadbeef<0> 4016c2e8<0> 4016c8ac<0> 4013c394<0> 0000000a<0> deadbeef< 0> 4002dc18<0> 4016b1c4<0> <0> 00000000<0> 00000000<0> 401782f0<0> 4013d284<0> 4013d284<0> 4016b8ec< 0> deadbeef<0> deadbeef<0> <0> 4016c2e8<0> 4016c8ac<0> 00000000<0> 4016c898<0> 40000274<0> deadbeef< 0> deadbeef<0> deadbeef<0> <0> 401756a0<0> 400044c4<0> 401756a0<0> deadbeef<0> deadbeef<0> deadbeef< 0> deadbeef<0> 401756a0<0> <0> 40bd1f98<0> 40008b34<0> deadbeef<0> deadbeef<0> 40002fb4<0> 00000000< 0> 00000000<0> 00000000<0> Call Trace:<0> <0> [<40007768>]<0> [<400001b0>]<0> [<40000150>]<0> [<400044b4>]<0> TCP: Hash tables configured (established 262144 bind 65536) oom-killer: gfp_mask=0xd0 DMA per-cpu: cpu 0 hot: low 2, high 6, batch 1 cpu 0 cold: low 0, high 2, batch 1 Normal per-cpu: cpu 0 hot: low 32, high 96, batch 16 cpu 0 cold: low 0, high 32, batch 16 HighMem per-cpu: empty Free pages: 888kB (0kB HighMem) Active:0 inactive:0 dirty:0 writeback:0 unstable:0 free:222 slab:318 mapped:0 pa getables:0 DMA free:0kB min:12kB low:24kB high:36kB active:0kB inactive:0kB present:16384kB protections[]: 0 0 0 Normal free:888kB min:1020kB low:2040kB high:3060kB active:0kB inactive:0kB pres ent:1064960kB protections[]: 0 0 0 HighMem free:0kB min:128kB low:256kB high:384kB active:0kB inactive:0kB present: 0kB protections[]: 0 0 0 DMA: 0*4kB 0*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 0kB Normal: 0*4kB 1*8kB 1*16kB 1*32kB 1*64kB 0*128kB 1*256kB 1*512kB 0*1024kB 0*2048 kB 0*4096kB = 888kB HighMem: empty DMA per-cpu: cpu 0 hot: low 2, high 6, batch 1 cpu 0 cold: low 0, high 2, batch 1 Normal per-cpu: cpu 0 hot: low 32, high 96, batch 16 cpu 0 cold: low 0, high 32, batch 16 HighMem per-cpu: empty Free pages: 888kB (0kB HighMem) Active:0 inactive:0 dirty:0 writeback:0 unstable:0 free:222 slab:318 mapped:0 pa getables:0 DMA free:0kB min:12kB low:24kB high:36kB active:0kB inactive:0kB present:16384kB protections[]: 0 0 0 Normal free:888kB min:1020kB low:2040kB high:3060kB active:0kB inactive:0kB pres ent:1064960kB protections[]: 0 0 0 HighMem free:0kB min:128kB low:256kB high:384kB active:0kB inactive:0kB present: 0kB protections[]: 0 0 0 DMA: 0*4kB 0*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 0kB Normal: 0*4kB 1*8kB 1*16kB 1*32kB 1*64kB 0*128kB 1*256kB 1*512kB 0*1024kB 0*2048 kB 0*4096kB = 888kB HighMem: empty Kernel panic - not syncing: Out of memory and no killable processes... - Altera_Forum
Honored Contributor
If you want to leave a hole between the two zones, there is more work to do. You can no longer use the function free_area_init, you have to call free_area_init_node, in paging_init.
If you want to stick to the simpler free_area_init, you have to tell it the actual size of your SDRAM. The flip side is you will waste a lof of memory on the paging structures (there are two many pages). My advice is, right now stick to free_area_init and give all 1G sdram to Linux, make sure it works. In the future you can use free_area_init_node. - Altera_Forum
Honored Contributor
Thanks again,
The problem with telling it about all 1G is that I don't have all 1G of SDRAM right now -- just a 128MB stick. So, right now, my gear looks like: 0x0 - 0x07FFFFFF -- SDRAM 0x08000000 - 0x3FFFFFFF -- Nothing 0x40000000 - 0x40FFFFFF -- SRAM So, if I understand correctly, to use free_area_init_node, I need to pass it a zholes_size array, which in my case should be { (0x40000000 - 0x08000000), 0, 0 }. I edited paging_init as shown below, and I get uClinux/Nios II Altera Nios II support © 2004 Microtronix Datacom Ltd. KERNEL -> TEXT=0x40000000-0x40132c04 DATA=0x40132c10-0x40160000 BSS=0x40179350-0 x4017937d KERNEL -> MEM=0x4017a000-0x41000000 STACK=0x41000000-0x41000000 setup_arch: No persistant network settings signature at 43FF0000 start_mem is 0x4017a000 virtual_end is 0x41000000 Built 1 zonelists Kernel command line: root=/dev/mtdblock0 ro PID hash table entries: 4096 (order: 12, 65536 bytes) __alloc_bootmem_core(): zero-sized request /cygdrive/c/altera/kits/nios2/bin/eclipse/plugins/com.microtronix.nios2linux.ker nel_0.1.5/linux-2.6.x/mm/bootmem.c(156): kernel BUG! Dentry cache hash table entries: -2147483648 (order: -12, 0 bytes) __alloc_bootmem_core(): zero-sized request /cygdrive/c/altera/kits/nios2/bin/eclipse/plugins/com.microtronix.nios2linux.ker nel_0.1.5/linux-2.6.x/mm/bootmem.c(156): kernel BUG! Inode-cache hash table entries: 1073741824 (order: -12, 0 bytes) Any thoughts? Am I doing something blatantly wrong in the code below? Ryanvoid paging_init(void) { /* * Make sure start_mem is page aligned, otherwise bootmem and * page_alloc get different views of the world. */ # ifdef DEBUG unsigned long start_mem = PAGE_ALIGN(memory_start); //#endif unsigned long end_mem = memory_end & PAGE_MASK; //#ifdef DEBUG printk (/*KERN_DEBUG*/ "start_mem is %#lx\nvirtual_end is %#lx\n", start_mem, end_mem); //#endif /* * Initialize the bad page table and bad page to point * to a couple of allocated pages. */ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)empty_zero_page, 0, PAGE_SIZE); /* * Set up SFC/DFC registers (user data space). */ set_fs (USER_DS); # ifdef DEBUG printk (KERN_DEBUG "before free_area_init\n"); printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", start_mem, end_mem);# endif { unsigned long zones_size = {0, 0, 0}; unsigned long holes_size = {0, 0, 0}; zones_size = (0x8000000-PAGE_OFFSET) >> PAGE_SHIFT; zones_size = (0x1000000-PAGE_OFFSET) >> PAGE_SHIFT; holes_size = zones_size-zones_size; # ifdef CONFIG_HIGHMEM zones_size = 0;# endif //free_area_init(zones_size); free_area_init_node(0, &contig_page_data, zones_size, __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes_size); } } - Altera_Forum
Honored Contributor
sorry! I was busy on something else. Any progress?
Regarding your lost post, I think the zones_size[ZONE_NORMAL] shall be the actual size of your sram. and the hole for DMA_ZONE shall be 1G-128M. Of course all sizes are in pages. But I have never tried this, so not quite sure about this. - Altera_Forum
Honored Contributor
<div class='quotetop'>QUOTE </div>
--- Quote Start --- I think the zones_size[ZONE_NORMAL] shall be the actual size of your sram. and the hole for DMA_ZONE shall be 1G-128M. Of course all sizes are in pages. But I have never tried this, so not quite sure about this.[/b] --- Quote End --- I think I'm getting closer --- new panic message below. It seems to now be recognizing the 128MB in ZONE_DMA, and 16MB in ZONE_NORMAL, but it's still hiccupping near the end of the boot process. Any thoughts? Thanks again. Ryan uClinux/Nios II Altera Nios II support © 2004 Microtronix Datacom Ltd. KERNEL -> TEXT=0x40000000-0x40132cb0 DATA=0x40132cb0-0x40160000 BSS=0x40179350-0 x4017937d KERNEL -> MEM=0x4017a000-0x41000000 STACK=0x41000000-0x41000000 setup_arch: No persistant network settings signature at 43FF0000 start_mem is 0x4017a000 virtual_end is 0x41000000 Built 1 zonelists Kernel command line: root=/dev/mtdblock0 ro PID hash table entries: 1024 (order: 10, 16384 bytes) Dentry cache hash table entries: 32768 (order: 5, 131072 bytes) Inode-cache hash table entries: 16384 (order: 4, 65536 bytes) Mem_init: start=4017a000, end=41000000 Memory available: 6264k/16384k RAM, 0k/0k ROM (1227k kernel code, 281k data) Mount-cache hash table entries: 512 (order: 0, 4096 bytes) NET: Registered protocol family 16 Serial: JTAG UART driver $Revision: 1.3 $ ttyJ0 at MMIO 0xc4000808 (irq = 0) is a jtag_uart RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize Loading Quantapoint LIDAR Processor Driver v. 0.1 smc_probe: 75000 Khz Nios SMSC LAN91C111 Driver (v2.1), (Linux Kernel 2.6) eth0: SMC91C11xFD(rev:1) at 0x4400a000 IRQ:2 MEMSIZE:8192b NOWAIT:0 ADDR: 00:07: ed:00:00:00 smc_probe: 75000 Khz Nios Using anticipatory io scheduler Microtronix map: Found 1 x16 devices at 0x0 in 16-bit bank Amd/Fujitsu Extended Query Table at 0x0040 Microtronix map: CFI does not contain boot bank location. Assuming top. number of CFI chips: 1 cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness. cmdlinepart partition parsing not available RedBoot partition parsing not available Using Microtronix development partition definition Creating 2 MTD partitions on "Microtronix map": 0x00200000-0x00800000 : "romfs" 0x00000000-0x00200000 : "loader/kernel" NET: Registered protocol family 2 IP: routing cache hash table of 8192 buckets, 64Kbytes TCP: Hash tables configured (established 524288 bind 65536) NET: Registered protocol family 1 NET: Registered protocol family 17 VFS: Mounted root (romfs filesystem) readonly. Freeing unused kernel memory: 48k freed (0x40160000 - 0x4016b000) Warning: unable to open an initial console. sh: page allocation failure. order:5, mode:0xd0 Stack from 40b4fd58:<0> <0> 00000005<0> 4002dc2c<0> 00000000<0> 00000010<0> 00000000<0> 00000001< 0> 000000d0<0> 000000d0<0> <0> 0000000d<0> 40182e6c<0> 40182e60<0> 409f00a0<0> 40182e60<0> 40a06400< 0> 4002dc5c<0> 40031a6c<0> <0> 00000000<0> 40032318<0> 00000011<0> 00009b50<0> 00004036<0> 4013582c< 0> 4017e620<0> 00000001<0> <0> 000119b6<0> 00000001<0> 40031f68<0> 00000000<0> 40037cec<0> deadbe00< 0> 00000000<0> 00000000<0> <0> 00000080<0> 4099ccc0<0> 00000001<0> 0000c514<0> 000012b0<0> 00000004< 0> 40a2dba0<0> ffffe000<0> <0> 4004a060<0> 40047644<0> 00006873<0> 00000000<0> 40b4e000<0> 00000000< 0> 00000002<0> 401353b0<0> Call Trace:<0> <0> [<400681c0>]<0> [<4002d698>]<0> [<40047fe0>]<0> [<40048238>]<0> <0> [<40004558>]<0> [<400030d0>]<0> [<40002b70>]<0> Allocation of length 72118 from process 12 failed DMA per-cpu: cpu 0 hot: low 16, high 48, batch 8 cpu 0 cold: low 0, high 16, batch 8 Normal per-cpu: cpu 0 hot: low 2, high 6, batch 1 cpu 0 cold: low 0, high 2, batch 1 HighMem per-cpu: empty Free pages: 204kB (0kB HighMem) Active:3 inactive:0 dirty:0 writeback:0 unstable:0 free:51 slab:396 mapped:0 pag etables:0 DMA free:0kB min:340kB low:680kB high:1020kB active:0kB inactive:0kB present:131 072kB protections[]: 0 0 0 Normal free:204kB min:40kB low:80kB high:120kB active:12kB inactive:0kB present: 16384kB protections[]: 0 0 0 HighMem free:0kB min:128kB low:256kB high:384kB active:0kB inactive:0kB present: 0kB protections[]: 0 0 0 DMA: 0*4kB 0*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 0kB Normal: 7*4kB 8*8kB 5*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048 kB 0*4096kB = 204kB HighMem: empty Unable to allocate RAM for process text/data, errno 12 munmap of non-mmaped memory by process 12 (sh): 4017e640 Kernel panic - not syncing: Attempted to kill init!