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

Pandurang Kale kale.pandurang at gmail.com
Thu Mar 10 18:37:20 CET 2011


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 at 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 at 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
>


More information about the U-Boot mailing list