These are definition that are related to the basic architecture of the
CPU. These include the CPU context save format, context switching, bit
twiddling, breakpoints, stack sizes and address translation.
Most of these definition are found in
cyg/hal/hal_arch.h. This file is supplied by the
architecture HAL. If there are variant or platform specific
definitions then these will be found in
cyg/hal/var_arch.h or
cyg/hal/plf_arch.h. These files are include
automatically by this header, so need not be included explicitly.
typedef struct HAL_SavedRegisters
{
/* architecture-dependent list of registers to be saved */
} HAL_SavedRegisters; |
This structure describes the layout of a saved machine state on the
stack. Such states are saved during thread context switches,
interrupts and exceptions. Different quantities of state may be saved
during each of these, but usually a thread context state is a subset
of the interrupt state which is itself a subset of an exception state.
For debugging purposes, the same structure is used for all three
purposes, but where these states are significantly different, this
structure may contain a union of the three states.
HAL_THREAD_INIT_CONTEXT( sp, arg, entry, id ) |
This macro initializes a thread's context so that
it may be switched to by HAL_THREAD_SWITCH_CONTEXT().
The arguments are:
- sp
A location containing the current value of the thread's stack
pointer. This should be a variable or a structure field. The SP
value will be read out of here and an adjusted value written
back.
- arg
A value that is passed as the first argument to the entry
point function.
- entry
The address of an entry point function. This will be called
according the C calling conventions, and the value of
arg will be passed as the first
argument. This function should have the following type signature
void entry(CYG_ADDRWORD arg).
- id
A thread id value. This is only used for debugging purposes,
it is ORed into the initialization pattern for unused registers
and may be used to help identify the thread from its register dump.
The least significant 16 bits of this value should be zero to allow
space for a register identifier.
HAL_THREAD_LOAD_CONTEXT( to )
HAL_THREAD_SWITCH_CONTEXT( from, to ) |
These macros implement the thread switch code. The arguments are:
- from
A pointer to a location where the stack pointer of the current
thread will be stored.
- to
A pointer to a location from where the stack pointer of the next
thread will be read.
For HAL_THREAD_LOAD_CONTEXT() the current CPU
state is discarded and the state of the destination thread is
loaded. This is only used once, to load the first thread when the
scheduler is started.
For HAL_THREAD_SWITCH_CONTEXT() the state of the
current thread is saved onto its stack, using the current value of the
stack pointer, and the address of the saved state placed in
*from. The value in
*to is then read and the state of the new
thread is loaded from it.
While these two operations may be implemented with inline assembler,
they are normally implemented as calls to assembly code functions in
the HAL. There are two advantages to doing it this way. First, the
return link of the call provides a convenient PC value to be used in
the saved context. Second, the calling conventions mean that the
compiler will have already saved the caller-saved registers before the
call, so the HAL need only save the callee-saved registers.
The implementation of HAL_THREAD_SWITCH_CONTEXT()
saves the current CPU state on the stack, including the current
interrupt state (or at least the register that contains it). For
debugging purposes it is useful to save the entire register set, but
for performance only the ABI-defined callee-saved registers need be
saved. If it is implemented, the option
CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM controls
how many registers are saved.
The implementation of HAL_THREAD_LOAD_CONTEXT()
loads a thread context, destroying the current context. With a little
care this can be implemented by sharing code with
HAL_THREAD_SWITCH_CONTEXT(). To load a thread
context simply requires the saved registers to be restored from the
stack and a jump or return made back to the saved PC.
Note that interrupts are not disabled during this process, any
interrupts that occur will be delivered onto the stack to which the
current CPU stack pointer points. Hence the stack pointer
should never be invalid, or loaded with a value that might cause the
saved state to become corrupted by an interrupt. However, the current
interrupt state is saved and restored as part of the thread
context. If a thread disables interrupts and does something to cause a
context switch, interrupts may be re-enabled on switching to another
thread. Interrupts will be disabled again when the original thread
regains control.
HAL_LSBIT_INDEX( index, mask )
HAL_MSBIT_INDEX( index, mask ) |
These macros place in index the bit index of
the least significant bit in mask. Some
architectures have instruction level support for one or other of these
operations. If no architectural support is available, then these
macros may call C functions to do the job.
HAL_IDLE_THREAD_ACTION( count ) |
It may be necessary under some circumstances for the HAL to execute
code in the kernel idle thread's loop. An example might be to execute
a processor halt instruction. This macro provides a portable way of
doing this. The argument is a copy of the idle thread's loop counter,
and may be used to trigger actions at longer intervals than every
loop.
When optimizing the compiler can reorder code. In some parts of
multi-threaded systems, where the order of actions is vital, this can
sometimes cause problems. This macro may be inserted into places where
reordering should not happen and prevents code being migrated across
it by the compiler optimizer. It should be placed between statements
that must be executed in the order written in the code.
HAL_BREAKPOINT( label )
HAL_BREAKINST
HAL_BREAKINST_SIZE |
These macros provide support for breakpoints.
HAL_BREAKPOINT() executes a breakpoint
instruction. The label is defined at the breakpoint instruction so
that exception code can detect which breakpoint was executed.
HAL_BREAKINST contains the breakpoint instruction
code as an integer value. HAL_BREAKINST_SIZE is
the size of that breakpoint instruction in bytes. Together these
may be used to place a breakpoint in any code.
HAL_THREAD_GET_SAVED_REGISTERS( sp, regs )
HAL_GET_GDB_REGISTERS( regval, regs )
HAL_SET_GDB_REGISTERS( regs, regval ) |
These macros provide support for interfacing GDB to the HAL.
HAL_THREAD_GET_SAVED_REGISTERS() extracts a
pointer to a HAL_SavedRegisters structure
from a stack pointer value. The stack pointer passed in should be the
value saved by the thread context macros. The macro will assign a
pointer to the HAL_SavedRegisters structure
to the variable passed as the second argument.
HAL_GET_GDB_REGISTERS() translates a register
state as saved by the HAL and into a register dump in the format
expected by GDB. It takes a pointer to a
HAL_SavedRegisters structure in the
regs argument and a pointer to the memory to
contain the GDB register dump in the regval
argument.
HAL_SET_GDB_REGISTERS() translates a GDB format
register dump into a the format expected by the HAL. It takes a
pointer to the memory containing the GDB register dump in the
regval argument and a pointer to a
HAL_SavedRegisters structure
in the regs argument.
CYGARC_JMP_BUF_SIZE
hal_jmp_buf[CYGARC_JMP_BUF_SIZE]
hal_setjmp( hal_jmp_buf env )
hal_longjmp( hal_jmp_buf env, int val ) |
These functions provide support for the C
setjmp() and longjmp()
functions. Refer to the C library for further information.
CYGNUM_HAL_STACK_SIZE_MINIMUM
CYGNUM_HAL_STACK_SIZE_TYPICAL |
The values of these macros define the minimum and typical sizes of
thread stacks.
CYGNUM_HAL_STACK_SIZE_MINIMUM defines the minimum
size of a thread stack. This is enough for the thread to function
correctly within eCos and allows it to take interrupts and context
switches. There should also be enough space for a simple thread entry
function to execute and call basic kernel operations on objects like
mutexes and semaphores. However there will not be enough room for much
more than this. When creating stacks for their own threads,
applications should determine the stack usage needed for application
purposes and then add
CYGNUM_HAL_STACK_SIZE_MINIMUM.
CYGNUM_HAL_STACK_SIZE_TYPICAL is a reasonable increment over
CYGNUM_HAL_STACK_SIZE_MINIMUM, usually about 1kB. This should be
adequate for most modest thread needs. Only threads that need to
define significant amounts of local data, or have very deep call trees
should need to use a larger stack size.
CYGARC_CACHED_ADDRESS(addr)
CYGARC_UNCACHED_ADDRESS(addr)
CYGARC_PHYSICAL_ADDRESS(addr) |
These macros provide address translation between different views of
memory. In many architectures a given memory location may be visible
at different addresses in both cached and uncached forms. It is also
possible that the MMU or some other address translation unit in the
CPU presents memory to the program at a different virtual address to
its physical address on the bus.
CYGARC_CACHED_ADDRESS() translates the given
address to its location in cached memory. This is typically where the
application will access the memory.
CYGARC_UNCACHED_ADDRESS() translates the given
address to its location in uncached memory. This is typically where
device drivers will access the memory to avoid cache problems. It may
additionally be necessary for the cache to be flushed before the
contents of this location is fully valid.
CYGARC_PHYSICAL_ADDRESS() translates the given
address to its location in the physical address space. This is
typically the address that needs to be passed to device hardware such
as a DMA engine, ethernet device or PCI bus bridge. The physical
address may not be directly accessible to the program, it may be
re-mapped by address translation.
CYGARC_HAL_SAVE_GP()
CYGARC_HAL_RESTORE_GP() |
These macros insert code to save and restore any global data pointer
that the ABI uses. These are necessary when switching context between
two eCos instances - for example between an eCos application and
RedBoot.