Public Functions

Describes how to implement the three exported functions of the platform-specific layer.

InitialiseHardware()

See the Template port (os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/bootstrap/template.s) to see how this function is coded in practice.

The code can be found at the label:

    ...
    EXPORT    InitialiseHardware
InitialiseHardware    ROUT
    ...

Entry conditions

This function is called immediately after reset with the CPU in supervisor mode, with all interrupts disabled, and R12 pointing to the ROM header (a TRomHeader object). There is no valid stack on entry to this function, i.e. R13 is undefined.

What the function should do

The function is intended to perform the basic hardware initialisation that is required immediately after reset. It also sets up the address of the boot table.

In detail, it should:

  1. Initialise the CPU/MMU registers. This is done by making a call to the generic function InitCpu(), passing the address of the boot parameter table. For more information on the boot parameter table, see BTF_Params, which is one of the boot table functions.

    InitCpu() flushes all caches, sets up the MMU control registers, and enables the instruction cache (on a split cache device). Note that R14 needs to be preserved before making the function call. As there is no valid stack, R14 is typically saved in R13.

  2. Interrogate the hardware to determine the reset reason. In a transparent reset, all RAM contents are preserved and the reset should be invisible to the user, for example waking up from a low power mode such as the SA1110 sleep mode. In this case, perform whatever device-dependent sequence is required to restore the processor state, and jump back into the power down code: InitialiseHardware() will never return to the generic boot code.

    For bootloader bootstraps, if the reset reason is power on reset or hardware cold reset, or if it is a software reset and a rerun of the bootloader was requested (i.e. Kern::Restart() was called with a parameter value of 0x80000000), then proceed to step 3. If these conditions are not true, for example when the reset reason is software reset with any other parameter value or a reset caused by waking up from a low power mode, then control should immediately be transferred to the image already loaded. The state of the system at the point where control is transferred should be as close as possible to the state immediately after reset, to provide proper conditions for the bootstrap in the already loaded image.

    If the system contains FLASH memory which can be programmed with a ROM image, an additional check may be needed to see if an image already present in FLASH should be run instead of the bootloader following a hardware reset. A spare switch on the board is often used for this purpose.

  3. Initialise enough hardware to satisfy the rest of the bootstrap. The precise split between what is initialised here, what is initialised later in the bootstrap, and what is done during variant initialisation is flexible, but as an absolute minimum this function must make some RAM accessible. Typically this function should set up ROM and RAM controllers, set the CPU clock frequency, set sensible states for GPIO lines and set up whatever bus controller is necessary to communicate with any external peripheral chips present. Note also that it is often useful to allow the ROM image to run from either ROM or RAM - this is one of the main reasons for making the bootstrap position independent. To allow for this, the intialisation code must check the PC when setting up the memory controllers; if code is already running from RAM then RAM must already have been initialised and it may not be necessary to touch the RAM controller.

  4. Determine the physical address of the super page. This will usually be at the beginning of physical RAM, unless there is a good reason for it not to be. The main reason why the super page might not be at the beginning of physical RAM is usually because either that address is reserved for hardware (e.g. video RAM), or that code is running from that address. R10 should be loaded with the physical address determined. Note that, if it is not possible to determine the final address of the super page here, a temporary address can be used and the super page relocated to its final address later on. See BTF_Alloc for more detail.

    The super page is defined by the SSuperPageBase struct in os/kernelhwsrv/kernel/eka/include/kernel/kernboot.h

  5. Fill in valid values for the following minimum set of super page fields:

    • iBootTable should contain the address of the boot table.

    • iCodeBase should contain the base address of the bootstrap code. It is used to resolve offset addresses such as those in the boot table.

    • iActiveVariant is the hardware variant discriminator (such as 05040001) for the hardware platform in use. It is used to find the corresponding primary (kernel) executable image.

    • iCpuId should be set to the value of the CP15 main ID register, obtained by MRC P15, 0, Rd, C0, C0, 0.

  6. The super page field iMachineData is used to communicate hardware-specific data between the bootstrap and the variant. It must be set to point to somewhere in the super page or CPU page. Typically, it points to the beginning of the CPU page.

  7. The super page field iHwStartupReason is used to pass the detailed reset reason to the variant. It is a hardware specific value.

  8. In debug builds of the bootstrap, as indicated by the symbol CFG_DebugBootRom being TRUE, the debug tracing port should be initialised here. See also Platform-Specific Configuration Header.

  9. If Level 2 cache is included in the bootstrap (i.e. specifically L210 cache or L220 cache), then:

    • the function must initialise the cache. This involves setting cache properties: size, type, N-ways and cache invalidation. The following code is an example of L210 cache initialisation, but it is also valid for L220 cache initialisation:

      ;Configure L2 cache
      ;-------------------
          
          LDR     r0, =L210CtrlBasePhys    ; Base phys. addr. of L210 Cache Controller
          ;Set L210 Control Register 
          
          LDR r1, #L210CTRLReg        ; L210CTRLReg comes from Ref.Manual
          STR r1, [r0, #0x104]  ; 104h is address offset of Control Register
          
          ;Invalidate entire L2 cache by way (8 ways are presumed)
          MOV r1, #0xFF
          STR r1, [r0, #0x77c]  ; 77Ch is address offset of InvalidateByWay Register
          
          ;Loop while invalidate is completed
      _L2loop
          LDR r1, [r0, #0x77c]
          CMP r1, #0    
          BNE _L2loop
      
    • the superpage field SSuperPageBase::iArmL2CacheBase must be set to the base physical address of the L2 cache control area, like in the following example:

          ;Initialise SSuperPageBase::iArmL2CacheBase
          ;------------------------------------------
          LDR r0, =L210CtrlBasePhys    ; this is base physical address of L210 cache controller
          STR r0, [r10, #SSuperPageBase_iArmL2CacheBase];r10 holds the base address of super page
      

      Note that the superpage is defined by the SSuperPageBase struct in os/kernelhwsrv/kernel/eka/include/kernel/kernboot.h

Exit conditions

The function can modify any CPU registers subject to the conditions that:

  • it returns in supervisor mode with all interrupts disabled

  • it returns the physical address of the super page in R10.

Fault()

Entry conditions

The processor state is completely undefined except that R14 of the current mode points to the instruction after the fault.

What the function should do

This function is called if a fatal error is detected during boot.

The implementation should halt the system and produce whatever diagnostics are possible. Typically, if debug tracing is enabled, the CPU state can be dumped over the debug port. A generic function is provided to do this, as the minimal implementation is simply:

        EXPORT Fault
Fault    ROUT
        B BasicFaultHandler ; generic handler dumps registers via
                            ; debug serial port

RestartEntry()

Entry conditions

On entry the CPU state is indeterminate, as the restart may be caused by a kernel fault, with the exception that R0 contains the reboot reason, the parameter passed to Kern::Restart().

This value is hardware specific except for the following two values:

  • 0x00000000 means restart the same ROM image, preserving RAM contents if possible.

  • 0x80000000 means restart the boot loader and load a new image. This code is generated by the crash debugger in response to the X command of the crash debugger.

What the function should do

The function is called by the kernel when a system restart is required, and should perform whatever actions are necessary to restart the system. If possible, a hardware reset should be used. Failing that, it should reset all peripheral controllers and CPU registers, disable the MMU and jump back to the reset vector.