[U-Boot] uboot for MIPS: need help to skip relocate uboot and start uboot from RAM

Hello Everyone,
We have MIPS based development board and I am trying to get the uboot up and running on it. We have a primary bootloader which check for the valid mod-image stored on the flash. This mod-image consist of header, uboot and linux kernel. Depending on the recent, active and stable imagethe primary bootloader first copies the uboot image. and later on we would copy the kernel image from uboot.
But when primary bootloader copies the uboot image to the RAM and passes the control to the uboot, uboot (MIPS version of start.S and arch/mips/lib/borad.c) tries to relocate the already copied image from RAM (the primary bootloader copied it to start of the RAM+1MB address) to top of the RAM (0x87fc0000) region thinking that the uboot image is stored in flash.
All I need to do is skip the uboot relocate code in MIPS version of uboot startup as the primary bootloader has already relocated the uboot from Flash to RAM and set up the stack pointer and other global data appropriately, which it does after relocation. I can see there is a switch for ARM processor, CONFIG_SKIP_RELOCATE_UBOOT, which skips the relocation of uboot code and tries to run the uboot from RAM. I cannot see a similar switch implemented for MIPS and didnt find any related thread anywhere in mailing list or on net.
Do we have similar ARM like switch to SKIP the RELOCATION? If not has anyone done this before?
I would really appreciate if you can guide me to overcome this issue to run the uboot cleanly skipping the relocation.
Thanks in advance, Pandu

Dear Pandurang:
Sounds like you have battling boot loaders going on, perhaps with the Broadcom CFE (Common Firmware Environment) ?
Someone else may have some data on CONFIG_SKIP_RELOCATE_UBOOT, or you could reflash your target and replace the existing bootloader with the U-Boot bootloader so your bootloaders are not battling for the same resource.
Charles
On Thu, Mar 3, 2011 at 2:08 AM, Pandurang Kale kale.pandurang@gmail.comwrote:
Hello Everyone,
We have MIPS based development board and I am trying to get the uboot up and running on it. We have a primary bootloader which check for the valid mod-image stored on the flash. This mod-image consist of header, uboot and linux kernel. Depending on the recent, active and stable imagethe primary bootloader first copies the uboot image. and later on we would copy the kernel image from uboot.
But when primary bootloader copies the uboot image to the RAM and passes the control to the uboot, uboot (MIPS version of start.S and arch/mips/lib/borad.c) tries to relocate the already copied image from RAM (the primary bootloader copied it to start of the RAM+1MB address) to top of the RAM (0x87fc0000) region thinking that the uboot image is stored in flash.
All I need to do is skip the uboot relocate code in MIPS version of uboot startup as the primary bootloader has already relocated the uboot from Flash to RAM and set up the stack pointer and other global data appropriately, which it does after relocation. I can see there is a switch for ARM processor, CONFIG_SKIP_RELOCATE_UBOOT, which skips the relocation of uboot code and tries to run the uboot from RAM. I cannot see a similar switch implemented for MIPS and didnt find any related thread anywhere in mailing list or on net.
Do we have similar ARM like switch to SKIP the RELOCATION? If not has anyone done this before?
I would really appreciate if you can guide me to overcome this issue to run the uboot cleanly skipping the relocation.
Thanks in advance, Pandu
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Charles,
Thanks for the info. We have a primary boot loader, which read the flash which might contain more than one existing mod-image(containing header, uboot and kernel) and depending on the state and condition it decides which mod is valid and copies the uboot from the valid mod-image to RAM.
So our primary bootloader is needed to load correct version of u-boot to RAM from flash. But I am looking for a fix where in the uboot should setup the stack and gp and start executing from RAM and not to copy/relocate itself all over again to different RAM (High-memory region) location.
Thanks, Pandu
On Thu, Mar 3, 2011 at 3:27 PM, Charles Krinke charles.krinke@gmail.comwrote:
Dear Pandurang:
Sounds like you have battling boot loaders going on, perhaps with the Broadcom CFE (Common Firmware Environment) ?
Someone else may have some data on CONFIG_SKIP_RELOCATE_UBOOT, or you could reflash your target and replace the existing bootloader with the U-Boot bootloader so your bootloaders are not battling for the same resource.
Charles
On Thu, Mar 3, 2011 at 2:08 AM, Pandurang Kale kale.pandurang@gmail.comwrote:
Hello Everyone,
We have MIPS based development board and I am trying to get the uboot up and running on it. We have a primary bootloader which check for the valid mod-image stored on the flash. This mod-image consist of header, uboot and linux kernel. Depending on the recent, active and stable imagethe primary bootloader first copies the uboot image. and later on we would copy the kernel image from uboot.
But when primary bootloader copies the uboot image to the RAM and passes the control to the uboot, uboot (MIPS version of start.S and arch/mips/lib/borad.c) tries to relocate the already copied image from RAM (the primary bootloader copied it to start of the RAM+1MB address) to top of the RAM (0x87fc0000) region thinking that the uboot image is stored in flash.
All I need to do is skip the uboot relocate code in MIPS version of uboot startup as the primary bootloader has already relocated the uboot from Flash to RAM and set up the stack pointer and other global data appropriately, which it does after relocation. I can see there is a switch for ARM processor, CONFIG_SKIP_RELOCATE_UBOOT, which skips the relocation of uboot code and tries to run the uboot from RAM. I cannot see a similar switch implemented for MIPS and didnt find any related thread anywhere in mailing list or on net.
Do we have similar ARM like switch to SKIP the RELOCATION? If not has anyone done this before?
I would really appreciate if you can guide me to overcome this issue to run the uboot cleanly skipping the relocation.
Thanks in advance, Pandu
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
-- Charles Krinke

