The Programmable Interrupt Controller is a chip responsible for
translating hardware interrupts to system interrupts. When it
receives an Interrupt Request (IRQ), it triggers the appropriate
interrupt line reaching the appropriate IDT gate, following a
previously setup offset.
There are 2 daisy-chained PICs. PIC1 handles IRQs 0-7 and PIC2
handles IRQs 8-15. If no vector offset is set, an IRQ0, for instance,
would trigger the interrupt 0, clashing with the "Division by zero exception"
handler. Thus the IRQs must be remapped.
This patch implements the PICs initialization through their 4
Initialization Command Words (ICWs) in a very "canonical" way:
- ICW1: the initializing command;
- ICW2: the vector offset for the PIC1 and PIC2 (we add an offset of 32 positions);
- ICW3: the inter-PICs wiring setup (we connect PIC2 to PIC1's IRQ2);
- ICW4: extra systems information (we set PIC1 as Master and PIC2 as slave).
It then masks the Interrupt Mask Register, blocking all IRQs but #2 initially.
These must be unmasked on demand. The IMR is 8-bits long, so setting the n^th bit to 1
would DISABLE the IRQ n while setting it to 0 would ENABLE IRQ n.
As stated, this is an implementation of the legacy 8259 PIC. More
investigation is needed so we decide if it is enough or if we need
the (newer) APIC implementation instead.
This patch also adds the outb() helper function to helpers.h. The helpers
is a wrapper for assembly 'out' instruction.
Finally, since we now properly support hardware interrupts, this patch
also enables IRQs in platform main().
More information:
- Quark X1000 Datasheet, section 21.12, page 898.
- http://wiki.osdev.org/8259_PIC
- http://stanislavs.org/helppc/8259.html
This patch sets an interrupt handler for Double Fault exception during
CPU initialization. In case such exception is raised, we halt the system.
This way, we avoid the system to triple fault (due to an unhandled
interrupt for instance), leaving no trace about what cause the triple
fault.
This patch introduces the interrupt.h header file which provides some
helper macros to set a interrupt handler and disable/enable maskable
hardware interrupts.
Since there is no easy way to write an Interrupt Service Routines
(ISR) in C (for further information on this, see [1]), we introduce
the SET_INTERRUPT_HANDLER helper macro.
The macro does two things:
1) Defines an assembly trampolin to a C function that will, indeed,
handle the interrupt.
2) Sets the corresponding interrupt gate descriptor in IDT.
The macro usage is pretty straightforward. The macro is defined as
SET_INTERRUPT_HANDLER(num, has_error_code, handler) where:
@num: Interrupt number (0-255)
@has_error_code: 0 if processor doesn't push error code onto the
stack. Otherwise, set this argument to 1.
@handler: Pointer to function that should be called once the
interrupt is raised. In case has_error_code == 0
the function prototype should be the following:
void handler(void)
Otherwise, it should be:
void handler(struct interrupt_context context)
For instance, let's say we want to set a handler for a device interrupt
(for example, interrupt number 101). Remember, hardware interrupts don't
have error code. So we should have something like this:
void interrupt_handler(void)
{
/* Handling code here */
}
void my_device_init(void)
{
...
SET_INTERRUPT_HANDLER(101, 0, interrupt_handler);
...
}
Now, let's say we want to set an interrupt handler for Page Fault
(interrupt number 14). Some exceptions, such as Page Fault, pushes an
error code onto the stack and may require registers values in order
to be properly be handled. Thus, the code should look like this:
void pagefault_handler(struct interrupt_context context)
{
/* Handling code here */
}
void init_memory(void)
{
...
SET_INTERRUPT_HANDLER(14, 1, pagefault_handler);
...
}
For further information about exceptions and error code, refer to Intel
Combined Manual, Vol. 3, Sections 6.3 and 6.13.
Finally, we don't define any API to unregister interrupt handlers since
we believe that it wouldn't be useful at all, at least at this moment.
Considering Contiki's context, interrupt handler registration is pretty
"static" and defined at compile-time by platform code (or the device
drivers used by the platform).
[1] http://wiki.osdev.org/Interrupt_Service_Routines
This patch defines the cpu_init() function which should encapsulate
all code related to x86 CPU initialization. For now, this function
initializes GDT and IDT.
This patch adds code to handle Interrupt Descriptor Table (IDT)
initialization. The IDT is initialized with null descriptors
therefore any interrupt at this point will cause a triple fault.
The IDT initialization is part of x86 CPU initialization.
Strictly speaking, there is no need to use attribute packed in struct
intr_gate_desc however we use it for readability reasons.
This patch adds the helpers.h. This file should contain only x86-related
helper functions and macros. For now, we define the BIT macro and halt()
helpers which will be used in upcoming patches.
Additionally, this patch also changes loader.S to call the halt().
This patch adds code to initialize the Global Descriptor Table. For
simplicity, the memory is organized following the flat model. Thus,
memory appears to Contiki as a single, continuous address space. Code,
data, and stack are all contained in this address space (so called
linear address space).
The macros to manipulate bits from segment descriptor and the
set_descriptor() helper are based on the ones described in [1].
[1] http://wiki.osdev.org/GDT_Tutorial
This patch implements the main() function for Galileo platform. At this
moment, only Processes subsystem is enabled. After this patch we are
able to some rudimentary debugging to ensure that process thread from
applications are being indeed executed.
Once we properly support more Contiki subsystems, such as clock, ctimer,
etimer, and rtimer, we will add them to Galileo platform's main() as well.
All we need to provide to C at this point is a region in memory dedicated to
its stack. This is done by allocating a region in .bss and pushing its start
address to esp. Since the multiboot spec says it is not safe to rely on the
initial stack provided by the bootloader, this patch provides our own stack.
Galileo boards have 512Kb of SRAM and 256Mb of DDR3 RAM, so providing 8kb as
a start seems safe. Moreover, stack sizes are very application-oriented
so it may be too early to provide a bigger (or smaller) stack.
This patch changes Galileo's buildsystem to print the elf sections
sizes after a new image is built. This way we can easily track how
these sections increase or decrease after any change.
To achieve that, we define a custom linking rule which is pretty much
the same as the default linking rule define in Makefile.include, but
we run 'size' command after the image is built.
This patch adds a README file which contains general information about
the Intel Galileo board support. The file provides information about
supported features as well as instructions on how to build, run and debug
applications for this platform.
This patch the 'debug' rule to simplify the debugging process. This new
rule runs OpenOCD and gdb with the right parameters. OpenOCD runs in
background and its output will be redirected to a log file in the
application's path called LOG_OPENOCD. Once gdb client is detached,
OpenOCD is terminated.
The 'debug' rule is defined in Makefile.customrules-galileo file (create
by this patch) which is included by the Contiki's buildsystem. So to
debug a Contiki application for Galileo board, run the following command:
$ make TARGET=galileo debug
If you use a gdb front-end, you can define the "GDB" environment variable
and your gdb front-end will be used instead of default gdb. For instance,
if you want to use cgdb front-end, just run the command:
$ make BOARD=galileo debug GDB=cgdb
This patch adds the initial support for Intel Galileo Platform. It
contains the minimum set of code required to boot a dummy Contiki
image.
For Galileo initial support, we implemented a linker script, a minimal
bootstrap code, a set of stubbed functions required by newlib, and a
very simple main() function. Moreover, we also define some header files
and macros required by Contiki.
To build applications for this platform you should first build newlib
(in case it wasn't already built). To build newlib you can run the
following command:
$ platform/galileo/bsp/libc/build_newlib.sh
Once newlib is built, you can build applications. To build applications
for Galileo platform you should set TARGET variable to 'galileo'. For
instance, building the hello-world application should look like this:
$ cd examples/hello-world/ && make TARGET=galileo
This will generate the 'hello-world.galileo' file which is a multiboot-
compliant [1] ELF image. This image can be booted by any multiboot-
complaint bootloader such as Grub.
Finally, this patch should be used as a guideline to add the initial
support for others platforms based on x86 SoCs.
[1] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
This patch creates the platform/galileo/bsp directory. This directory
contain all files related to Galileo's Board Support Package (BSP). For
now, the BSP consists of libc and bootloader.
Within the BSP directory, we have the scripts build_newlib.sh and build_
grub.sh. These scripts provide an easy and quick way to build the newlib
and the grub for the Galileo platform.
Currently there are only one platform using CPU x86: Cooja. The
elfloader-x86.c is rather a POSIX implementation, so the Galileo port
won't use it for now. This patch fixes this by moving this source file to
be included by the platforms using it instead of the cpu's Makefile.
The peripheral core clocks of the PWM timers are gated in PM1+, so these
power modes must be disabled if a PWM timer is running. Use
lpm_register_peripheral() to handle this automatically and dynamically.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau.dev@gmail.com>
The peripheral core clock of the general-purpose timers used by the PWM
driver is the system clock, not the I/O clock.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau.dev@gmail.com>
According to the Procedure Call Standard for the ARM Architecture
(AAPCS) - ABI r2.09 [1], §5.2.1.2, the stack pointer must be
double-word-aligned at a public interface. The stack implementation
being full-descending, this requires that the top of stack be
double-word-aligned too.
[1] http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau.dev@gmail.com>