Hardware initialization
The startup code does the minimum needed to detect the hardware configuration and completes any other configuration needed for the OS kernel to run.
The source code for the initialization routines is found in the src/hardware/startup/boards/boardname/ and src/hardware/startup/lib/ directories of the BSP. The boardname directory has the platform- and platform variant-specific source code. If the source code is generic for the architecture (which is more common with x86 platforms), the source code is in the startup/lib/ directory.
Source code structure) calls the following hardware initialization functions in this order:
Many BSPs also include hardware initialization functions for supported technologies; you will find these in appropriately named files (e.g., init_sata.c, init_usb.c). For more information, see the init_*() functions in the Startup Library.
Adding hardware initialization code
- If the code is only a few lines, put it right in the main() function.
- If the code is more involved, create a new function and call it from main().
// Announce start of Startup code
for (i = 0; i < 8; ++i)
led[i] = startup_msg[i];
Setting interrupt sensitivity
Most systems today use only level-sensitive interrupts. QNX OS supports level-sensitive interrupts but also edge-sensitive interrupts to support legacy hardware (e.g., Intel x86 hardware with the 8259 PIC on an ISA bus).
It is the responsibility of the interrupt
controller initialization code along with the interrupt kernel callouts to specify
the interrupt sensitivity (see Interrupt controller
for information about interrupt kernel
callouts).
/*
* Make all SPI interrupts level-triggered by default
*/
for (i = 32; i < itn; i += 16) {
out32(gicd + ARM_GICD_ICFGRn + (i * 4 / 16), 0);
}
On this board, the sensitivity information for each interrupt ID is stored in the GIC's ICFGR registers. Zero (0) means level-sensitive interrupts. The code snippet above writes 0 to these registers. Check your board's documentation to learn what registers you need to set (if any) and to what values to enable level-sensitive interrupt support.
gic_v2_init(paddr_t gicd, paddr_t gicc)
{
struct aarch64_gic_map_entry *gic_map = lsp.cpu.aarch64_gic_map.p;
unsigned gic_cpu;
unsigned itn;
unsigned i;
gic_gicd = gicd;
gic_gicc = gicc;
gic_cpu_init = gic_v2_gicc_init;
gic_sendipi = &sendipi_gic_v2;
/*
* Initialise the GIC cpu map with invalid values.
* gic_v2_gicc_init() will set the mapping for each cpu as it comes up.
*/
for (i = 0; i < lsp.syspage.p->num_cpu; i++) {
gic_map->gic_cpu[i] = ~0u;
}
gic_cpu = gic_v2_cpunum();
/*
* Disable distributor
*/
out32(gicd + ARM_GICD_CTLR, 0);
/*
* Calculate number of interrupt lines
*/
itn = ((in32(gicd + ARM_GICD_TYPER) & ARM_GICD_TYPER_ITLN) + 1) * 32;
gic_v2_intr.num_vectors = itn;
if (debug_flag) {
kprintf("GICv2: %d interrupts\n", itn);
}
/*
* Disable all interrupts and clear pending state
*/
for (i = 0; i < itn; i += 32) {
out32(gicd + ARM_GICD_ICENABLERn + (i * 4 / 32), 0xffffffff);
out32(gicd + ARM_GICD_ICPENDRn + (i * 4 / 32), 0xffffffff);
}
/*
* Set default priority of all interrupts to 0xa0
*/
for (i = 0; i < itn; i += 4) {
out32(gicd + ARM_GICD_IPRIORITYn + i, 0xa0a0a0a0);
}
/*
* Route all SPI interrupts to cpu0
*/
if (debug_flag) {
kprintf("GICv2: routing SPIs to gic cpu %d\n", gic_cpu);
}
for (i = 32; i < itn; i += 4) {
out32(gicd + ARM_GICD_ITARGETSRn + i, (0x01010101u << gic_cpu));
}
/*
* Make all SPI interrupts level-triggered by default
*/
for (i = 32; i < itn; i += 16) {
out32(gicd + ARM_GICD_ICFGRn + (i * 4 / 16), 0);
}
/*
* Enable distributor - cpu interface is initialised via init_cpuinfo()
*/
out32(gicd + ARM_GICD_CTLR, ARM_GICD_CTLR_EN);
/*
* Add the interrupt callouts
*/
add_interrupt(&gic_v2_intr);
}
A programmer's use of interrupt-related functions such as InterruptAttachThread() or InterruptMask() isn't affected by the interrupt sensitivity, though you should be aware of the implications of the interrupt sensitivity on your system, as this may affect what you must do when working with interrupts.
For more information about interrupts, see the Interrupts chapter in Getting Started with the QNX OS, and the Handling Hardware Interrupts chapter in the Programmer's Guide.