Dear Pandurang Kale,
In message AANLkTikLJzuCSwOhMLz2sWy1j9a3LiV8zzY6=TjTfnrR@mail.gmail.com you wrote:
But when primary bootloader copies the uboot image to the RAM and passes the control to the uboot, uboot (MIPS version of start.S and arch/mips/lib/borad.c) tries to relocate the already copied image from RAM (the primary bootloader copied it to start of the RAM+1MB address) to top of the RAM (0x87fc0000) region thinking that the uboot image is stored in flash.
U-Boot does not "think" it is stored in flash - this is what you configured. If you know you're always loading it to a fixed RAM address, you can use this as reference for TEXT_BASE instead.
All I need to do is skip the uboot relocate code in MIPS version of uboot
No, you do NOT want to do thjat, as it would cripple U-Boot and remove basic functionality from it.
I can see there is a switch for ARM processor, CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I would really appreciate if you can guide me to overcome this issue to run the uboot cleanly skipping the relocation.
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
Best regards,
Wolfgang Denk

Hi Wolfgang Denk,
Thanks for the response. Please find my questions inline.
On Thu, Mar 3, 2011 at 11:11 PM, Wolfgang Denk wd@denx.de wrote:
Dear Pandurang Kale,
In message AANLkTikLJzuCSwOhMLz2sWy1j9a3LiV8zzY6=TjTfnrR@mail.gmail.com you wrote:
But when primary bootloader copies the uboot image to the RAM and passes
the
control to the uboot, uboot (MIPS version of start.S and arch/mips/lib/borad.c) tries to relocate the already copied image from RAM (the primary bootloader copied it to start
of
the RAM+1MB address) to top of the RAM (0x87fc0000) region thinking that
the
uboot image is stored in flash.
U-Boot does not "think" it is stored in flash - this is what you configured. If you know you're always loading it to a fixed RAM address, you can use this as reference for TEXT_BASE instead
For MIPS I do not find the TEXT_BASE symbol, there is SYS_CFG_MONITOR_BASE which it uses to relocate the code from the define symbol to high RAM address. how can I avoid this? As I see we have a switch defined for ARM, CONFIG_SKIP_RELOCATE_UBOOT, to skip the code relocation I cant find a similar instance in MIPS code. Can you please throw some light on getting the TEXT_BASE setting correctly for MIPS code? how can I do that?
.
All I need to do is skip the uboot relocate code in MIPS version of uboot
No, you do NOT want to do thjat, as it would cripple U-Boot and remove basic functionality from it.
I can see there is a switch for ARM processor,
CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I have recent uboot code for MIPS and I cant find any similar switch for MIPS codebase. arch/mips/lib/board.c and arch/mips/cpu/start.S
I would really appreciate if you can guide me to overcome this issue to
run
the uboot cleanly skipping the relocation.
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
The uboot is already loaded in the RAM (by the primary boot loader) so I dont want uboot to again relocate itself from one location of RAM to its predefined high-memory region in RAM which I have explained in my first mail.
Best regards,
Wolfgang Denk
Thanks a lot,
Pandu
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de If God wanted me to touch my toes, he'd have put them on my knees.

