Entries 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
RISC OS and the "HAL"

RISC OS currently is tied to the IOMD20 and VIDC20 peripheral set,
descendents of the original IOC, MEMC and VIDC devices designed in parallel
with the original ARM. These devices provide a close fit with RISC OS, and
their functionality is well suited to general purpose and embedded systems,
but the continuing drive to reduce cost requires us to support other
peripheral sets on off-the-shelf ARM system on chips.

First targets for support are L7205/L7210 for Customer L and CL92xx (the new
ARM920T based devices) for Customer A. Enclosed are a summary of their
advantages and disadvantages over the ARM7500FE for our Information
Appliance designs.

              L7205                       CL92xx
            + Faster (50% or so)        + Faster (400%+)
            + SDRAM support             + SDRAM support
            + USB                       + USB
                                        + EIDE interface
                                        + Lots of GPIO
            - No hardware cursor
            - No floating point         - Incompatible floating point
            - No video DACs             - No video DACs
            - No PS/2                   - No PS/2
                                        - Bizarre MS-Windows video system

To support these devices, and others in the future, a simple HAL is to be
inserted underneath RISC OS. This will provide two functions. Firstly, it
will be responsible for initial system bootstrap, much like a PC BIOS, and
secondly it will provide simple APIs to allow hardware access.

The HAL APIs are a thin veneer on top of the hardware. They are designed to
act as replacements for all the hardware knowledge and manipulation performed
by the RISC OS Kernel, together with some APIs that will allow RISC OS driver
modules to become more hardware independent. No attempt will be made (at this
stage) to perform such tasks as separating the video drivers from the Kernel,
for example.

One tricky design decision is the amount of abstraction to aim for. Too
little, and the system is not flexible enough; too much and HAL design is
needlessly complicated for simple hardware. The present design tries to
err on the side of too little abstraction. Extra, more abstract APIs can
always be added later. So, initially, for example, the serial device API
will just provide discovery, some capability flags and the base address
of the UART register set. This will be sufficient for the vast majority
of devices. If new hardware comes along later that isn't UART compatible,
a new API can be defined. Simple hardware can continue to just report
UART base addresses.

The bulk of device driver implementation remains in RISC OS modules - the
difference is that the HAL will allow many device drivers to no longer
directly access hardware. For example, PS2Driver can now use HAL calls to
send and receive bytes through the PS/2 ports, and thus is no longer tied to
IOMD's PS/2 hardware. Similarly, interrupt masking and unmasking, as
performed by any device vector claimant, is now a HAL call. Note that HAL
calls are normally performed via a Kernel SWI - alternatively the Kernel
can return the address of specific Kernel routines. There is nothing to stop
specific drivers talking to hardware directly, as long as they accept that
this will tie them to specific devices.

This dividing line between the HAL and RISC OS driver modules is crucial. If
the HAL does everything, then we have achieved nothing - we have just as much
hardware dependent code - it's just in a different place. It is important to
place the dividing line as close to the hardware as possible, to make it easy
to design a HAL and to prevent large amounts of code  duplication between
HALs for different platforms.

The Kernel remains responsible for the ARM's MMU and all other aspects of the
CPU core. The HAL requires no knowledge of details of ARM implementations,
and thus any HAL implementation should work on any processor from the ARM610
to the ARM940T or XScale.

OS independence

Notionally, the HAL implementation is OS independent. It makes no assumptions
about the virtual memory map of the OS, and only uses the defined HAL->OS
entries. The HAL should not call RISC OS SWIs.

In practice, however, the HALs are unlikely to be used on anything other
than RISC OS, and many HALs are likely to be written. This makes it sensible
to place as much intelligence as possible within RISC OS itself, to prevent
duplicated effort.

Calling standards

RISC OS and the HAL are two separate entities, potentially linked separately.
Thus some simple dynamic linking is required. This occurs via a hybrid of the
RISC OS module header and Shared C Library stubs. Each RISC OS/HAL entry is
given a unique (arbitrary) number, starting at 0. The offset to each entry is
given in an entry table. Calls can be made manually through this table, or
stubs could be created at run-time to allow high-level language calls.

Every entry (up to the declared maximum) must exist. If not implemented, a
failure response must be returned, or the call ignored, as appropriate.

To permit high-level language use in the future, the procedure call standard
in both directions is ATPCS, with no use of floating point, no stack limit
checking, no frame pointers, and no Thumb interworking. HAL code is expected
to be ROPI and RWPI (hence it is called with its static workspace base in
sb). The OS kernel is neither ROPI nor RWPI (except for the pre-MMU calls,
which are ROPI).

The HAL will always be called in a privileged mode - if called in an
interrupt mode, the corresponding interrupts will be disabled. The HAL should
not change mode. HAL code should work in both 26-bit and 32-bit modes (but
should assume 32-bit configuration).

Header formats

The OS is linked to run at a particular base address. At present, the address
will be at <n>MB + 64KB. This allows a HAL of up to 64K to be placed at the
bottom of a ROM below the OS, and the whole thing to be section-mapped.
However, if a different arrangement is used, the system will still work
(albeit slightly less efficiently).

