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 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.
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 symbol generation shell scripts cause CRLF issues on Windows/Cygwin again and again. Instead of fixing this yet again I opted to remove the symbol generation script at least for the "no symbols" scenario with two C source files to be copied.
- All compilers used support the -I option for setting an include search directory.
- The Contiki source tree follows the (common) approach of placing declarations (in headerf iles) in the same directory as definitions (in source files).
As a result it makes sense to use the -I compiler option for just the same set of directories used for the vpath gnumake directive.
Note: I checked several builds but nevertheless one or the other might need some additional adjustsments. Sorry for the inconvenience.
- Search target specific directories before CPU specific directories.
- Search CPU specific directories before generic directories.
Note: I checked several builds but nevertheless one or the other might need some additional adjustsments. Sorry for the inconvenience.