Dear Pandurang Kale,
In message AANLkTinTqxJPU9Gwye_8pT2PcUxR8E36=zm78ypc1740@mail.gmail.com you wrote:
For MIPS I do not find the TEXT_BASE symbol, there is SYS_CFG_MONITOR_BASE
Please check again. MIPS uses CONFIG_SYS_TEXT_BASE like all other architectures.
which it uses to relocate the code from the define symbol to high RAM address. how can I avoid this? As I see we have a switch defined for ARM,
You should not try to avoid this. It is a useful feature, even if you load U-Boot to RAM separately.
CONFIG_SKIP_RELOCATE_UBOOT, to skip the code relocation I cant find a similar instance in MIPS code. Can you please throw some light on getting the TEXT_BASE setting correctly for MIPS code? how can I do that?
You did not understand what I wrote:
I can see there is a switch for ARM processor,
CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I have recent uboot code for MIPS and I cant find any similar switch for MIPS codebase. arch/mips/lib/board.c and arch/mips/cpu/start.S
I meant: do you see CONFIG_SKIP_RELOCATE_UBOOT in recent ARM code, on working (compilable) ARM boards?
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
The uboot is already loaded in the RAM (by the primary boot loader) so I dont want uboot to again relocate itself from one location of RAM to its predefined high-memory region in RAM which I have explained in my first mail.
Please re-read what I wrote. In general, U-Boot's load address cannot be determined at compile time, at least not without crippeling it from some interesting features. You should really not try doing things differently to everybody else. We had similar discussins not so long ago for AMR, so please just re-read this in the archives.
Best regards,
Wolfgang Denk

