- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi there.
I have coded my own bootloader and i need to assign the loaded applications main function and a variable to a specific address that my bootloader calls. Is there a way to force the linker/compiler to place a variable or function at a specific memory address by using the __attribute__ command in my c code. I know that : __attribute__ ((section (".my_mem_name.rwdata"))); assigns the varable or function to a specific memory section, but not a memory specific address. And I have jet another question My bootloader app is placed in internal memory so it executes every time I reset the nois, then it loads a user app into sdram. This works fine but when I jump to "entry" (as defined in the objdump file) nothing happens. If I jump to "main" it seems to work and starts the user program, but if I do this, the user program still uses the exceptions table, heap and stack asignments from the bootloader app. How do I init the assignments from user program? Hopes this makes sense to someone.Link Copied
12 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
> Is there a way to force the linker/compiler to place a variable or function at a > specific memory address by using the __attribute__ command in my c code. This is _normally_ done with the linker command file. For example, a function with a section attribute of ".startfn" in the file start.c can be placed in whatever section you want. If you identify the object file and the input section name as the first entry, it will be located at the start of the output section: <div class='quotetop'>QUOTE </div> --- Quote Start --- SECTIONS { .whatever : { start.o (.startfn) *(.whatever) } ...[/b] --- Quote End --- Everything else from start.o (all other input sections) will be located to their associated output sections as normal. Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
As i understand you are telling me that i need to make a costum linker script(or edit) generated.x file (the auto linker script). Find the section where i want to place my function eq .text and insert "start.o (.startfn)" before anything else. will look something like this SECTIONS { .text : { start.o (.startfn) "line added" *(.interp) *(.hash) *(.dynsym) *(.dynstr) *(.gnu.version) } right ? the result will be that my function is placed (if .text is defined in sdram) at SDRAMbase+.textoffset (the start of text section in sdram). Do you have any clue about my bootloader jmp question? thx for all your help- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
> the result will be that my function is placed (if .text is defined in sdram) at > SDRAMbase+.textoffset (the start of text section in sdram). Yes, in the example you provide, your function (if it's the only .startfn input section in start.o) will be placed at the start of the output .text section. > Do you have any clue about my bootloader jmp question? You'll need to provide more details ... but it's probably a problem with your app format, your loader, or your startup code. > My bootloader app is placed in internal memory so it executes every time I reset the > nois, then it loads a user app into sdram. This works fine but when I jump to "entry" > (as defined in the objdump file) nothing happens. What do you mean "it loads a user app"? Are you using an instruction cache and do you flush before jumping? What code did you implement at the entry point? What happens when you download the code (e.g. using nios2-download) ... does it work? Use nios2-console and set a breakpoint just before jumping to your code. Then step through ... see what happens. Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
>You'll need to provide more details ... but it's probably a problem with your >app format, your loader, or your startup code. Ok here is the detail: I’m coding a standalone bootloader for use with custom fpga hardware. The fpga includes a nios with instruction cache. On this hardware there is also a PowerPC (not in the fpga). The setup should work as follows: In the fpga, at power on, a fpgaimage is loaded from the PowerPC. This image includes a nios and the bootloader code. Bootloader code is placed in internal fpga memory when I build the quartus project. The PowerPC resets the niosCPU and the bootloader starts. The bootloader app requests a binary file from the PowerPC. The file is loaded, by the nios bootloader, into SDRAM. All this works perfect. The last thing the bootloader has to do is to start the user program it just placed in sdram, and here is the problem. It wont start the program. Btw. the user app is compiled with the same nios system as the bootloader, but is set to use only sdram for .text .ro .rw and so on What I do at the end of the bootloader is: use a void pointer and load this with the address I want to call Looks something like this (haven’t got the code in front of me right now) but its only these 2 lines userapp = 0x1000000 ; // or 0x1000034 ; _start or _main userapp(); I can see (in the objdump.file) that this creates a ADDI, a "I cant remember instruction" and at last a CALLR instruction. So this c code seems to work ok, but nothing happens. For starters my user app is simple: main calls a function that runs some LED's As described, if I jump to sdram base (_entry)(address found in user app objdump file) nothing happens. If I jump to (_start) nothing happens. If I jump to (_main) the program runs, and if I jump to (myLEDfunc) it runs. The problem is that I can see that the .heap, .stack and .exceptions +++ still uses the internal fpga memory (led flash slower when running from SDRAM). If I init irq's or init other features in my user app the jump to _main from bootloader doesn’t work. my conclusion: I’m missing something but what? >What do you mean "it loads a user app"? Are you using an instruction cache and >do you flush before jumping? NO, how do I do that ? What code did you implement at the entry point? none (using default compiler script) > What happens when you download the code (e.g. using nios2-download) ... does it work? I'm not using any tools provited with the nios software >Use nios2-console and set a breakpoint just before jumping to your code. Then >step Bootloader jumps but user app crash depending on address I jump to thx for all your help and time Scott I think I need it.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
Sounds like a problem with a stray interrupt and/or the exception trampoline. If your exception address is in SDRAM, you need to: (1) disable interrupts, (2) load the image into SDRAM, (3) flush icache and the pipeline, (4) finally jump to _start. Actually you should flush the icache/pipeline no matter where your exception address is -- otherwise you run the risk of executing stale code in the icache. And even though you don't have a data cache, it's a good idea to go through the motions anyway (which will be the equivalent of a few nops) ... it will save you some headaches in the future if you decide to add dcache. But a few more questions: 1. Where is your exception address located? SDRAM? 2. How do you generate the binary file? And a few comments: > If I jump to (_start) nothing happens. - _start is the correct entry point. In your case, since .text is not in the boot device, and you have no data cache, all _start does is: (1) set the stack pointer to the top of memory, (2) sets the gp, (3) clears .bss, and (4) calls alt_main. Check your system library properties to make sure you have your stack, heap, etc. set properly. - _start does NOT call alt_load when .text is NOT in the boot device. It's your loader's responsibility to load the various sections to their proper VMA. Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
>1. Where is your exception address located? SDRAM? For the bootloader application all system library properties is set to internal nios memory (.text .ro .rw .exception .heap and stack) including the sopc builder settings reset addr and exception (as if the sdram didn’t exist) For the user application, all settings are in sdram, except SOPC .reset setting it's still in internal memory. The reset addr for both bootloader and user application is in internal memory. So if I reset the nios, at any point in any application(s), the nios would reboot and start the bootloader. What I’m trying to do is to have one application in internal memory (bootloader) and another in sdram (user app). My goal with this is to load and execute the user app (via. the bootloader) as if it was downloaded by the nios IDE (-run as nios hardware) but without using the nios IDE software. >2. How do you generate the binary file? This took me some time to figure out, but i use the elf2hex tool and run it from nios2 sdk shell: elf2hex --input=userapp.elf --output=userapp.bin --width=8 --start=0x1000000 --end=0x1FFFFFF This creates my binary file. I have compared the file with the memory content of the sdram when I use the nios IDE to download the user app they are the same. So it seems my file is valid. I have also compared the sdram memory content, when using my bootloader, with the sdram memory content, when using the nios IDE to download my user app. Again it’s the same result. My conclusion is that my file transfer works. >exception address is in SDRAM, you need to: (1) disable interrupts, (2) load the >image into SDRAM, (3) flush icache and the pipeline, (4) finally jump to _start. Ok I understand my bootloader should do this. Is there a function(s) to flush icache,dcache and pipeline that i can use? my guess is: alt_icache_flush_all(), alt_dcache_flush_all() > _start is the correct entry point. Ok so my target is to call _start. I haven't seen this work jet, but it probably helps when I flush icache >Check your system library properties to make sure you have your stack, heap, etc. set properly. Bootloader sets stack pointer top of internal Memory. User application sets stack pointer top of SDRAM Memory. 0x2000000 > _start does NOT call alt_load when .text is NOT in the boot device. It's your loader's responsibility to load the various sections to their proper VMA. I’m not sure that this means? As i understand alt_load normally copys .ro .rw .exceptions from LMA to VMA or am i wrong ? In my user app, the objdump file shows me that LMA and VMA for .ro and .rw are the same, all located in sdram. When i create my binary file, these addresses are included. So when the bootloader copys the user app bin file to SDRAM the .ro .rw are initialised. Or are they?? Regards Rasdan- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
> For the bootloader application all system library properties is set to internal nios > memory (.text .ro .rw .exception .heap and stack) including the sopc builder settings > reset addr and exception (as if the sdram didn’t exist) Ok, so your processor's exception address is in the internal memory. > For the user application, all settings are in sdram, > except SOPC .reset setting it's still in internal memory. If I understand you correctly, for your user application, you are placing the .exception section in SDRAM??? If this is the case, this is your problem. That is: - the exception address is set in SOPCBuilder ... it's fixed ... your .exception section in your user application MUST be assigned to this address. Simply changing the VMA in your application is useless. - If you're downloading the app, the on chip memory (where the exception address is set) must be ram ... otherwise you can't overwrite the exception handler. If it's rom, the handler isn't overwritten, and an interrupt in your user app will cause the exception handler in your bootloader to execute -- probably not what you want. - If the on chip memory is actually ram, then resetting the CPU (not the FPGA) also cause problems if your bootloader code enables interrupts -- since the exception handler has been overwritten by the application. - And finally, if alt_load is not called, then your application's exception handler is not copied to the correct address -- you're app will have to do that itself -- unless your bootloader is smart enough to do it. Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
>Ok, so your processor's exception address is in the internal memory. Yes >If I understand you correctly, for your user application, you are placing >the .exception section in SDRAM??? >If this is the case, this is your problem. : Sorry my fault. No the user app .exception segment is set to internal memory. so it should be ok. > If the on chip memory is actually ram, then resetting the CPU (not the FPGA) >also cause problems if your bootloader code enables interrupts -- since the > exception handler has been overwritten by the application. The on chip memory is ram, and i'm not using interrupts in the bootloader. However the bootloader project is not a freestanding application. So if this enables interrupts i'm not avere of it, but i don't use them anyway, so this shouldn't be a problem? >- And finally, if alt_load is not called, then your application's exception handler is >not copied to the correct address -- you're app will have to do that itself -- unless >your bootloader is smart enough to do it. My user application is a freestanding project. I don't call alt_load in my user application or in the bootloader. If I understand you correct, this is a problem because the .exception segment, from my bootloader program, is still in internal memory when the user application is started. This fact will course a conflict when the user application uses or initialises interrupt. So to sum up, this is really important. -BOOTLOADER After transfer of user application to SDRAM: -make sure interrupts is not used If your not using _alt_load in the user application. -Copy .exception from user app image(now in sdram, look in objdump file to locate, normally sdrambase + 0x20 to ??). Copy this segment to the .exception address defined in SOPC builder, overwriting the bootloaders .exception code. -flush icache, dcache and the pipeline, using alt_icache_flush_all(), alt_dcache_flush_all() -Call _start address to start the user application USER APPLICATiON If boot loader doesn’t handle the .exception copy thing. Call the alt_load function at the start of main/alt_main to do the same job. -Do whatever to code needs to do. Hope this is correct? Regards, Rasdan EDIT UPDATE!! Ok I still have the same questions I tried flushing icache and dcache. The result was the same no execution of the user program. Then I tried something new: I edited the bootloader so it only loads code into sdram nothing more, no calls, no flush. Then I made a new freestanding project witch sole purpose was to call/jump to _start (were my userprogram is located after the bootloader ends) I compiled the quartus project with the new no_jump bootloader, reset my board and let the bootloader load the user app into sdram. Then I used the nios IDE to run my new jump program into internal ram (making sure not to destroy the user program in sdram). The jump program look like this: int alt_main(void) { void (*AppStartP)(void); alt_irq_init (ALT_IRQ_BASE); alt_sys_init(); alt_icache_flush_all(); alt_dcache_flush_all(); AppStartP = (void*)0x1000000; //_start AppStartP(); } I run the jump program and nothing happen, no led flashing. I then edit the jump program to look like this: int alt_main(void) { void (*AppStartP)(void); //alt_irq_init (ALT_IRQ_BASE); alt_sys_init(); alt_icache_flush_all(); alt_dcache_flush_all(); AppStartP = (void*)0x1000000; //_start AppStartP(); } I run it and my user application starts and the led flashing begins. My conclusion: If the bootloader (nonfreestanding) init interrupts the jump/call doesn’t work. I think this happens with a non freestanding application just before main QUESTION: Why does this irq init affect the call/jump to the user application?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
> However the bootloader project is not a freestanding application. ... > My user application is a freestanding project. > I don't call alt_load in my user application or in the bootloader. Ok. Just to be sure we're on the same page: --The difference between freestanding and hosted basically boils down to who implements alt_main ... the application or the HAL. In a freestanding app, the application (programmer) implements alt_main by overriding alt_main.c. In a hosted app, the HAL implements alt_main (which calls the app's main routine). --alt_load on the other hand is called by the startup code (crt0) when: (1) your .text section is located in the boot device AND (2) your .rodata, .rwdata, or .exceptions are _NOT_ in the boot device. So "freestanding" v. "hosted" really doesn't affect the sections being loaded: --Your bootloader does not call alt_load since the bootloader's .rodata, .rwdata and .exceptions are all in the on chip ram (everything is already where it needs to be). --Your application does not call alt_load because its .text section is not in the boot device. I think the short answer (sorry for rambling above) is your plan sounds fine to me. But you need to consider a few things for everything to work the way you want it to: 1. After your application is loaded and successfully executed, your bootloader's exception handler has been overwritten. If your application exits (returns to the bootloader) or the CPU is reset, your bootloader will not restore its exception handler. 2. If the exception handler in your application and the handler in your bootloader are not the same size (e.g. different versions of the HAL or the app has a custom handler, etc) it is possible for the application handler to corrupt you bootloader code. That is, if the app exception handler is longer than the loader's, you'll spill over into an adjacent section of you boot loader's image (probably the HAL irq dispatch code). Which may or may not be fatal ;-) You can probably resolve most of these issues by placing your exception address in SDRAM. In this case, the bootloader code should relocate its exception handler each time it runs (since .exceptions are not in the boot device). And, your application will already have the exception handler where it needs to be when it is loaded -- just food for thought -- you may want to experiment with it regardless :-) Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
Thx for the outstanding explanation on the difference between hosted and freestanding applications. This has answered all questions I might have on this topic. > Your plan sounds fine to me. I'm very happy you think my approach is fine >1. After your application is loaded and successfully executed, your bootloader's >exception handler has been overwritten. If your application exits (returns to the >bootloader) or the CPU is reset, your bootloader will not restore its exception >handler. This shouldn't be a problem. My user application never exits and my bootloader doesn’t do anything that uses exceptions. >2. That is, if the app exception handler is longer than the loader's, you'll spill >over into >an adjacent section of you boot loader's image (probably the HAL irq dispatch >code). >Which may or may not be fatal ;-) Yes I guess this would be fatal, but only if the bootloader .exception segment is placed is internal ram. If so, I would have to copy the user app .exception segment to internal ram overwriting the bootloaders .exception segment and probably some other bootloader code due to the segment size difference. You mention placing exception address in SDRAM (SOPC builder). As i understand this would eliminate the overwriting problem because at power on the boot loader is started and copies (crt0) the exception segment to SDRAM automatically. After this the bootloader (my code) probably overwrites the exception segment with the user app and calls it. My user application doesn’t need to copy anything because all segments (except reset) are defined in sdram so they are already there. If I, at this point, reset the cpu the bootloader should work just fine. Is this correct? >You can probably resolve most of these issues by placing your exception address in sdram Yes i have done this, and finally something works. Bootloader calls user program (_start) after load to SDRAM and the program runs (led flashing). However this is not the end (sorry). This only works IF the bootloader is freestanding and it doesn’t call : alt_irq_init (ALT_IRQ_BASE); Any use of this function in the bootloader will somehow crash the user application when i call (_start). I don't understand why? Do u have any clue to this? What I’m afraid of is that this is a symptom of a problem I might encounter later on, when I start using interrupts in my user application. I don't want to have some strange "why doesn’t the interrupt work" problem later on if I can help it. Regards, Rasdan- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rasdan,
> Yes I guess this would be fatal, but only if the bootloader .exception segment > is placed is internal ram. Correct. If the exception address is in SDRAM, the bootloader _should_ always copy its .exception section to the exception address -- so no problem. > After this the bootloader (my code) probably overwrites the exception segment with > the user app and calls it. My user application doesn’t need to copy anything because > all segments (except reset) are defined in sdram so they are already there. > If I, at this point, reset the cpu the bootloader should work just fine. > > Is this correct? Correct. > This only works IF the bootloader is freestanding and it doesn’t call : > > alt_irq_init (ALT_IRQ_BASE); > > Any use of this function in the bootloader will somehow crash the user application > when i call (_start). > I don't understand why? > Do u have any clue to this? This all gets back to alt_main -- when your app is "hosted" the HAL alt_main is called ... which in turn calls alt_sys_init. And alt_sys_init is the most likely culprit. alt_irq_init just clears the ienable (disables all external hardware interrupts), then sets status.PIE (enables CPU response to external interrupts) -- not a problem ... ... at least not yet: When alt_sys_init is called, the drivers for your hardware are initialized and interrupts get enabled. My guess is: (1) you have at least 1 timer, (2) it's selected as the system clock in your syslib properties, (3) the interrupt gets enabled, and finally (4) the interrupt is asserted and causes problems while you are downloading (and overwriting the exception trampoline). You can test this by selecting "none" for your system clock timer -- see if things get better ;-) Let us know how you make out :-) Regards, --Scott- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Scott,
>Let us know how you make out :-) Status today: Everything seems to work. I tested the interrupt system using a timer in my user application and it works perfect. At this time I have no further problems. I can see a lot of people have been looking at this topic. So for anyone reading this topic and reaching all the way down to this post. I would like to sum up everything I did to get this far. I will not comment on why the settings are the way they are. This info can be found in the text above (replys). So here goes: TARGET: 1. Make an independent bootloader that loads a user application from a nios hardware interface into SDRAM. (this interface could be anything rs232, parallel port, usb, TCP/IP or custom something). My project uses a custom interface between a PowerPC and the nios. 2. Bootloader has to call and execute the user application at the end of user application transfer. 3. A nios reset should restart the bootloader so the user application can be updated or reloaded. NIOS HARDWARE minimum: Nios cpu (no comment) Internal on chip memory (program memory for bootloader) User application memory (SDRAM in my case) Interface hardware (my PowerPC - NIOS interface, anything could be used). SOPC SETTINGS: Reset address: on chip ram Exception address: user application memory (sdram) Break location: whatever SOFTWARE SETTINGS (Nios IDE) 1. Bootloader: Program mem (.text): on chip ram Read only mem (.rodata) : on chip ram Read/write mem (.rwdata) : on chip ram Heap mem: on chip ram Stack mem: on chip ram System clock timer: select none 2. User application Program mem (.text): SDRAM Read only mem (.rodata) : SDRAM Read/write mem (.rwdata) : SDRAM Heap mem: SDRAM Stack mem: SDRAM SOFTWARE BOOTLOADER This should be a freestanding application. Use hallo freestanding as template. Delete any init functions calls in this code (These will probably cause something bad to happen). //alt_sys_init(); //alt_sys_init(); //alt_io_redirect(); The first thing the bootloader should do is to copy the user program into the user application memory. Can’t help with this. This depends on the interface you are using) When this is done all that is left is to call the user application, flush icache and dcache. alt_icache_flush_all(); alt_dcache_flush_all(); AppStartP = (void*)0x10001c8; // _start address (found in objdump file) AppStartP(); // call application SOFTWARE USER APP: Do whatever you need to do. GENERATION OF USER APPLICATION UPLOAD FILE Click Start->All programs->Altera->Nios II development kit -> nios II SDK shell In the console use elf2hex: elf2hex --input=userapp.elf --start=0x1000000 --end=0x1ffffff –width= 8 This creates a hex file named userapp.hex that contains the user program. This can be changed to binary or whatever are needed using normal hex2bin tools. It’s not needed to set end addr to the end of the sdram(my case) only to the end of user application (look in objdump file) --------------------------------------------- This seems real simple when you know how. -comments to Scott >My guess is: (1) you have at least 1 timer Correct! What a great guess > It’s selected as the system clock in your syslib properties Correct again! Now Scott how do you know all this (all of it)? Your understanding of the nios system seems amazing, you deserve the NIOS GOD status of your profile. Your help has been amazing and I’m very grateful to you, but also to the nios community for making this possible. Thank you all Feel free to comment on anything. I will be reading any comments. Regards, --Rasdan
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page