HAL amendments for SMP
======================

What this document covers
-------------------------

This document describes any additions or revisions to the HAL specification, in particular any new or changed HAL entry points. Other documents may cover specific areas of the HAL/OS (e.g. IRQ handling) which are not covered here.


Overview
--------

Startup of an SMP system will be along the following lines:

1. The HAL performs the standard OS boot process (RISCOS_InitARM,
   RISCOS_AddRAM, RISCOS_Start), for a single core. The HAL should ensure the
   other cores are held in some form of reset state (e.g. in a software
   spin/sleep loop, if necessary)

2. Once the kernel is sufficiently initialised, it will make use of the new
   HAL_CPUCount and HAL_CPUNumber entry points to determine that it is running
   on a multi-core system and the ID of the boot core.

3. For each additional core that the OS wants to make use of, the OS will call
   HAL_SMPStartup to instruct the HAL to boot the core. The HAL is required to
   initialise the core (e.g. basic CP15 register settings) and then jump to the
   physical address that was provided in the HAL_SMPStartup call.

SMP safety of HAL and OS entry points is described in terms of three levels:

* PRIMARY: The entry point or group of entry points must only be called from the primary core (or whichever core issues RISCOS_Start)
* UNSAFE: The entry point or group of entry points cannot be called concurrently from multiple cores.
* PER-RESOURCE: The entry point or group of entry points can be called concurrently from multiple cores, as long as no two concurrent calls access the same resource (e.g. making concurrent calls to two different timers)
* SAFE: Concurrent calls which target the same resource are expected to be handled in a fully SMP-safe manner.

For UNSAFE and PER-RESOURCE, if calls are to be made from different cores, it is the caller's responsibility to use the necessary memory barriers to make sure that each core which makes a call sees a consistent view of memory, as if all the calls had been made from a single core. For example, the DualSerial module will want to use a per-UART spinlock to ensure that HAL calls for a specific UART can only occur on one core at a time. The spinlock implementation will internally perform barrier operations when locking and unlocking, automatically fulfilling this requirement.

For SAFE calls, the HAL must contains its own barriers and/or spinlocks as necessary, to allow it to cope with any kind of concurrent behaviour.


SMP safety of OS entry points
-----------------------------

Currently, all OS entry points are PRIMARY.


SMP safety of HAL entry points
------------------------------

PRIMARY:

* HAL_Init
* HAL_InitDevices
* HAL_KbdScan
* HAL_Reset
* HAL_SMPStartup

UNSAFE:

* HAL_NVMemory
* HAL_PCI
* HAL_USB
* HAL_Video
* HAL_DebugRX, HAL_DebugTX
* HAL_Watchdog

PER-RESOURCE:

* HAL_Timer & HAL_Counter (Note that HAL_Counter counts as timer zero)
* HAL_IIC
* HAL_UART

SAFE:

* HAL_CleanerSpace
* HAL_ExtMachineID
* HAL_HardwareInfo
* HAL_MachineID
* HAL_PhysInfo
* HAL_PlatformInfo
* HAL_PlatformName
* HAL_SuperIOInfo
* HAL_CPUCount
* HAL_CPUNumber


Safety of HAL_IRQ & HAL_FIQ entry points are described in a separate document.

The HAL_Matrix and HAL_Touchscreen entry points have been retired and replaced with new SMP/IRQ-related entry points, as described elsewhere.


SMP safety of HAL devices
-------------------------

In general, individual HAL devices are UNSAFE. Concurrent calls to different HAL devices should be safe, unless there are device-specific restrictions in place (e.g. DMA and audio typically make use of linked devices, and so count as a single unsafe resource). For more details, consult revised device documentation where available.


New entry points
----------------

For SMP systems, all of these entry points must be implemented. For non-SMP systems they can be left unimplemented (standard MOV pc,lr stub).


#56: int HAL_CPUCount(void)

  Returns the number of CPU cores which are present in the system and can be controlled by the HAL. E.g. 4 for a quad-core system.


#57: int HAL_CPUNumber(void)

  Returns a number in the range [0, HAL_CPUCount) which identifies the current core. Typically this will just involve extracting the lower bits from the CP15 MPIDR register, however since core numbering is platform-specific this action must be performed by the HAL.


#58: void HAL_SMPStartup(int core, unsigned int addr)

  Starts the indicated core (core number in the range [0, HAL_CPUCount)). Behaviour is undefined if the call is made for a core which has already started.

  'addr' provides the physical address of the code that the core should jump to once it starts. Depending on the platform and bootloader, the HAL may be required to perform basic initialisation beforehand (e.g. enabling the SMP bit in CP15, enabling the snoop control unit, GIC CPU interface initialisation, etc.). Essentially the core should be in the same state as the primary core was when OS_Start was called.

  The HAL can assume that all required code/data located at 'addr' has been fully flushed to main memory prior to the call.

  The HAL need not wait for the core to fully initialise; the OS will contain its own wait loop that will be exited once the desired core executes the startup code located at 'addr'.

  The OS will not attempt to initialise multiple cores in parallel. E.g. it is safe for the HAL to reuse the same portion of NCNB workspace to store any dynamic bootstrap code/data that is required.