Hi Wolfgang Denk,
Thanks a lot for all the clarification and help. I really appreciate your support.
I have few question with reards to the start.S file for MIPS. What is the significance of CONFIG_SYS_MONITOR_BASE ?? why is this used as the base/source address in relocate_code in mips start.S file while for ARM we use the _start as base/source address?
secondly for ARM we compare the source and destination address and skip the copy_loop(in ARM specific start.S file) if both are same, while this has not been implemented for MIPS.
I had to make similar changes in the start.S file (MIPS version) to skip the copying section.
Thanks, Pandu.
P.S: I am aware that you are out till 14th but I thought of posting it as these are valid arguments.
On Fri, Mar 4, 2011 at 6:23 AM, Wolfgang Denk wd@denx.de wrote:
Dear Pandurang Kale,
In message AANLkTinTqxJPU9Gwye_8pT2PcUxR8E36=zm78ypc1740@mail.gmail.com you wrote:
For MIPS I do not find the TEXT_BASE symbol, there is
SYS_CFG_MONITOR_BASE
Please check again. MIPS uses CONFIG_SYS_TEXT_BASE like all other architectures.
which it uses to relocate the code from the define symbol to high RAM address. how can I avoid this? As I see we have a switch defined for
ARM,
You should not try to avoid this. It is a useful feature, even if you load U-Boot to RAM separately.
CONFIG_SKIP_RELOCATE_UBOOT, to skip the code relocation I cant find a similar instance in MIPS code. Can you please throw some light on getting the TEXT_BASE setting correctly for MIPS code? how can I do that?
You did not understand what I wrote:
I can see there is a switch for ARM processor,
CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I have recent uboot code for MIPS and I cant find any similar switch for MIPS codebase. arch/mips/lib/board.c and arch/mips/cpu/start.S
I meant: do you see CONFIG_SKIP_RELOCATE_UBOOT in recent ARM code, on working (compilable) ARM boards?
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
The uboot is already loaded in the RAM (by the primary boot loader) so I dont want uboot to again relocate itself from one location of RAM to its predefined high-memory region in RAM which I have explained in my first mail.
Please re-read what I wrote. In general, U-Boot's load address cannot be determined at compile time, at least not without crippeling it from some interesting features. You should really not try doing things differently to everybody else. We had similar discussins not so long ago for AMR, so please just re-read this in the archives.
Best regards,
Wolfgang Denk
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Pandurang,
We solved this problem by using TLB mapping for U-Boot on our MIPS platforms.
This was also due to the fact that we need to load U-Boot at the top of physical memory which is often unreachable with 32-bit addressing. By doing this we always link U-Boot at address 0xC0000000 and it doesn't care where it's actually loaded in physical memory. The only thing we have to be careful about is that any drivers that expect pointers to contain physical addresses need to use a macro for mapping (and handle the case where the physical address is 64-bits).
We have to load U-boot at the top of physical memory since we have large applications and operating systems that need all available physical memory and some 32-bit operating systems need all the low physical memory they can get.
This also allows us to use the same U-Boot image when booting over PCI/PCIE, JTAG or from multiple copies we store in flash (standard and failover). Early in the U-Boot process we check one of our GPIO lines to see if it's set or not. If set we just scan flash for a second copy of U-Boot and branch there, otherwise we continue executing and run in "failsafe" mode. With this we don't even care about the size of U-Boot, as long as it remains under 4MB we're fine.
Granted, the "proper" way is to use ELF relocation, but that does not work when 64-bit physical addressing is required for phyisical memory and it is currently unsupported for MIPS.
We first set up the TLB mapping in start.S after we discover where we are executing from in flash or DRAM then do it again in the code that copies U- Boot from flash to DRAM. The initialization code can also detect if it's already running out of RAM and skip the DRAM initialization as in the case where we boot over PCI/PCIE/EJTAG where the host initializes the memory controller. U-Boot no longer cares at all where it is executing from in physical memory.
We just set CONFIG_SYS_MONITOR_BASE to 0xC0000000 and go from there.
On MIPS this is actually quite simple and just requires a single entry in the TLB table. We use the last entry.
We just have to be careful to clear the TLB entry before executing any application or operating system on core 0 (where U-Boot resides).
We basically do this:
/* Set up TLB registers to clear desired entry. The actual * tlbwi instruction is done in ASM when running from unmapped DRAM */ write_64bit_c0_entrylo0 (0); write_c0_pagemask (0); write_64bit_c0_entrylo1 (0); write_64bit_c0_entryhi (0xFFFFFFFF91000000ull); write_c0_index (get_num_tlb_entries () - 1);
asm volatile (" .set push \n" " .set mips64 \n" " .set noreorder \n" " move $4, %[arg0] \n" " move $5, %[arg1] \n" " move $6, %[arg2] \n" " move $7, %[arg3] \n" " move $8, %[arg4] \n" " j %[addr] \n" " nop \n" " .set pop \n"::[arg0] "r" (arg0), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3),[arg4] "r" (arg4),[addr] "r" (addr) :"$4", "$5", "$6", "$7", "$8");
Which calls:
/* * Launch 64-bit Linux kernel entry point from a 32-bit U-boot * a0-a3 normal args, set up by C code. We never come back, * so we keep this simple. * a4 is entry point * Calling C code sets up TLB to be ready for a write that clears the TLB * entry that u-boot uses. This code is executed from XKPHYS address space * to allow the TLB entry to be removed. */ .globl asm_launch_linux_entry_point .ent asm_launch_linux_entry_point asm_launch_linux_entry_point: tlbwi j a4 cache 0, 0($0) /* Flush icache in delay slot*/ .end asm_launch_linux_entry_point
Our relocate code basically looks like:
/* * void relocate_code (addr_sp, gd, addr_moni) * * This "function" does not return, instead it continues in RAM * after relocating the monitor code. * * a0 = addr_sp * a1 = gd address (on stack) * a2 = destination address (physical) */ .globl relocate_code .ent relocate_code relocate_code: la t9, relocate_code_octeon j t9 move a3, zero /* No mapping */ .end relocate_code
/* * void relocate_code_octeon (addr_sp, gd, addr_moni) * * This "function" does not return, instead it continues in RAM * after relocating the monitor code. * * a0 = addr_sp * a1 = gd address (on stack) * a2 = destination address (physical) * a3 = TLB page size (when TLB mapping used */
.globl relocate_code_octeon .ent relocate_code_octeon relocate_code_octeon: move v0, a1 /* Save gd address */ move sp, a0 /* Set new stack pointer */
li a4, CONFIG_SYS_MONITOR_BASE /* Text base, 0xC0000000 */ la a7, in_ram lw a6, -12(a7) /* a6 <-- uboot_end_data */ move a5, a2
/* * a4 = source address * a5 = target address * a6 = source end address */
/* Use 64 bit copies to relocate code for speed. We need to be careful to * not copy too much as BSS comes immediately after the initialized data, * and bss clearing is done _before_ the copy, so if too much is copied we get * garbage in some bss variable(s). * The Linker script is constructed to align the end of the initialized data * so that we can use 8 byte chunks. */ beq a4, a5, copyDone 1: ld a7, 0(a4) sd a7, 0(a5) daddu a4, 8 blt a4, a6, 1b daddu a5, 8 /* delay slot */
/* If caches were enabled, we would have to flush them here. */ copyDone:
/* Jump to where we've relocated ourselves. */
/* We now need to redo the TLB. We can call it directly * since we are now running from the linked address. */ /* Now replace the single TLB mapping that was set up in flash. */ move a1, a2
la a0, _start /* Mapping size in a3 from above */ move a2, a3 jal single_tlb_setup nop
/* We aren't changing execution (virtual) addresses, * so we don't need any address fixups here. */ la a4, in_ram j a4 nop
.globl single_tlb_setup .ent single_tlb_setup .align 8 /* Sets up a single TLB entry. Virtual/physical addresses * must be properly aligned. * a0 Virtual address * a1 Physical address * a2 page (_not_ mapping) size */ single_tlb_setup:
/* Determine the number of TLB entries available, and * use the top one. */ mfc0 a3, COP0_CONFIG1_REG srl a3, a3, 25 mfc0 a5, COP0_CONFIG3_REG /* Check if config4 reg present */ bbit0 a5, 31, single_tlb_setup_cont and a3, a3, 0x3F /* a3 now has the max mmu entry index */ mfc0 a5, COP0_CONFIG4_REG bbit0 a5, 14, single_tlb_setup_cont /* check config4[MMUExtDef] */ nop /* append config4[MMUSizeExt] to most significant bit of * config1[MMUSize-1] */ ins a3, a5, 6, 8 and a3, a3, 0x3fff /* a3 now includes max entries for cn6xxx */
single_tlb_setup_cont:
/* Format physical address for entry low */ nop dsrl a1, a1, 12 dsll a1, a1, 6 ori a1, a1, 0x7 /* set DVG bits */
move a4, a2 dadd a5, a4, a4 /* mapping size */ dsll a6, a4, 1 daddi a6, a6, -1 /* pagemask */ dsrl a4, a4, 6 /* adjust for adding with entrylo */
/* Now set up mapping */ mtc0 a6, COP0_PAGEMASK_REG mtc0 a3, COP0_INDEX_REG
dmtc0 a1, COP0_ENTRYLO0_REG dadd a1, a1, a4
dmtc0 a1, COP0_ENTRYLO1_REG dadd a1, a1, a4
dmtc0 a0, COP0_ENTRYHI_REG dadd a0, a0, a5
ehb tlbwi jr ra nop .end single_tlb_setup
Note that this code would have to be modified for other MIPS platforms since this makes use of some instructions not normally found (i.e. bbit0 (branch if bit clear) and ins (insert bits)). The code also uses the n32 ABI with 64-bit support enabled. It could easily be adapted to other MIPS platforms and could be used on 32-bit platforms as well.
I've met a lot of resistance to the idea of using virtual memory for the boot loader, but it really simplifies things.
The only thing we have to relocate is bd and gd where we copy them from cache to DRAM after we initialize DRAM. All the other relocations disappear so we just link at the fixed address.
The only modifications we've had to do to U-Boot due to this is add macros to the USB EHCI driver and the E1000 driver (the last was only as an exercize) to map virtual addresses to physical addresses. Our platform drivers already take this into account. Any other drivers that perform DMA would also need to use macros to convert pointers to physical addresses, which really should be present anyway since KSEG0 pointer addresses are not always physical addresses.
We can always load U-Boot into the top of memory, whether there's 256MB or 8+GB of physical memory installed without having to make major changes to U- Boot to make it fully support 64-bit addressing.
With this there's no ELF relocation, fixups or anything else to worry about and it greatly simplifies things.
-Aaron
On Thursday, March 03, 2011 10:23:11 pm Wolfgang Denk wrote:
Dear Pandurang Kale,
In message AANLkTinTqxJPU9Gwye_8pT2PcUxR8E36=zm78ypc1740@mail.gmail.com
you wrote:
For MIPS I do not find the TEXT_BASE symbol, there is SYS_CFG_MONITOR_BASE
Please check again. MIPS uses CONFIG_SYS_TEXT_BASE like all other architectures.
which it uses to relocate the code from the define symbol to high RAM address. how can I avoid this? As I see we have a switch defined for ARM,
You should not try to avoid this. It is a useful feature, even if you load U-Boot to RAM separately.
CONFIG_SKIP_RELOCATE_UBOOT, to skip the code relocation I cant find a similar instance in MIPS code. Can you please throw some light on getting the TEXT_BASE setting correctly for MIPS code? how can I do that?
You did not understand what I wrote:
I can see there is a switch for ARM processor,
CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I have recent uboot code for MIPS and I cant find any similar switch for MIPS codebase. arch/mips/lib/board.c and arch/mips/cpu/start.S
I meant: do you see CONFIG_SKIP_RELOCATE_UBOOT in recent ARM code, on working (compilable) ARM boards?
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
The uboot is already loaded in the RAM (by the primary boot loader) so I dont want uboot to again relocate itself from one location of RAM to its predefined high-memory region in RAM which I have explained in my first mail.
Please re-read what I wrote. In general, U-Boot's load address cannot be determined at compile time, at least not without crippeling it from some interesting features. You should really not try doing things differently to everybody else. We had similar discussins not so long ago for AMR, so please just re-read this in the archives.
Best regards,
Wolfgang Denk

