riscv-rust / hifive1

Board support crate for HiFive1 and LoFive boards
77 stars 16 forks source link

Modify the Linker Script #19

Open dkhayes117 opened 4 years ago

dkhayes117 commented 4 years ago

Is it possible to modify the linker script on my project? I want to keep all machine mode and user mode functions separated in memory. I thought that I might can build the machine code and the user code separately, then change the linker script somehow to load them into separate memory locations. Then I can use the PMP to sandbox my user mode operation.

Disasm commented 4 years ago

Definitely! You can copy the linker script from the corresponding riscv-rt source tree into your project under a different name and use it in .cargo/config instead of one provided by riscv-rt.

dkhayes117 commented 4 years ago

So this line "-C", "link-arg=-Thifive1-link.x" would change to "-C", "link-arg=-newlink.x" if newlink.x was in my project tree ?

Disasm commented 4 years ago

Change it to:

"-C", "link-arg=-Thifive1-memory.x",
"-C", "link-arg=-Tnewlink.x"

(you also need to include memory definitions before the linker script)

dkhayes117 commented 4 years ago

Will I need to modify the memory-hifive1-revb.x too, or just the linker?

Disasm commented 4 years ago

Only if you need a different memory layout or you do not have a bootloader.

dkhayes117 commented 4 years ago

Are the region alias' sensitive to renaming? For example, keeping U and M level code separate wouldn't I need to have a .textM and a .textU etc?

Maybe I can build and run my M level code with one linker and memory file (original). Then once completed, build and run the U level code with a modified linker and memory file that has different memory addresses. Or should this be a single process with some kind of compile time flags/switches?

Disasm commented 4 years ago

Region aliases are different things, they were added to prevent hardcoding FLASH everywhere and to allow some flexibility. If you have different .textX section names, you can try to group them in the linker script in a way you want.

dkhayes117 commented 4 years ago

I've never done this before, obviously. How completely nuts does this look?

INCLUDE memory-fe310.x MEMORY { MFLASH ORIGIN = 0x20000000, LENGTH = 2M UFLASH ORIGIN = 0x20200000, LENGTH = 2M MRAM ORIGIN = 0x80000000, LENGTH = 8K URAM ORIGIN = 0x80002000, LENGTH = 8K
}

REGION_ALIAS("REGION_MTEXT", MFLASH); REGION_ALIAS("REGION_MRODATA", MFLASH); REGION_ALIAS("REGION_MDATA", MRAM); REGION_ALIAS("REGION_MBSS", MRAM); REGION_ALIAS("REGION_MHEAP", MRAM); REGION_ALIAS("REGION_MSTACK", MRAM);

REGION_ALIAS("REGION_UTEXT", UFLASH); REGION_ALIAS("REGION_URODATA", UFLASH); REGION_ALIAS("REGION_UDATA", URAM); REGION_ALIAS("REGION_UBSS", URAM); REGION_ALIAS("REGION_UHEAP", URAM); REGION_ALIAS("REGION_USTACK", URAM);

/Skip first 64k allocated for bootloader/ _stext = 0x20010000;

Disasm commented 4 years ago

You don't need the first INCLUDE as you defined your own RAM regions, but other things look sane

dkhayes117 commented 4 years ago

Wow, really? LOL, cool. Obviously, I can tweak the region sizes a bit to not waste space, just divided everything in half to start. I will get rid of the include line.

Next, I need to modify the link.x file to handle these regions, correct?

Disasm commented 4 years ago

Correct. Or you can create two different memory.x files, one for M-mode and one for U-mode and use them to link two different binaries with the same (possibly modified) link.x file.

dkhayes117 commented 4 years ago

Right, that makes sense. If I did that, then I wouldn't need the change the region names just the memory boundaries. I would also have to $cargo run twice this way. Once to load m-mode stuff, and once to load the u-mode stuff?

Disasm commented 4 years ago

Yes, you're right.

dkhayes117 commented 4 years ago

I really appreciate your help!

dkhayes117 commented 4 years ago

One more thought. I plan on entering the user mode memory section by setting the stack pointer address and changing to u mode. When I write my user mode code, I don't need an #[entry] attribute point included, just in the machine mode code. That should allow the machine code to be called on start up, then I will use the mret process to move into the user mode portion from m-mode. Should that work?

Disasm commented 4 years ago

Probably you need to write your own startup code for the user mode and place it somewhere (beginning of the user mode .text as an option). In any case, you need to have something, that will be KEEPed while linking, otherwise you likely end up with an empty user mode binary.

dkhayes117 commented 4 years ago

I see what you are saying. Do you have any suggestions for the memory definition file. When I try to build with the extra -C argument, it says that "RAM" is already defined. The ram is being defined somewhere else during linking. I think it might be in the hifive/build.rs file. It seems to be pointing to the default memory file. Not sure how to modify this without changing the repo file.

dkhayes117 commented 4 years ago

Nope, the problem is the quickstart template is adding the -Thifive1-link.x argument which calls the hifive-memory.x file then link.x linker. I think I can just do this "-C", "link-arg=-Tnew-memory.x", "-C", "link-arg=-Tlink.x"

dkhayes117 commented 4 years ago

This seems to be working, but the ram doesn't start at the origin I define, it always puts it at 0x80000000.

Disasm commented 4 years ago

Strange, try to rebuild the project. Sometimes these script files don't get updated and linker uses the old version.

dkhayes117 commented 4 years ago

Yahoo! That worked. I ran cargo clean then cargo build --workspace