The OS starts with a magic word - this aids probing and location of images.
Following that is a defined header format:

Word 0: Magic word ("OSIm" - &6D49534F)
Word 1: Flags (0)
Word 2: Image size
Word 3: Offset from base to entry table
Word 4: Number of entries available

The HAL itself may have whatever header is required to start the system. For
example on ARM7500 16->32 bit switch code is required, and on the 9500 parts
a special ROM header and checksum must be present. Instead of a header,
a pointer to the HAL descriptor is passed to the OS in the OS_Start call:

139 140 141
Word 0: Flags
            bit 0 => uncachable workspace (32K) required
            bits 1-31 reserved
142 143 144 145 146 147
Word 1: Offset from descriptor to start of HAL (will be <= 0)
Word 2: HAL size
Word 3: Offset from descriptor to entry table
Word 4: Number of entries available
Word 5: Static workspace required

Kevin Bracey's avatar
Kevin Bracey committed
Each of the HAL and the OS must be contiguous within physical memory.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

RISC OS entry points from HAL init

Entry 0:
void RISCOS_InitARM(unsigned int flags)

    flags: reserved - sbz

On entry:
  SVC mode
  MMU and caches off
  IRQs and FIQs disabled
  No RAM or stack used

On exit:
  Instruction cache may be on

  This routine must be called once very early on in the HAL start-up, to accelerate the
  CPU for the rest of HAL initialisation. Typically, it will just enable the instruction
  cache (if possible on the ARM in use), and ensure that the processor is in 32-bit
  configuration and mode.

  Some architecture 4 (and later) ARMs have bits in the control register that affect
  the hardware layer - eg the iA and nF bits in the ARM920T. These are the HAL's
  responsibility - the OS will not touch them. Conversely, the HAL should not touch the
  cache, MMU and core configuration bits (currently bits 0-14).

  On architecture 3, the control register is write only - the OS will set bits 11-31 to

  Likewise, such things as the StrongARM 110's register 15 (Test, Clock and Idle Control)
  are the HAL's responsibility. The OS does not know about the configuration of the
  system, so cannot program such registers.

  This entry may not be called after RISCOS_Start.

Entry 1:
void *RISCOS_AddRAM(unsigned int flags, void *start, void *end, uintptr_t sigbits, void *ref)
        bit 0: video memory (only first contiguous range will be used)
        bits 8-11: speed indicator (arbitrary, higher => faster)
        other bits reserved (SBZ)
        start address of RAM (inclusive) (no alignment requirements)
        end address of RAM (exclusive) (no alignment requirements, but must be >= start)
        significant address bit mask (1 => this bit of addr decoded, 0 => this bit ignored)
        reference handle (NULL for first call)

Returns ref for next call

On entry:
  SVC32 mode
  MMU and data cache off
  IRQs and FIQs disabled

Other notes:
  This entry point must be the first call from the HAL to RISC OS following a hardware
  reset. It may be called as many times as necessary to give all enumerate RAM that
  is available for general purpose use. It should only be called to declare video
  memory if the video memory may be used as normal RAM when in small video modes.

  To permit software resets:
    The HAL must be non-destructive of any declared RAM outside the first 4K of the first
    The stack pointer should be initialised 4K into the first block, or in some non-
    declared RAM.
    Must present memory in a fixed order on any given system.

  Current limitations:
    The first block must be at least 256K and 16K aligned. (Yuck)
    Block coalescing only works well if RAM banks are added in ascending address order.

  RISC OS will use RAM at the start of the first block as initial workspace. Max usage
  is 16 bytes per block + 32 (currently 8 per block + 4). This limits the number of
  discontiguous blocks (although RISC OS will concatanate contiguous blocks where

  This call must not be made after RISCOS_Start.

Entry 2:
void RISCOS_Start(unsigned int flags, int *riscos_header, int *hal_entry_table, void *ref)

        bit 0: power on reset
247 248 249
        bit 1: CMOS reset inhibited (eg protection link on Risc PC)
        bit 2: perform a CMOS reset (if bit 1 clear and bit 0 set - eg front panel
                                     button held down on an NC)
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

On entry:
  SVC32 mode
  MMU and data cache off
  IRQs and FIQs disabled

  This routine must be called after all calls to RISCOS_AddRAM have been completed.
  It does not return. Future calls back to the HAL are via the HAL entry table, after
  the MMU has been enabled.

Entry 3:
void *RISCOS_MapInIO(unsigned int flags, void *phys, unsigned int size)

   flags: bit 2 => make memory bufferable
    phys: physical address to map in
    size: number of bytes of memory to map in

  This routine is used to map in IO memory for the HAL's usage. Normally it would
  only be called during HAL_Init(). Once mapped in the IO space cannot be released.

  It returns the resultant virtual address corresponding to phys, or 0 for failure.
  Failure can only occur if no RAM is available for page tables, or if the virtual
  address space is exhausted.

HAL entries

void HAL_Start(int *riscos_header)