Hi Aaron,
Thanks you for such a detailed explanation. It was of a great help to me.
Thanks, Pandu
On Thu, Mar 10, 2011 at 6:05 AM, Aaron Williams < Aaron.Williams@caviumnetworks.com> wrote:
Hi Pandurang,
We solved this problem by using TLB mapping for U-Boot on our MIPS platforms.
This was also due to the fact that we need to load U-Boot at the top of physical memory which is often unreachable with 32-bit addressing. By doing this we always link U-Boot at address 0xC0000000 and it doesn't care where it's actually loaded in physical memory. The only thing we have to be careful about is that any drivers that expect pointers to contain physical addresses need to use a macro for mapping (and handle the case where the physical address is 64-bits).
We have to load U-boot at the top of physical memory since we have large applications and operating systems that need all available physical memory and some 32-bit operating systems need all the low physical memory they can get.
This also allows us to use the same U-Boot image when booting over PCI/PCIE, JTAG or from multiple copies we store in flash (standard and failover). Early in the U-Boot process we check one of our GPIO lines to see if it's set or not. If set we just scan flash for a second copy of U-Boot and branch there, otherwise we continue executing and run in "failsafe" mode. With this we don't even care about the size of U-Boot, as long as it remains under 4MB we're fine.
Granted, the "proper" way is to use ELF relocation, but that does not work when 64-bit physical addressing is required for phyisical memory and it is currently unsupported for MIPS.
We first set up the TLB mapping in start.S after we discover where we are executing from in flash or DRAM then do it again in the code that copies U- Boot from flash to DRAM. The initialization code can also detect if it's already running out of RAM and skip the DRAM initialization as in the case where we boot over PCI/PCIE/EJTAG where the host initializes the memory controller. U-Boot no longer cares at all where it is executing from in physical memory.
We just set CONFIG_SYS_MONITOR_BASE to 0xC0000000 and go from there.
On MIPS this is actually quite simple and just requires a single entry in the TLB table. We use the last entry.
We just have to be careful to clear the TLB entry before executing any application or operating system on core 0 (where U-Boot resides).
We basically do this:
/* Set up TLB registers to clear desired entry. The actual * tlbwi instruction is done in ASM when running from unmapped DRAM */ write_64bit_c0_entrylo0 (0); write_c0_pagemask (0); write_64bit_c0_entrylo1 (0); write_64bit_c0_entryhi (0xFFFFFFFF91000000ull); write_c0_index (get_num_tlb_entries () - 1); asm volatile (" .set push \n" " .set mips64 \n" " .set noreorder \n" " move $4, %[arg0] \n" " move $5, %[arg1] \n" " move $6, %[arg2] \n" " move $7, %[arg3] \n" " move $8, %[arg4] \n" " j %[addr] \n" " nop \n" " .set pop \n"::[arg0] "r" (arg0), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3),[arg4] "r" (arg4),[addr] "r" (addr) :"$4", "$5", "$6", "$7", "$8");
Which calls:
/*
- Launch 64-bit Linux kernel entry point from a 32-bit U-boot
- a0-a3 normal args, set up by C code. We never come back,
- so we keep this simple.
- a4 is entry point
- Calling C code sets up TLB to be ready for a write that clears the TLB
- entry that u-boot uses. This code is executed from XKPHYS address space
- to allow the TLB entry to be removed.
*/ .globl asm_launch_linux_entry_point .ent asm_launch_linux_entry_point asm_launch_linux_entry_point: tlbwi j a4 cache 0, 0($0) /* Flush icache in delay slot*/ .end asm_launch_linux_entry_point
Our relocate code basically looks like:
/*
- void relocate_code (addr_sp, gd, addr_moni)
- This "function" does not return, instead it continues in RAM
- after relocating the monitor code.
- a0 = addr_sp
- a1 = gd address (on stack)
- a2 = destination address (physical)
*/ .globl relocate_code .ent relocate_code relocate_code: la t9, relocate_code_octeon j t9 move a3, zero /* No mapping */ .end relocate_code
/*
- void relocate_code_octeon (addr_sp, gd, addr_moni)
- This "function" does not return, instead it continues in RAM
- after relocating the monitor code.
- a0 = addr_sp
- a1 = gd address (on stack)
- a2 = destination address (physical)
- a3 = TLB page size (when TLB mapping used
*/
.globl relocate_code_octeon .ent relocate_code_octeon
relocate_code_octeon: move v0, a1 /* Save gd address */ move sp, a0 /* Set new stack pointer */
li a4, CONFIG_SYS_MONITOR_BASE /* Text base, 0xC0000000 */ la a7, in_ram lw a6, -12(a7) /* a6 <-- uboot_end_data */ move a5, a2 /* * a4 = source address * a5 = target address * a6 = source end address */
/* Use 64 bit copies to relocate code for speed. We need to be careful to
- not copy too much as BSS comes immediately after the initialized data,
- and bss clearing is done _before_ the copy, so if too much is copied we
get
- garbage in some bss variable(s).
- The Linker script is constructed to align the end of the initialized
data
- so that we can use 8 byte chunks.
*/ beq a4, a5, copyDone 1: ld a7, 0(a4) sd a7, 0(a5) daddu a4, 8 blt a4, a6, 1b daddu a5, 8 /* delay slot */
/* If caches were enabled, we would have to flush them here. */
copyDone:
/* Jump to where we've relocated ourselves. */ /* We now need to redo the TLB. We can call it directly * since we are now running from the linked address. */ /* Now replace the single TLB mapping that was set up in flash. */ move a1, a2 la a0, _start /* Mapping size in a3 from above */ move a2, a3 jal single_tlb_setup nop /* We aren't changing execution (virtual) addresses, * so we don't need any address fixups here. */ la a4, in_ram j a4 nop .globl single_tlb_setup .ent single_tlb_setup .align 8 /* Sets up a single TLB entry. Virtual/physical addresses * must be properly aligned. * a0 Virtual address * a1 Physical address * a2 page (_not_ mapping) size */
single_tlb_setup:
/* Determine the number of TLB entries available, and * use the top one. */ mfc0 a3, COP0_CONFIG1_REG srl a3, a3, 25 mfc0 a5, COP0_CONFIG3_REG /* Check if config4 reg present */ bbit0 a5, 31, single_tlb_setup_cont and a3, a3, 0x3F /* a3 now has the max mmu entry index
*/ mfc0 a5, COP0_CONFIG4_REG bbit0 a5, 14, single_tlb_setup_cont /* check config4[MMUExtDef] */ nop /* append config4[MMUSizeExt] to most significant bit of * config1[MMUSize-1] */ ins a3, a5, 6, 8 and a3, a3, 0x3fff /* a3 now includes max entries for cn6xxx */
single_tlb_setup_cont:
/* Format physical address for entry low */ nop dsrl a1, a1, 12 dsll a1, a1, 6 ori a1, a1, 0x7 /* set DVG bits */ move a4, a2 dadd a5, a4, a4 /* mapping size */ dsll a6, a4, 1 daddi a6, a6, -1 /* pagemask */ dsrl a4, a4, 6 /* adjust for adding with entrylo */ /* Now set up mapping */ mtc0 a6, COP0_PAGEMASK_REG mtc0 a3, COP0_INDEX_REG dmtc0 a1, COP0_ENTRYLO0_REG dadd a1, a1, a4 dmtc0 a1, COP0_ENTRYLO1_REG dadd a1, a1, a4 dmtc0 a0, COP0_ENTRYHI_REG dadd a0, a0, a5 ehb tlbwi jr ra nop .end single_tlb_setup
Note that this code would have to be modified for other MIPS platforms since this makes use of some instructions not normally found (i.e. bbit0 (branch if bit clear) and ins (insert bits)). The code also uses the n32 ABI with 64-bit support enabled. It could easily be adapted to other MIPS platforms and could be used on 32-bit platforms as well.
I've met a lot of resistance to the idea of using virtual memory for the boot loader, but it really simplifies things.
The only thing we have to relocate is bd and gd where we copy them from cache to DRAM after we initialize DRAM. All the other relocations disappear so we just link at the fixed address.
The only modifications we've had to do to U-Boot due to this is add macros to the USB EHCI driver and the E1000 driver (the last was only as an exercize) to map virtual addresses to physical addresses. Our platform drivers already take this into account. Any other drivers that perform DMA would also need to use macros to convert pointers to physical addresses, which really should be present anyway since KSEG0 pointer addresses are not always physical addresses.
We can always load U-Boot into the top of memory, whether there's 256MB or 8+GB of physical memory installed without having to make major changes to U- Boot to make it fully support 64-bit addressing.
With this there's no ELF relocation, fixups or anything else to worry about and it greatly simplifies things.
-Aaron
On Thursday, March 03, 2011 10:23:11 pm Wolfgang Denk wrote:
Dear Pandurang Kale,
In message <AANLkTinTqxJPU9Gwye_8pT2PcUxR8E36=zm78ypc1740@mail.gmail.com
you wrote:
For MIPS I do not find the TEXT_BASE symbol, there is SYS_CFG_MONITOR_BASE
Please check again. MIPS uses CONFIG_SYS_TEXT_BASE like all other architectures.
which it uses to relocate the code from the define symbol to high RAM address. how can I avoid this? As I see we have a switch defined for ARM,
You should not try to avoid this. It is a useful feature, even if you load U-Boot to RAM separately.
CONFIG_SKIP_RELOCATE_UBOOT, to skip the code relocation I cant find a similar instance in MIPS code. Can you please throw some light on
getting
the TEXT_BASE setting correctly for MIPS code? how can I do that?
You did not understand what I wrote:
I can see there is a switch for ARM processor,
CONFIG_SKIP_RELOCATE_UBOOT,
Are you looking at recent code and working boards?
I have recent uboot code for MIPS and I cant find any similar switch
for
MIPS codebase. arch/mips/lib/board.c and arch/mips/cpu/start.S
I meant: do you see CONFIG_SKIP_RELOCATE_UBOOT in recent ARM code, on working (compilable) ARM boards?
Do do not want to skip relocation. U-Boot may need to auto-adjust it's start address dynamically, depending on configuration, system requirements and/or environment settings.
The uboot is already loaded in the RAM (by the primary boot loader) so
I
dont want uboot to again relocate itself from one location of RAM to
its
predefined high-memory region in RAM which I have explained in my first mail.
Please re-read what I wrote. In general, U-Boot's load address cannot be determined at compile time, at least not without crippeling it from some interesting features. You should really not try doing things differently to everybody else. We had similar discussins not so long ago for AMR, so please just re-read this in the archives.
Best regards,
Wolfgang Denk
participants (4)
-
Aaron Williams
-
Charles Krinke
-
Pandurang Kale
-
Wolfgang Denk