merge with master

This commit is contained in:
akroh 2014-09-29 13:11:13 +10:00
commit 911d135e2f
54 changed files with 879 additions and 286 deletions

54
CONTRIBUTORS.md Normal file
View file

@ -0,0 +1,54 @@
Contributors
------------
People who contributed to the seL4 code, design, or documentation in this
repository (in alphabetical order).
* June Andronick, NICTA & UNSW
* Ali Akguel, NICTA
* Joel Beeren, NICTA
* Bernard Blackham, NICTA & UNSW
* Timothy Bourke, NICTA
* Andrew Boyton, NICTA & UNSW
* Matthew Brassil, NICTA
* Aleksander Budzynowski, NICTA & UNSW
* Manuel Chakravarty, NICTA & UNSW
* Xi Ma Chen, NICTA
* Nahida Chowdhury, NICTA
* Peter Chubb, NICTA
* David Cock, NICTA & UNSW
* Adrian Danis, NICTA
* Matthias Daum, NICTA & UNSW
* Philip Derrin, NICTA
* Dhammika Elkaduwe, NICTA & UNSW
* Kevin Elphinstone, NICTA & UNSW
* Matthew Fernandez, NICTA & UNSW
* Peter Gammie, NICTA
* Xin Gao, NICTA
* David Greenaway, NICTA & UNSW
* Matthew Grosvenor, NICTA
* Lukas Haenel, NICTA
* Gernot Heiser, NICTA & UNSW
* Benjamin Kalman, NICTA
* Justin King-Lacroix, NICTA
* Gerwin Klein, NICTA & UNSW
* Rafal Kolanski, NICTA & UNSW
* Alexander Kroh, NICTA
* Etienne Le Sueur, NICTA & UNSW
* Corey Lewis, NICTA
* Japheth Lim, NICTA
* Anna Lyons, NICTA & UNSW
* Stephanie McArthur, NICTA
* Sam McNally, NICTA
* Toby Murray, NICTA & UNSW
* Ameya Palande, NICTA
* Max R.D. Parmer
* Sean Peters, NICTA
* Simon Rodgers, NICTA
* Sean Seefried, NICTA
* Thomas Sewell, NICTA & UNSW
* Michael von Tessin, NICTA & UNSW
* Adam Walker, NICTA
* James Wilmot, NICTA
* Simon Winwood, NICTA
* Jiawei Xie, NICTA

View file

@ -202,7 +202,7 @@ menu "seL4 System Parameters"
config MAX_NUM_BOOTINFO_DEVICE_REGIONS
int "Max number of bootinfo device regions"
default 200
default 199
config MAX_NUM_BOOTINFO_UNTYPED_CAPS
int "Max number of bootinfo untyped caps"

View file

@ -17,7 +17,7 @@
ARCH_LIST:=arm ia32
CPU_LIST:=arm1136jf-s ixp420 cortex-a8 cortex-a9 cortex-a15
PLAT_LIST:=imx31 pc99 integratorcp ixp420 omap3 am335x exynos4 exynos5 imx6 apq8064
PLAT_LIST:=imx31 pc99 ixp420 omap3 am335x exynos4 exynos5 imx6 apq8064
ARMV_LIST:=armv6 armv7-a
ifndef SOURCE_ROOT
@ -343,7 +343,7 @@ endif
ifndef NK_CFLAGS
ifeq (${ARCH}, arm)
CFLAGS += -mtune=${CPU} -marm -march=${ARMV}
ASFLAGS += -mcpu=${CPU} -march=${ARMV}
ASFLAGS += -Wa,-mcpu=${CPU} -Wa,-march=${ARMV}
DEFINES += -D$(shell echo ${ARMV}|tr [:lower:] [:upper:]|tr - _)
ifeq (${CPU},cortex-a8)
DEFINES += -DARM_CORTEX_A8
@ -356,7 +356,7 @@ endif
ifeq (${ARCH}, ia32)
CFLAGS += -m32 -mno-mmx -mno-sse
ASFLAGS += --32
ASFLAGS += -Wa,--32
endif
endif
@ -465,7 +465,7 @@ kernel_all.c: sources_list_updated ${C_SOURCES_WITH_PARSE} ${DOMAIN_CONFIG_FILE}
kernel.o: kernel_final.s
@echo " [AS] $@"
$(Q)${AS} ${ASFLAGS} -o $@ $<
$(Q)${CC} ${ASFLAGS} -o $@ -c $<
kernel_final.s: kernel_final.c
@echo " [CC] $@"
@ -480,7 +480,7 @@ LINKER_SCRIPT = src/plat/${PLAT}/linker.lds
kernel.elf: ${OBJECTS} ${LINKER_SCRIPT}
@echo " [LD] $@"
$(Q)${CHANGED} $@ ${LD} ${LDFLAGS} -T ${SOURCE_ROOT}/${LINKER_SCRIPT} \
$(Q)${CHANGED} $@ ${CC} ${LDFLAGS} -Wl,-T -Wl,${SOURCE_ROOT}/${LINKER_SCRIPT} \
-o $@ ${OBJECTS}
############################################################
@ -493,7 +493,7 @@ kernel.elf: ${OBJECTS} ${LINKER_SCRIPT}
%.o: %.s | ${DIRECTORIES}
@echo " [AS] $@"
$(Q)${AS} ${ASFLAGS} $< -o $@
$(Q)${CC} ${ASFLAGS} -c $< -o $@
###################

View file

@ -13,15 +13,23 @@ The seL4 Repository
This repository contains the source code of seL4 microkernel.
For details about the seL4 microkernel, including details about the proof,
please see the [`sel4.systems`][1] website and associated [FAQ][2].
For details about the seL4 microkernel, including details about its formal
correctness proof, please see the [`sel4.systems`][1] website and associated
[FAQ][2].
DOIs for citing recent releases of this repository:
* [![DOI][4]](http://dx.doi.org/10.5281/zenodo.11247)
We welcome contributions to seL4. Please see the website for information
on [how to contribute][3].
This repository is usually not used in isolation, but as part of the build
system in a larger project.
[1]: http://sel4.systems/
[2]: http://sel4.systems/FAQ/
[3]: http://sel4.systems/Contributing/
[4]: https://zenodo.org/badge/doi/10.5281/zenodo.11247.png
Repository Overview
-------------------
@ -31,7 +39,7 @@ Repository Overview
* `haskell`: Haskell model of the seL4 kernel,
kept in sync with the C version.
* `libsel4`: C bindings for the seL4 ABI
* `manual`: LaTeX sourced of the seL4 reference manual
* `manual`: LaTeX sources of the seL4 reference manual
Build Instructions
@ -63,6 +71,10 @@ build using `make`, follow these instructions:
* For a debug build, append `DEBUG=y`.
See the seL4 website for more [comprehensive build instructions][5].
[5]: http://sel4.systems/Download/
License
=======

View file

@ -138,6 +138,10 @@ The following data type defines the set of possible invocations for IRQ capabili
> setIRQHandlerCap :: Capability,
> setIRQHandlerSlot :: PPtr CTE }
> | ClearIRQHandler { irqHandlerIRQ :: IRQ }
> | SetMode {
> modeIRQ :: IRQ,
> modeTrigger :: Bool,
> modePolarity :: Bool }
> deriving Show
\subsection{Invocation Labels}
@ -172,6 +176,7 @@ This datatype is defined globally over architectures as well as object types.
> | IRQAckIRQ
> | IRQSetIRQHandler
> | IRQClearIRQHandler
> | IRQSetMode
> | DomainSetSet
> | ARMPDClean_Data
> | ARMPDInvalidate_Data

View file

@ -554,12 +554,12 @@ If the kernel receives a VM fault from the CPU, it must determine the address an
> handleVMFault _ ARMDataAbort = do
> addr <- withoutFailure $ doMachineOp getFAR
> fault <- withoutFailure $ doMachineOp getDFSR
> throw $ VMFault addr [0, fault .&. mask 12]
> throw $ VMFault addr [0, fault .&. mask 14]
>
> handleVMFault thread ARMPrefetchAbort = do
> pc <- withoutFailure $ asUser thread $ getRestartPC
> fault <- withoutFailure $ doMachineOp getIFSR
> throw $ VMFault (VPtr pc) [1, fault .&. mask 12]
> throw $ VMFault (VPtr pc) [1, fault .&. mask 14]
\subsection{Unmapping and Deletion}

View file

@ -156,6 +156,12 @@ This function is used by the kernel to acknowledge an interrupt, after it has be
> ackInterrupt :: IRQ -> MachineMonad ()
> ackInterrupt (IRQ irq) = Arch.ackInterrupt irq
This function is used to implement IOAPIC functionality in the kernel.
> setInterruptMode :: IRQ -> Bool -> Bool -> MachineMonad ()
> setInterruptMode (IRQ irq) levelTrigger polarityLow = Arch.setInterruptMode irq levelTrigger polarityLow
\subsubsection{Timers}
The timer interval is set at boot time by calling this function. It returns the IRQ that is used for timer interrupts.

View file

@ -142,6 +142,10 @@ The following functions define the ARM-specific interface between the kernel and
> cbptr <- ask
> liftIO $ Platform.maskInterrupt cbptr maskI irq
> -- IOAPIC only does stuff on IA32
> setInterruptMode :: IRQ -> Bool -> Bool -> MachineMonad ()
> setInterruptMode _ _ _ = return ()
> configureTimer :: MachineMonad IRQ
> configureTimer = do
> cbptr <- ask

View file

@ -90,9 +90,9 @@ There is a single, global interrupt controller object; a capability to it is pro
An IRQ handler capability allows a thread possessing it to set an endpoint which will be notified of incoming interrupts, and to acknowledge received interrupts.
> decodeIRQHandlerInvocation :: Word -> IRQ -> [(Capability, PPtr CTE)] ->
> decodeIRQHandlerInvocation :: Word -> [Word] -> IRQ -> [(Capability, PPtr CTE)] ->
> KernelF SyscallError IRQHandlerInvocation
> decodeIRQHandlerInvocation label irq extraCaps =
> decodeIRQHandlerInvocation label args irq extraCaps =
> case (invocationType label,extraCaps) of
> (IRQAckIRQ,_) -> return $ AckIRQ irq
> (IRQSetIRQHandler,(cap,slot):_) -> case cap of
@ -101,8 +101,14 @@ An IRQ handler capability allows a thread possessing it to set an endpoint which
> _ -> throw $ InvalidCapability 0
> (IRQSetIRQHandler,_) -> throw TruncatedMessage
> (IRQClearIRQHandler,_) -> return $ ClearIRQHandler irq
> (IRQSetMode,_) -> case args of
> trig:pol:_ -> return $ SetMode irq (toBool trig) (toBool pol)
> _ -> throw TruncatedMessage
> _ -> throw IllegalOperation
> toBool :: Word -> Bool
> toBool w = w /= 0
> invokeIRQHandler :: IRQHandlerInvocation -> Kernel ()
> invokeIRQHandler (AckIRQ irq) =
> doMachineOp $ maskInterrupt False irq
@ -113,6 +119,8 @@ An IRQ handler capability allows a thread possessing it to set an endpoint which
> invokeIRQHandler (ClearIRQHandler irq) = do
> irqSlot <- getIRQSlot irq
> cteDeleteOne irqSlot
> invokeIRQHandler (SetMode irq trig pol) =
> doMachineOp $ setInterruptMode irq trig pol
\subsection{Kernel Functions}

View file

@ -452,9 +452,9 @@ The "decodeInvocation" function parses the message, determines the operation tha
> liftM InvokeIRQControl $
> decodeIRQControlInvocation label args slot $ map fst extraCaps
>
> decodeInvocation label _ _ _ (IRQHandlerCap { capIRQ = irq }) extraCaps =
> decodeInvocation label args _ _ (IRQHandlerCap { capIRQ = irq }) extraCaps =
> liftM InvokeIRQHandler $
> decodeIRQHandlerInvocation label irq extraCaps
> decodeIRQHandlerInvocation label args irq extraCaps
>
> decodeInvocation label args capIndex slot (ArchObjectCap cap) extraCaps =
> liftM InvokeArchObject $

View file

@ -65,6 +65,7 @@ void setNextPC(tcb_t *thread, word_t v);
/* Architecture specific machine operations */
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline uint32_t getProcessorID(void)
{
uint32_t processor_id;
@ -72,6 +73,7 @@ static inline uint32_t getProcessorID(void)
return processor_id;
}
/** DONT_TRANSLATE */
static inline uint32_t readSystemControlRegister(void)
{
uint32_t scr;
@ -79,11 +81,13 @@ static inline uint32_t readSystemControlRegister(void)
return scr;
}
/** DONT_TRANSLATE */
static inline void writeSystemControlRegister(uint32_t scr)
{
MCR("p15, 0, %0, c1, c0, 0", scr);
}
/** DONT_TRANSLATE */
static inline uint32_t readAuxiliaryControlRegister(void)
{
uint32_t acr;
@ -91,12 +95,14 @@ static inline uint32_t readAuxiliaryControlRegister(void)
return acr;
}
/** DONT_TRANSLATE */
static inline void writeAuxiliaryControlRegister(uint32_t acr)
{
MCR("p15, 0, %0, c1, c0, 1", acr);
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void clearExMonitor(void)
{
word_t tmp;
@ -104,12 +110,14 @@ static inline void clearExMonitor(void)
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void flushBTAC(void)
{
asm volatile("mcr p15, 0, %0, c7, c5, 6" : : "r"(0));
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void writeContextID(word_t id)
{
#ifndef ARM_HYP
@ -137,6 +145,7 @@ void setHardwareASID(hw_asid_t hw_asid);
/* Address space control */
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void setCurrentPD(paddr_t addr)
{
#ifndef ARM_HYP
@ -203,6 +212,7 @@ static inline void setMAIR(word_t hmair0, word_t hmair1)
/* TLB control */
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void invalidateTLB(void)
{
dsb();
@ -212,6 +222,7 @@ static inline void invalidateTLB(void)
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void invalidateTLB_ASID(hw_asid_t hw_asid)
{
#ifdef ARM_HYP
@ -224,6 +235,7 @@ static inline void invalidateTLB_ASID(hw_asid_t hw_asid)
#endif
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void invalidateTLB_VAASID(word_t mva_plus_asid)
{
#ifdef ARM_HYP
@ -248,6 +260,7 @@ static inline void invalidateHypTLB(void)
void lockTLBEntry(vptr_t vaddr);
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void cleanByVA(vptr_t vaddr, paddr_t paddr)
{
#ifdef ARM_CORTEX_A8
@ -284,6 +297,7 @@ static inline void cleanByVA_PoU(vptr_t vaddr, paddr_t paddr)
}
/* D-Cache invalidate to PoC (v6/v7 common) */
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void invalidateByVA(vptr_t vaddr, paddr_t paddr)
{
#ifdef ARM_CORTEX_A8
@ -296,6 +310,7 @@ static inline void invalidateByVA(vptr_t vaddr, paddr_t paddr)
dmb();
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
/* I-Cache invalidate to PoU (L2 cache) (v6/v7 common) */
static inline void invalidateByVA_I(vptr_t vaddr, paddr_t paddr)
{
@ -308,6 +323,7 @@ static inline void invalidateByVA_I(vptr_t vaddr, paddr_t paddr)
isb();
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
/* I-Cache invalidate all to PoU (L2 cache) (v6/v7 common) */
static inline void invalidate_I_PoU(void)
{
@ -319,6 +335,7 @@ static inline void invalidate_I_PoU(void)
isb();
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
/* D-Cache clean & invalidate to PoC (v6/v7 common) */
static inline void cleanInvalByVA(vptr_t vaddr, paddr_t paddr)
{
@ -334,6 +351,7 @@ static inline void cleanInvalByVA(vptr_t vaddr, paddr_t paddr)
dsb();
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
/* Invalidate branch predictors by VA (v6/v7 common) */
static inline void branchFlush(vptr_t vaddr, paddr_t paddr)
{
@ -364,6 +382,7 @@ void cleanInvalidateL1Caches(void);
/* Fault status */
/** MODIFIES: */
/** DONT_TRANSLATE */
static inline word_t PURE getIFSR(void)
{
word_t IFSR;
@ -371,6 +390,7 @@ static inline word_t PURE getIFSR(void)
return IFSR;
}
/** MODIFIES: */
/** DONT_TRANSLATE */
static inline word_t PURE getDFSR(void)
{
word_t DFSR;
@ -378,6 +398,7 @@ static inline word_t PURE getDFSR(void)
return DFSR;
}
/** MODIFIES: */
/** DONT_TRANSLATE */
static inline word_t PURE getFAR(void)
{
word_t FAR;

View file

@ -33,6 +33,8 @@ bool_t isIRQPending(void);
void maskInterrupt(bool_t disable, interrupt_t irq);
/** MODIFIES: [*] */
void ackInterrupt(irq_t irq);
/** MODIFIES: [*] */
static inline void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow) { }
/** MODIFIES: [*] */
void initIRQController(void);

View file

@ -375,9 +375,9 @@ block vm_fault {
padding 2
field instructionFault 1
#else
field FSR 12
field FSR 14
field instructionFault 1
padding 16
padding 14
#endif
field faultType 3
}
@ -684,6 +684,7 @@ tagged_union pteS1 pteS1Type {
#endif /* !ARM_HYP */
-- VM attributes
block vm_attributes {
padding 30
field armParityEnabled 1

View file

@ -17,6 +17,7 @@
#include <plat/machine/hardware.h>
#include <arch/machine.h>
/** DONT_TRANSLATE */
static inline void dsb_fp(void)
{
/*
@ -31,6 +32,7 @@ static inline void dsb_fp(void)
}
/* Change the translation root by updating TTBR0. */
/** DONT_TRANSLATE */
static inline void
setCurrentPD_fp(word_t pd_addr)
{
@ -43,6 +45,7 @@ setCurrentPD_fp(word_t pd_addr)
}
/* Change the current hardware ASID. */
/** DONT_TRANSLATE */
static inline void
setHardwareASID_fp(hw_asid_t asid)
{

View file

@ -12,18 +12,21 @@
#define __ARCH_ARMV6_MACHINE_H
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void dsb(void)
{
asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r"(0) : "memory");
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void dmb(void)
{
asm volatile("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory");
}
/** MODIFIES: [*] */
/** DONT_TRANSLATE */
static inline void isb(void)
{
asm volatile("mcr p15, 0, %0, c7, c5, 4" : : "r"(0) : "memory");

View file

@ -17,7 +17,7 @@
#include <api/syscall.h>
void slowpath(syscall_t syscall)
VISIBLE FASTCALL NORETURN;
NORETURN;
void fastpath_call(word_t cptr, word_t r_msgInfo)
VISIBLE FASTCALL NORETURN;

View file

@ -24,6 +24,10 @@ bool_t map_kernel_window(
pde_t* pd,
pte_t* pt,
p_region_t ndks_p_reg
#ifdef CONFIG_IRQ_IOAPIC
, uint32_t num_ioapic,
paddr_t* ioapic_paddrs
#endif
#ifdef CONFIG_IOMMU
, uint32_t num_drhu,
paddr_t* drhu_list

View file

@ -55,7 +55,7 @@
/* maximum number of device regions in bootinfo */
/* WARNING: must match value in libsel4! */
#ifndef CONFIG_MAX_NUM_BOOTINFO_DEVICE_REGIONS
#define CONFIG_MAX_NUM_BOOTINFO_DEVICE_REGIONS 200
#define CONFIG_MAX_NUM_BOOTINFO_DEVICE_REGIONS 199
#endif
/* maximum number of untyped caps in bootinfo */

View file

@ -21,11 +21,12 @@ exception_t decodeIRQControlInvocation(word_t label, unsigned int length,
cte_t *srcSlot, extra_caps_t extraCaps,
word_t *buffer);
exception_t invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot);
exception_t decodeIRQHandlerInvocation(word_t label, irq_t irq,
extra_caps_t extraCaps);
exception_t decodeIRQHandlerInvocation(word_t label, unsigned int length, irq_t irq,
extra_caps_t extraCaps, word_t *buffer);
void invokeIRQHandler_AckIRQ(irq_t irq);
void invokeIRQHandler_SetIRQHandler(irq_t irq, cap_t cap, cte_t *slot);
void invokeIRQHandler_ClearIRQHandler(irq_t irq);
void invokeIRQHandler_SetMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow);
void deletingIRQHandler(irq_t irq);
void deletedIRQHandler(irq_t irq);
void handleInterrupt(irq_t irq);

View file

@ -72,6 +72,8 @@ void maskInterrupt(bool_t enable, irq_t irq);
/** MODIFIES: */
irq_t getActiveIRQ(void);
/** MODIFIES: [*] */
static inline void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow) { }
/** MODIFIES: [*] */
void resetTimer(void);
/** MODIFIES: [*] */
void initTimer(void);

View file

@ -73,6 +73,8 @@ void maskInterrupt(bool_t enable, irq_t irq);
/** MODIFIES: */
irq_t getActiveIRQ(void);
/** MODIFIES: [*] */
static inline void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow) { }
/** MODIFIES: [*] */
void resetTimer(void);
/** MODIFIES: [*] */
void initTimer(void);

View file

@ -72,6 +72,8 @@ void maskInterrupt(bool_t enable, irq_t irq);
/** MODIFIES: */
irq_t getActiveIRQ(void);
/** MODIFIES: [*] */
static inline void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow) { }
/** MODIFIES: [*] */
void resetTimer(void);
/** MODIFIES: [*] */
void initTimer(void);

View file

@ -11,37 +11,60 @@
#ifndef __PLAT_MACHINE_H
#define __PLAT_MACHINE_H
/* interrupt vectors (corresponds to IDT entries) */
#define PIC_IRQ_LINES 16
#define IOAPIC_IRQ_LINES 24
typedef enum _interrupt_t {
int_invalid = -1,
int_unimpl_dev = 0x07,
int_page_fault = 0x0e,
int_irq_min = 0x20, /* First IRQ. */
int_irq_isa_min = 0x20,
int_irq_isa_max = 0x2f,
int_irq_msi_min = 0x30,
int_irq_msi_max = 0x3d,
int_iommu = 0x3e,
int_timer = 0x3f,
int_irq_max = 0x3f, /* Last IRQ. */
int_trap_min = 0x40,
int_trap_max = 0xfe,
int_spurious = 0xff,
int_max = 0xff
} interrupt_t;
/* interrupt vectors (corresponds to IDT entries) */
#define IRQ_INT_OFFSET 0x20
typedef enum _interrupt_t {
int_invalid = -1,
int_unimpl_dev = 0x07,
int_page_fault = 0x0e,
int_irq_min = IRQ_INT_OFFSET, /* First IRQ. */
#ifdef CONFIG_IRQ_IOAPIC
int_irq_ioapic_min = int_irq_min,
int_irq_ioapic_max = (int_irq_ioapic_min + (CONFIG_MAX_NUM_IOAPIC * IOAPIC_IRQ_LINES)) - 1,
#else
int_irq_isa_min = int_irq_min,
int_irq_isa_max = int_irq_min + PIC_IRQ_LINES - 1,
#endif
int_irq_msi_min,
int_irq_msi_max = int_irq_msi_min + 0xd,
int_iommu,
int_timer,
int_irq_max = int_timer, /* Last IRQ. */
int_trap_min,
int_trap_max = 0xfe,
int_spurious = 0xff,
int_max = 0xff
} interrupt_t;
/* Construction of most of the interrupt numbers was relative by padding
* off previous values. Therefore to ensure we didn't overflow just need
* to ensure int_trap_min is less than int_trap_max */
compile_assert(interrupt_numbers_not_overflow, int_trap_min < int_trap_max);
typedef enum _irq_t {
irqInvalid = -1,
irq_isa_min = int_irq_isa_min - IRQ_INT_OFFSET, /* 0x00 */
irq_isa_max = int_irq_isa_max - IRQ_INT_OFFSET, /* 0x0f */
irq_msi_min = int_irq_msi_min - IRQ_INT_OFFSET, /* 0x10 */
irq_msi_max = int_irq_msi_max - IRQ_INT_OFFSET, /* 0x1d */
irq_iommu = int_iommu - IRQ_INT_OFFSET, /* 0x1e */
irq_timer = int_timer - IRQ_INT_OFFSET, /* 0x1f */
maxIRQ = int_timer - IRQ_INT_OFFSET /* 0x1f */
#ifdef CONFIG_IRQ_IOAPIC
irq_ioapic_min = int_irq_ioapic_min - IRQ_INT_OFFSET,
irq_controller_min = irq_ioapic_min,
irq_ioapic_max = int_irq_ioapic_max - IRQ_INT_OFFSET,
irq_controller_max = irq_ioapic_max,
#else
irq_isa_min = int_irq_isa_min - IRQ_INT_OFFSET,
irq_controller_min = irq_isa_min,
irq_isa_max = int_irq_isa_max - IRQ_INT_OFFSET,
irq_controller_max = irq_isa_max,
#endif
irq_msi_min = int_irq_msi_min - IRQ_INT_OFFSET,
irq_msi_max = int_irq_msi_max - IRQ_INT_OFFSET,
irq_iommu = int_iommu - IRQ_INT_OFFSET,
irq_timer = int_timer - IRQ_INT_OFFSET,
maxIRQ = int_timer - IRQ_INT_OFFSET
} irq_t;
#define BIOS_PADDR_START 0x0e0000

View file

@ -42,7 +42,9 @@ acpi_rsdt_t* acpi_init(void);
uint32_t acpi_madt_scan(
acpi_rsdt_t* acpi_rsdt,
cpu_id_t* cpu_list,
uint32_t max_list_len
uint32_t max_list_len,
uint32_t* num_ioapic,
paddr_t* ioapic_addrs
);
#ifdef CONFIG_IOMMU

View file

@ -16,8 +16,17 @@
#define PPTR_APIC PPTR_KDEV
#ifdef CONFIG_IOMMU
/* Whether the IOAPIC exists or not will determine where we start mapping
* the IOMMUs. It is fine to define the DRHU_START even if CONFIG_IOMMU is not
* set as it will just pollute the preprocessor namespace */
#ifdef CONFIG_IRQ_IOAPIC
#define PPTR_IOAPIC_START (PPTR_APIC + BIT(PAGE_BITS))
#define PPTR_DRHU_START (PPTR_IOAPIC_START + BIT(PAGE_BITS) * CONFIG_MAX_NUM_IOAPIC)
#else /* CONFIG_IOAPIC */
#define PPTR_DRHU_START (PPTR_APIC + BIT(PAGE_BITS))
#endif /* CONFIG_IOAPIC */
#ifdef CONFIG_IOMMU
#define MAX_NUM_DRHU ((-PPTR_DRHU_START) >> PAGE_BITS)
#endif

View file

@ -62,6 +62,7 @@ void maskInterrupt(bool_t mask, irq_t irq);
void ackInterrupt(irq_t irq);
irq_t getActiveIRQ(void);
bool_t isIRQPending(void);
void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow);
void resetTimer(void);
void platAddDevices(void);

View file

@ -0,0 +1,26 @@
/*
* Copyright 2014, General Dynamics C4 Systems
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(GD_GPL)
*/
#ifndef __PLAT_MACHINE_IOAPIC_H
#define __PLAT_MACHINE_IOAPIC_H
#ifdef CONFIG_IRQ_IOAPIC
#include <types.h>
#include <plat/machine.h>
#include <arch/types.h>
void ioapic_init(uint32_t num_nodes, cpu_id_t *cpu_list, uint32_t num_ioapic);
void ioapic_mask_irq(bool_t mask, irq_t irq);
void ioapic_set_mode(irq_t irq, bool_t levelTrigger, bool_t polarityLow);
#endif
#endif

View file

@ -14,9 +14,17 @@
#include <types.h>
#include <plat/machine.h>
/* Even if not using the PIC as the main interrupt controller we still
* need to interact with it to remap and disable it */
void pic_remap_irqs(interrupt_t vector);
void pic_disable(void);
#ifdef CONFIG_IRQ_PIC
void pic_mask_irq(bool_t mask, irq_t irq);
bool_t pic_is_irq_pending(void);
void pic_ack_active_irq(void);
#endif
#endif

View file

@ -29,8 +29,16 @@
* programming the device */
#define IRQ_OFFSET 0x20
/* Range for MSI irqs */
/* Range for MSI irqs. Currently no proper way of getting at the corresponding
* definition inside seL4, but the vector table is setup such that MSIs start
* after all the IRQs for the external interrupt controller (PIC or IOAPIC).
* PIC has 0x10 lines and for the IOAPIC there are 24 for each IOAPIC */
#ifdef CONFIG_IRQ_IOAPIC
#define MSI_MIN (24 * CONFIG_MAX_NUM_IOAPIC)
#define MSI_MAX (MSI_MIN + 0xd)
#else
#define MSI_MIN 0x10
#define MSI_MAX 0x1d
#endif
#endif

View file

@ -145,6 +145,10 @@
<param dir="in" name="endpoint" type="seL4_CPtr"/>
</method>
<method id="IRQClearIRQHandler" name="Clear"/>
<method id="IRQSetMode" name="SetMode">
<param dir="in" name="level_trigger" type="uint32_t"/>
<param dir="in" name="low_polarity" type="uint32_t"/>
</method>
</interface>
<interface name="seL4_DomainSet">
<method id="DomainSetSet" name="Set">

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
#
# Copyright 2014, NICTA
#

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
#
# Copyright 2014, NICTA
#

View file

@ -10,6 +10,7 @@
#include <arch/machine/hardware.h>
/** DONT_TRANSLATE */
void
clean_D_PoU(void)
{
@ -17,6 +18,7 @@ clean_D_PoU(void)
asm volatile("mcr p15, 0, %0, c7, c10, 0" : : "r"(0));
}
/** DONT_TRANSLATE */
void
cleanInvalidate_D_PoC(void)
{

View file

@ -75,6 +75,7 @@ lookup_fp(cap_t cap, cptr_t cptr)
return cap;
}
/** DONT_TRANSLATE */
static inline void
clearExMonitor_fp(void)
{

View file

@ -446,6 +446,12 @@ try_init_kernel(
return false;
}
/* Before creating the initial thread (which also switches to it)
* we clean the cache so that any page table information written
* as a result of calling create_frames_of_region will be correctly
* read by the hardware page table walker */
cleanInvalidateL1Caches();
/* create the initial thread */
if (!create_initial_thread(
root_cnode_cap,

View file

@ -2096,11 +2096,13 @@ decodeARMFrameInvocation(word_t label, unsigned int length,
}
}
static const resolve_ret_t default_resolve_ret_t;
static resolve_ret_t
resolveVAddr(pde_t *pd, vptr_t vaddr)
{
pde_t *pde = lookupPDSlot(pd, vaddr);
resolve_ret_t ret;
resolve_ret_t ret = default_resolve_ret_t;
ret.valid = true;

View file

@ -15,6 +15,8 @@ include ${SOURCE_ROOT}/src/arch/$(ARCH)/model/Makefile
include ${SOURCE_ROOT}/src/arch/$(ARCH)/machine/Makefile
include ${SOURCE_ROOT}/src/arch/$(ARCH)/fastpath/Makefile
ARCH_C_SOURCES += c_traps.c
ARCH_ASM_SOURCES += machine_asm.S \
traps.S \
halt.S \

171
src/arch/ia32/c_traps.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright 2014, General Dynamics C4 Systems
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(GD_GPL)
*/
#include <config.h>
#include <model/statedata.h>
#include <arch/kernel/lock.h>
#include <arch/machine/fpu.h>
#include <arch/fastpath/fastpath.h>
#include <api/syscall.h>
void __attribute__((noreturn)) __attribute__((externally_visible)) restore_user_context(void);
void __attribute__((noreturn)) __attribute__((externally_visible)) restore_user_context(void)
{
/* set the tss.esp0 */
tss_ptr_set_esp0(&ia32KStss, ((uint32_t)ksCurThread) + 0x4c);
if (unlikely(ksCurThread == ia32KSfpuOwner)) {
/* We are using the FPU, make sure it is enabled */
enableFpu();
} else if (unlikely(ia32KSfpuOwner)) {
/* Someone is using the FPU and it might be enabled */
disableFpu();
} else {
/* No-one (including us) is using the FPU, so we assume it
* is currently disabled */
}
/* see if we entered via syscall */
if (likely(ksCurThread->tcbContext.registers[Error] == -1)) {
ksCurThread->tcbContext.registers[EFLAGS] &= ~0x200;
asm volatile(
// Set our stack pointer to the top of the tcb so we can efficiently pop
"movl %0, %%esp\n"
// restore syscall number
"popl %%eax\n"
// cap/badge reigster
"popl %%ebx\n"
// skip ecx and edx, these will contain esp and nexteip due to sysenter/sysexit convention
"addl $8, %%esp\n"
// message info register
"popl %%esi\n"
// message register
"popl %%edi\n"
// message register
"popl %%ebp\n"
//ds (if changed)
"cmpl $0x23, (%%esp)\n"
"je 1f\n"
"popl %%ds\n"
"jmp 2f\n"
"1: addl $4, %%esp\n"
"2:\n"
//es (if changed)
"cmpl $0x23, (%%esp)\n"
"je 1f\n"
"popl %%es\n"
"jmp 2f\n"
"1: addl $4, %%esp\n"
"2:\n"
//have to reload other selectors
"popl %%fs\n"
"popl %%gs\n"
// skip faulteip, tls_base and error (these are fake registers)
"addl $12, %%esp\n"
// restore nexteip
"popl %%edx\n"
// skip cs
"addl $4, %%esp\n"
"popfl\n"
// reset interrupt bit
"orl $0x200, -4(%%esp)\n"
// restore esp
"pop %%ecx\n"
"sti\n"
"sysexit\n"
:
: "r"(&ksCurThread->tcbContext.registers[EAX])
// Clobber memory so the compiler is forced to complete all stores
// before running this assembler
: "memory"
);
} else {
asm volatile(
// Set our stack pointer to the top of the tcb so we can efficiently pop
"movl %0, %%esp\n"
"popl %%eax\n"
"popl %%ebx\n"
"popl %%ecx\n"
"popl %%edx\n"
"popl %%esi\n"
"popl %%edi\n"
"popl %%ebp\n"
"popl %%ds\n"
"popl %%es\n"
"popl %%fs\n"
"popl %%gs\n"
// skip faulteip, tls_base, error
"addl $12, %%esp\n"
"iret\n"
:
: "r"(&ksCurThread->tcbContext.registers[EAX])
// Clobber memory so the compiler is forced to complete all stores
// before running this assembler
: "memory"
);
}
while (1);
}
void __attribute__((fastcall)) __attribute__((externally_visible)) c_handle_interrupt(int irq, int syscall);
void __attribute__((fastcall)) __attribute__((externally_visible)) c_handle_interrupt(int irq, int syscall)
{
if (irq == int_unimpl_dev) {
handleUnimplementedDevice();
} else if (irq == int_page_fault) {
/* Error code is in Error. Pull out bit 5, which is whether it was instruction or data */
handleVMFaultEvent((ksCurThread->tcbContext.registers[Error] >> 4) & 1);
} else if (irq < int_irq_min) {
handleUserLevelFault(irq, ksCurThread->tcbContext.registers[Error]);
} else if (likely(irq < int_trap_min)) {
ia32KScurInterrupt = irq;
handleInterruptEntry();
} else if (irq == int_spurious) {
/* fall through to restore_user_context and do nothing */
} else {
/* Interpret a trap as an unknown syscall */
/* Adjust FaultEIP to point to trapping INT
* instruction by subtracting 2 */
int sys_num;
ksCurThread->tcbContext.registers[FaultEIP] -= 2;
/* trap number is MSBs of the syscall number and the LSBS of EAX */
sys_num = (irq << 24) | (syscall & 0x00ffffff);
handleUnknownSyscall(sys_num);
}
restore_user_context();
}
void __attribute__((noreturn))
slowpath(syscall_t syscall)
{
ia32KScurInterrupt = -1;
/* increment nextEIP to skip sysenter */
ksCurThread->tcbContext.registers[NextEIP] += 2;
/* check for undefined syscall */
if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) {
handleUnknownSyscall(syscall);
} else {
handleSyscall(syscall);
}
restore_user_context();
}
void __attribute__((externally_visible)) c_handle_syscall(syscall_t syscall, word_t cptr, word_t msgInfo);
void __attribute__((externally_visible)) c_handle_syscall(syscall_t syscall, word_t cptr, word_t msgInfo)
{
#ifdef FASTPATH
if (syscall == SysCall) {
fastpath_call(cptr, msgInfo);
} else if (syscall == SysReplyWait) {
fastpath_reply_wait(cptr, msgInfo);
}
#endif
slowpath(syscall);
}

View file

@ -34,19 +34,24 @@ extern uint32_t kernel_pd_list[CONFIG_MAX_NUM_NODES][BIT(PD_BITS)];
/* functions exactly corresponding to abstract specification */
BOOT_CODE static void
init_irqs(cap_t root_cnode_cap, bool_t mask_legacy_irqs)
init_irqs(cap_t root_cnode_cap, bool_t mask_irqs)
{
irq_t i;
for (i = 0; i <= maxIRQ; i++) {
if (i == irq_timer) {
setIRQState(IRQTimer, i);
} else if (i == irq_iommu || i == 2 /* cascaded legacy PIC */) {
} else if (i == irq_iommu) {
setIRQState(IRQReserved, i);
} else if (i >= irq_isa_min && i <= irq_isa_max)
if (mask_legacy_irqs)
#ifdef CONFIG_IRQ_PIC
} else if (i == 2) {
/* cascaded legacy PIC */
setIRQState(IRQReserved, i);
#endif
} else if (i >= irq_controller_min && i <= irq_controller_max)
if (mask_irqs)
/* Don't use setIRQState() here because it implicitly also enables */
/* the IRQ on the PIC which only node 0 is allowed to do. */
/* the IRQ on the interrupt controller which only node 0 is allowed to do. */
{
intStateIRQTable[i] = IRQReserved;
} else {

View file

@ -23,6 +23,7 @@
#include <plat/machine/devices.h>
#include <plat/machine/pci.h>
#include <plat/machine/pic.h>
#include <plat/machine/ioapic.h>
/* addresses defined in linker script */
/* need a fake array to get the pointer from the linker script */
@ -70,6 +71,8 @@ typedef struct glks {
ui_info_t ui_info_list [CONFIG_MAX_NUM_NODES]; /* info about userland images */
dev_p_regs_t dev_p_regs; /* device memory regions */
uint32_t apic_khz; /* frequency of APIC/bus */
uint32_t num_ioapic; /* number of IOAPICs detected */
paddr_t ioapic_paddr[CONFIG_MAX_NUM_IOAPIC];
#ifdef CONFIG_IOMMU
uint32_t num_drhu; /* number of IOMMUs */
paddr_t drhu_list[MAX_NUM_DRHU]; /* list of physical addresses of the IOMMUs */
@ -293,6 +296,10 @@ lift_ndks(node_id_t node_id)
(pde_t*)kernel_pd_list[node_id],
(pte_t*)kernel_pt_list[node_id],
ndks_p_reg
#ifdef CONFIG_IRQ_IOAPIC
, glks.num_ioapic,
glks.ioapic_paddr
#endif
#ifdef CONFIG_IOMMU
, node_id == 0 ? glks.num_drhu : 0,
glks.drhu_list
@ -362,7 +369,11 @@ try_boot_node(void)
/* initialise the CPU */
if (!init_node_cpu(
glks.apic_khz,
#ifdef CONFIG_IRQ_IOAPIC
1
#else
node_id != 0
#endif
)) {
return false;
}
@ -464,6 +475,11 @@ try_boot_sys(
/* remapping legacy IRQs to their correct vectors */
pic_remap_irqs(IRQ_INT_OFFSET);
#ifdef CONFIG_IRQ_IOAPIC
/* Disable the PIC so that it does not generate any interrupts. We need to
* do this *before* we initialize the apic */
pic_disable();
#endif
/* Prepare for accepting device regions from here on */
glks.dev_p_regs.count = 0;
@ -492,11 +508,21 @@ try_boot_sys(
#endif
/* query available CPUs from ACPI */
glks.num_nodes = acpi_madt_scan(acpi_rsdt, glks.cpu_list, CONFIG_MAX_NUM_NODES);
glks.num_nodes = acpi_madt_scan(acpi_rsdt, glks.cpu_list, CONFIG_MAX_NUM_NODES, &glks.num_ioapic, glks.ioapic_paddr);
if (glks.num_nodes == 0) {
printf("No CPUs detected\n");
return false;
}
#ifdef CONFIG_IRQ_IOAPIC
if (glks.num_ioapic == 0) {
printf("No IOAPICs detected\n");
return false;
}
#else
if (glks.num_ioapic > 0) {
printf("Detected %d IOAPICs, but configured to use PIC instead\n", glks.num_ioapic);
}
#endif
if (glks.num_nodes > cmdline_opt.max_num_nodes) {
glks.num_nodes = cmdline_opt.max_num_nodes;
@ -603,6 +629,11 @@ try_boot_sys(
return false;
}
#ifdef CONFIG_IRQ_IOAPIC
/* Now that NDKS have been lifted we can access the IOAPIC and program it */
ioapic_init(glks.num_nodes, glks.cpu_list, glks.num_ioapic);
#endif
/* start up other CPUs and initialise their nodes */
for (i = 1; i < glks.num_nodes; i++) {
printf("Starting node #%d\n", i);

View file

@ -575,6 +575,10 @@ map_kernel_window(
pde_t* pd,
pte_t* pt,
p_region_t ndks_p_reg
#ifdef CONFIG_IRQ_IOAPIC
, uint32_t num_ioapic,
paddr_t* ioapic_paddrs
#endif
#ifdef CONFIG_IOMMU
, uint32_t num_drhu,
paddr_t* drhu_list
@ -585,9 +589,7 @@ map_kernel_window(
uint32_t idx;
pde_t pde;
pte_t pte;
#ifdef CONFIG_IOMMU
unsigned int i;
#endif
unsigned int UNUSED i;
/* Mapping of PPTR_BASE (virtual address) to kernel's PADDR_BASE
* up to end of virtual address space except for the last 4M.
@ -730,6 +732,49 @@ map_kernel_window(
pt[idx] = pte;
idx++;
#ifdef CONFIG_IRQ_IOAPIC
for (i = 0; i < num_ioapic; i++) {
phys = ioapic_paddrs[i];
pte = pte_new(
phys, /* page_base_address */
0, /* avl */
1, /* global */
0, /* pat */
0, /* dirty */
0, /* accessed */
1, /* cache_disabled */
1, /* write_through */
0, /* super_user */
1, /* read_write */
1 /* present */
);
assert(idx == ( (PPTR_IOAPIC_START + i * BIT(pageBitsForSize(IA32_4K))) & MASK(pageBitsForSize(IA32_4M))) >> pageBitsForSize(IA32_4K));
pt[idx] = pte;
idx++;
if (idx == BIT(PT_BITS)) {
return false;
}
}
/* put in null mappings for any extra IOAPICs */
for (; i < CONFIG_MAX_NUM_IOAPIC; i++) {
pte = pte_new(
0, /* page_base_address */
0, /* avl */
0, /* global */
0, /* pat */
0, /* dirty */
0, /* accessed */
0, /* cache_disabled */
0, /* write_through */
0, /* super_user */
0, /* read_write */
0 /* present */
);
assert(idx == ( (PPTR_IOAPIC_START + i * BIT(pageBitsForSize(IA32_4K))) & MASK(pageBitsForSize(IA32_4M))) >> pageBitsForSize(IA32_4K));
pt[idx] = pte;
idx++;
}
#endif
#ifdef CONFIG_IOMMU
/* map kernel devices: IOMMUs */

View file

@ -91,6 +91,8 @@ Arch_initFpu(void)
/* Enable FPU / SSE / SSE2 / SSE3 / SSSE3 / SSE4 Extensions. */
write_cr4(read_cr4() | CR4_OSFXSR);
/* Enable the FPU in general. */
write_cr0((read_cr0() & ~CR0_EMULATION) | CR0_MONITOR_COPROC | CR0_NUMERIC_ERROR);
/* Enable the FPU in general. Although leave it in a state where it will
* generate a fault if someone tries to use it as we implement lazy
* switching */
write_cr0((read_cr0() & ~CR0_EMULATION) | CR0_MONITOR_COPROC | CR0_NUMERIC_ERROR | CR0_TASK_SWITCH);
}

View file

@ -9,9 +9,6 @@
*/
#include <machine/assembler.h>
#include <arch/api/syscall.h>
# minimum and maximum seL4 syscall number
# On kernel entry, ESP points to the end of the thread's registers array.
# Hardware pushes onto the stack SS, ESP, EFLAGS, CS, NextEIP and Error,
@ -349,70 +346,14 @@ handle_interrupt:
andb %bl, %dl # we have a kernel exception if both BL and DL are 1
jnz kernel_exception
# save ESP (which now points to the current TCB)
movl %esp, %edx
# save ECX (which contains the interrupt vector)
movl %ecx, ia32KScurInterrupt
# switch to kernel stack
leal _kernel_stack_top, %esp
# the code below assumes:
# - EAX contains the syscall number
# - ECX contains the interrupt vector
# - EDX contains the current TCB
# Place the syscall number in the second argument slot
movl %eax, %edx
# depending on the interrupt vector, call appropriate handling function
cmpl $0x07, %ecx # 0x07 = int_unimpl_dev
je handle_unimplemented_device
cmpl $0x0e, %ecx # 0x0e = int_page_fault
je handle_page_fault
cmpl $0x20, %ecx # 0x20 = int_irq_isa_min
jb handle_fault
cmpl $0x50, %ecx # 0x50 = int_trap_min
jb handle_IRQ
cmpl $0xff, %ecx # 0xff = int_spurious
je restore_user_context # ignore and do not ack spurious interrupt
# Here we know we have a trap. It is interpreted as unknown syscall.
# We have to adjust the FaultEIP to point to the trapping INT instruction
# by subtracting 2. EDX contains the current TCB.
subl $2, 0x2c(%edx)
# The trap number is stored in the MSB and the 24-bit syscall number
# in the LSBs of EAX.
shll $24, %ecx
andl $0x00ffffff, %eax
orl %ecx, %eax
jmp undefined_syscall
handle_fault:
# fault code corresponds to error code of the exception
pushl 0x34(%edx) # push Error
# fault number corresponds to exception vector number
pushl %ecx
call handleUserLevelFault
addl $8, %esp
jmp restore_user_context
handle_page_fault:
movl 0x34(%edx), %edx # get Error code from TCB
shrl $4, %edx # get I/D flag
andl $1, %edx # mask rest of error code
pushl %edx # vm_fault_type_t (0 = data, 1 = instruction)
call handleVMFaultEvent
addl $4, %esp
jmp restore_user_context
handle_unimplemented_device:
call handleUnimplementedDevice
jmp restore_user_context
handle_IRQ:
call handleInterruptEntry
jmp restore_user_context
# gtfo to C land, we will not return
call c_handle_interrupt
# Handle a kernel exception
@ -444,27 +385,6 @@ BEGIN_FUNC(kernel_exception)
jmp halt
END_FUNC(kernel_exception)
#ifdef FASTPATH
# Calls the slowpath from the fastpath
# Defined with fastcall calling convention
BEGIN_FUNC(slowpath)
# indicate int_invalid as the interrupt currently being served
movl $-1, ia32KScurInterrupt
# syscall is in ECX
pushl %ecx
# Update NextEIP
movl ksCurThread, %ecx
addl $2, 56(%ecx)
call handleSyscall
jmp restore_user_context
END_FUNC(slowpath)
#endif
#define SET_SEL(sel, offset, val) \
cmpl $val, (offset)(%esp); \
je 1f; \
@ -507,131 +427,15 @@ BEGIN_FUNC(handle_syscall)
SET_SEL(ds, 7 * 4, 0x23)
SET_SEL(es, 8 * 4, 0x23)
# Perform this comparison as soon as we stop doing operations that clobber the FLAGS
#ifdef FASTPATH
cmpl $SYSCALL_REPLY_WAIT, %eax
#endif
# switch to kernel stack
leal _kernel_stack_top, %esp
#ifdef FASTPATH
# Shuffle some register to suit the fastcall calling convention
movl %ebx, %ecx
movl %esi, %edx
je fastpath_reply_wait
cmpl $SYSCALL_CALL, %eax
je fastpath_call
#endif
# Push all the arguments for c_handle_syscall
pushl %esi # msgInfo
pushl %ebx # cptr
pushl %eax # syscall number
# indicate int_invalid as the interrupt currently being served
movl $-1, ia32KScurInterrupt
# gtfo to C land, we will not return
call c_handle_syscall
# increment NextEIP
movl ksCurThread, %ecx
addl $2, 56(%ecx)
# check that syscall number is in range
cmpl $SYSCALL_MAX, %eax
jg undefined_syscall
cmpl $SYSCALL_MIN, %eax
jl undefined_syscall
# we have a seL4 syscall
pushl %eax
call handleSyscall
jmp restore_user_context
undefined_syscall:
pushl %eax
call handleUnknownSyscall
# fall through to restore_user_context
END_FUNC(handle_syscall)
#define POP_SEL(sel, val) \
cmpl $val, (%esp); \
je 1f; \
popl %sel; \
jmp 2f; \
1: \
addl $4, %esp; \
2:
BEGIN_FUNC(restore_user_context)
# save kernel ESP to TSS for next kernel entry
movl ksCurThread, %esp # point ESP to current user_context_t
addl $0x4c, %esp # size of registers array (0x4c bytes)
leal ia32KStss, %ecx
movl %esp, 4(%ecx) # tss.esp0 = pointer to end of thread's registers array
subl $0x4c, %esp # restore ESP to point to current TCB
# disable the FPU, unless owned by the current thread
cmpl %esp, ia32KSfpuOwner
je fpu_enable
movl %cr0, %eax
orl $0x8, %eax
movl %eax, %cr0
fpu_done:
# determine whether we entered via interrupt or syscall
cmpl $-1, 0x34(%esp) # if (Error == -1)
je restore_syscall
# we entered via interrupt, i.e. we return via iret
# precondition: ESP == ksCurThread
popl %eax
popl %ebx
popl %ecx
popl %edx
popl %esi
popl %edi
popl %ebp
popl %ds
popl %es
popl %fs
popl %gs
addl $4, %esp # skip FaultEIP
addl $4, %esp # skip TLS_BASE
addl $4, %esp # skip the error code
iret
fpu_enable:
clts
jmp fpu_done
restore_syscall:
# we entered via sysenter, i.e. we return via sysexit
# precondition: ESP == ksCurThread
popl %eax # restore EAX (syscall number)
popl %ebx # restore EBX (cap/badge register)
addl $8, %esp # skip ECX and EDX (will contain ESP and NextEIP)
popl %esi # restore ESI (msgInfo register)
popl %edi # restore EDI (message register)
popl %ebp # restore EBP (message register)
# Only pop the code and data selectors if their values have changed from the default
POP_SEL(ds, 0x23)
POP_SEL(es, 0x23)
# Have to reload fs and gs for update to the selectors to become visible
popl %fs
popl %gs
addl $4, %esp # skip FaultEIP
addl $4, %esp # skip TLS_BASE
addl $4, %esp # skip Error
popl %edx # restore NextEIP (passed in EDX)
addl $4, %esp # skip CS
andl $~0x200, (%esp) # clear interrupt bit before popping into EFLAGS
popfl # restore EFLAGS with interrupts off
orl $0x200, -4(%esp) # set interrupt bit again
popl %ecx # restore ESP (passed in ECX)
# skip SS
# We have following register contents when returning:
# EAX : syscall number (needed to restart syscall)
# ECX : user ESP
# EDX : user NextEIP
sti # now enable the interrupts, which were disabled
# by sysenter (will be enabled AFTER sysexit)
sysexit # return to user space
END_FUNC(restore_user_context)

View file

@ -90,8 +90,8 @@ invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot)
}
exception_t
decodeIRQHandlerInvocation(word_t label, irq_t irq,
extra_caps_t extraCaps)
decodeIRQHandlerInvocation(word_t label, unsigned int length, irq_t irq,
extra_caps_t extraCaps, word_t *buffer)
{
switch (label) {
case IRQAckIRQ:
@ -131,6 +131,21 @@ decodeIRQHandlerInvocation(word_t label, irq_t irq,
setThreadState(ksCurThread, ThreadState_Restart);
invokeIRQHandler_ClearIRQHandler(irq);
return EXCEPTION_NONE;
case IRQSetMode: {
bool_t trig, pol;
if (length < 2) {
userError("IRQSetMode: Not enough arguments", length);
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
trig = getSyscallArg(0, buffer);
pol = getSyscallArg(1, buffer);
setThreadState(ksCurThread, ThreadState_Restart);
invokeIRQHandler_SetMode(irq, !!trig, !!pol);
return EXCEPTION_NONE;
}
default:
userError("IRQHandler: Illegal operation.");
@ -145,6 +160,11 @@ invokeIRQHandler_AckIRQ(irq_t irq)
maskInterrupt(false, irq);
}
void invokeIRQHandler_SetMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow)
{
setInterruptMode(irq, levelTrigger, polarityLow);
}
void
invokeIRQHandler_SetIRQHandler(irq_t irq, cap_t cap, cte_t *slot)
{

View file

@ -668,8 +668,8 @@ decodeInvocation(word_t label, unsigned int length,
extraCaps, buffer);
case cap_irq_handler_cap:
return decodeIRQHandlerInvocation(label,
cap_irq_handler_cap_get_capIRQ(cap), extraCaps);
return decodeIRQHandlerInvocation(label, length,
cap_irq_handler_cap_get_capIRQ(cap), extraCaps, buffer);
default:
fail("Invalid cap type");

View file

@ -22,6 +22,7 @@
/* Available physical memory regions on platform (RAM) */
/* NOTE: Regions are not allowed to be adjacent! */
/* and must be page-aligned */
const p_region_t BOOT_RODATA avail_p_regs[] = {
/* 2 GiB -1 page to prevent uin32_t overflow */
{ /* .start = */ 0x80000000, /* .end = */ 0xfffff000 }
@ -38,7 +39,10 @@ get_avail_p_reg(unsigned int i)
{
return avail_p_regs[i];
}
/*
* We're limited to one page of boot data.
* Exclude some devices.
*/
const p_region_t BOOT_RODATA dev_p_regs[] = {
{ /* .start */ RPM_PADDR , /* .end */ RPM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ RPM_TIMERS_PADDR , /* .end */ RPM_TIMERS_PADDR + (1 << PAGE_BITS) },
@ -145,27 +149,49 @@ const p_region_t BOOT_RODATA dev_p_regs[] = {
{ /* .start */ SIC_APU_PADDR , /* .end */ SIC_APU_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SIC_NON_SECURE_PADDR , /* .end */ SIC_NON_SECURE_PADDR + (1 << PAGE_BITS) },
{ /* .start */ INTCTL0_PADDR , /* .end */ INTCTL0_PADDR + (1 << PAGE_BITS) },
#if (INTCTL1_PADDR & 0xfff) == 0
{ /* .start */ INTCTL1_PADDR , /* .end */ INTCTL1_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL2_PADDR & 0xfff) == 0
{ /* .start */ INTCTL2_PADDR , /* .end */ INTCTL2_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL3_PADDR & 0xfff) == 0
{ /* .start */ INTCTL3_PADDR , /* .end */ INTCTL3_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL4_PADDR & 0xfff) == 0
{ /* .start */ INTCTL4_PADDR , /* .end */ INTCTL4_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL5_PADDR & 0xfff) == 0
{ /* .start */ INTCTL5_PADDR , /* .end */ INTCTL5_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL6_PADDR & 0xfff) == 0
{ /* .start */ INTCTL6_PADDR , /* .end */ INTCTL6_PADDR + (1 << PAGE_BITS) },
#endif
#if (INTCTL7_PADDR & 0xfff) == 0
{ /* .start */ INTCTL7_PADDR , /* .end */ INTCTL7_PADDR + (1 << PAGE_BITS) },
#endif
{ /* .start */ SDC2_PADDR , /* .end */ SDC2_PADDR + (1 << PAGE_BITS) },
#if (SDC2_DML_PADDR & 0xfff) == 0
{ /* .start */ SDC2_DML_PADDR , /* .end */ SDC2_DML_PADDR + (1 << PAGE_BITS) },
#endif
{ /* .start */ SDC2_BAM_PADDR , /* .end */ SDC2_BAM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SDC3_PADDR , /* .end */ SDC3_PADDR + (1 << PAGE_BITS) },
#if (SDC3_DML_PADDR & 0xfff) == 0
{ /* .start */ SDC3_DML_PADDR , /* .end */ SDC3_DML_PADDR + (1 << PAGE_BITS) },
#endif
{ /* .start */ SDC3_BAM_PADDR , /* .end */ SDC3_BAM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SDC4_PADDR , /* .end */ SDC4_PADDR + (1 << PAGE_BITS) },
#if (SDC4_DML_PADDR & 0xfff) == 0
{ /* .start */ SDC4_DML_PADDR , /* .end */ SDC4_DML_PADDR + (1 << PAGE_BITS) },
#endif
{ /* .start */ SDC4_BAM_PADDR , /* .end */ SDC4_BAM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ BAM_DMA_PADDR , /* .end */ BAM_DMA_PADDR + (1 << PAGE_BITS) },
{ /* .start */ BAM_DMA_BAM_PADDR , /* .end */ BAM_DMA_BAM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ BAM_DMA_BAM_XPU_PADDR , /* .end */ BAM_DMA_BAM_XPU_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SDC1_PADDR , /* .end */ SDC1_PADDR + (1 << PAGE_BITS) },
#if (SDC1_DML_PADDR & 0xfff) == 0
{ /* .start */ SDC1_DML_PADDR , /* .end */ SDC1_DML_PADDR + (1 << PAGE_BITS) },
#endif
{ /* .start */ SDC1_BAM_PADDR , /* .end */ SDC1_BAM_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SPS_GSBI1_PADDR , /* .end */ SPS_GSBI1_PADDR + (1 << PAGE_BITS) },
{ /* .start */ SPS_UART1_DM_PADDR , /* .end */ SPS_UART1_DM_PADDR + (1 << PAGE_BITS) },

View file

@ -22,3 +22,30 @@ config IOMMU
default y
help
IOMMU support for VT-d enabled chipset
choice
prompt "IRQ Controller"
depends on ARCH_IA32
default IRQ_PIC
help
Select the IRQ controller seL4 will use. Code for others may
still be included if needed to disable at run time
config IRQ_PIC
bool "PIC"
help
Use the legacy PIC controller
config IRQ_IOAPIC
bool "IOAPIC"
help
Use one or more IOAPIC controllers
endchoice
config MAX_NUM_IOAPIC
prompt "Max supported IOAPICs"
depends on ARCH_IA32
int
default 1
help
Configure the maximum number of IOAPIC controllers that can
be supported. SeL4 will detect IOAPICs regardless of whether
the IOAPIC will actually be used as the final IRQ controller

View file

@ -14,6 +14,7 @@ PLAT_C_SOURCES += machine/acpi.c \
machine/hardware.c \
machine/pci.c \
machine/pic.c \
machine/ioapic.c \
machine/pit.c \
machine/io.c
ifdef DEBUG

View file

@ -256,7 +256,9 @@ BOOT_CODE uint32_t
acpi_madt_scan(
acpi_rsdt_t* acpi_rsdt,
cpu_id_t* cpu_list,
uint32_t max_list_len
uint32_t max_list_len,
uint32_t* num_ioapic,
paddr_t* ioapic_paddrs
)
{
unsigned int entries;
@ -270,6 +272,7 @@ acpi_madt_scan(
acpi_rsdt_mapped = (acpi_rsdt_t*)acpi_table_init(acpi_rsdt, ACPI_RSDT);
num_cpu = 0;
*num_ioapic = 0;
assert(acpi_rsdt_mapped->header.length >= sizeof(acpi_header_t));
entries = (acpi_rsdt_mapped->header.length - sizeof(acpi_header_t)) / sizeof(acpi_header_t*);
@ -307,6 +310,19 @@ acpi_madt_scan(
((acpi_madt_ioapic_t*)acpi_madt_header)->ioapic_addr,
((acpi_madt_ioapic_t*)acpi_madt_header)->gsib
);
if (*num_ioapic == CONFIG_MAX_NUM_IOAPIC) {
printf("ACPI: Not recording this IOAPIC, only support %d\n", CONFIG_MAX_NUM_IOAPIC);
} else {
ioapic_paddrs[*num_ioapic] = ((acpi_madt_ioapic_t*)acpi_madt_header)->ioapic_addr;
(*num_ioapic)++;
}
break;
case MADT_ISO:
printf("ACIP: MADT_ISO bus=%d source=%d gsi=%d flags=0x%x\n",
((acpi_madt_iso_t*)acpi_madt_header)->bus,
((acpi_madt_iso_t*)acpi_madt_header)->source,
((acpi_madt_iso_t*)acpi_madt_header)->gsi,
((acpi_madt_iso_t*)acpi_madt_header)->flags);
break;
default:
break;

View file

@ -14,6 +14,7 @@
#include <arch/model/statedata.h>
#include <arch/linker.h>
#include <plat/machine/pic.h>
#include <plat/machine/ioapic.h>
#include <plat/machine.h>
#ifdef CONFIG_IOMMU
@ -43,16 +44,35 @@ void platAddDevices(void)
/* Enable or disable irq according to the 'mask' flag. */
void maskInterrupt(bool_t mask, irq_t irq)
{
assert(irq >= irq_isa_min);
assert(irq >= irq_controller_min);
assert(irq <= maxIRQ);
if (irq <= irq_isa_max) {
if (irq <= irq_controller_max) {
#ifdef CONFIG_IRQ_IOAPIC
ioapic_mask_irq(mask, irq);
#else
pic_mask_irq(mask, irq);
#endif
} else {
/* we can't mask/unmask specific APIC vectors (e.g. MSIs/IPIs) */
}
}
/* Set mode of an irq */
void setInterruptMode(irq_t irq, bool_t levelTrigger, bool_t polarityLow)
{
#ifdef CONFIG_IRQ_IOAPIC
assert(irq >= irq_ioapic_min);
assert(irq <= maxIRQ);
if (irq <= irq_ioapic_max) {
ioapic_set_mode(irq, levelTrigger, polarityLow);
} else {
/* No mode setting for specific APIC vectors */
}
#endif
}
/* Handle a platform-reserved IRQ. */
void handleReservedIRQ(irq_t irq)
{
@ -78,14 +98,25 @@ irq_t getActiveIRQ(void)
/* Checks for pending IRQ */
bool_t isIRQPending(void)
{
return apic_is_interrupt_pending() || pic_is_irq_pending();
if (apic_is_interrupt_pending()) {
return true;
}
#ifdef CONFIG_IRQ_PIC
if (pic_is_irq_pending()) {
return true;
}
#endif
return false;
}
void ackInterrupt(irq_t irq)
{
#ifdef CONFIG_IRQ_PIC
if (irq <= irq_isa_max) {
pic_ack_active_irq();
} else {
} else
#endif
{
apic_ack_active_interrupt();
}
}

View file

@ -0,0 +1,177 @@
/*
* Copyright 2014, General Dynamics C4 Systems
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(GD_GPL)
*/
#include <config.h>
#ifdef CONFIG_IRQ_IOAPIC
#include <arch/linker.h>
#include <plat/machine/io.h>
#include <plat/machine/hardware.h>
#include <plat/machine/ioapic.h>
#define IOAPIC_REGSEL 0x00
#define IOAPIC_WINDOW 0x10
#define IOAPIC_REG_IOAPICID 0x00
#define IOAPIC_REG_IOREDTBL 0x10
#define IOREDTBL_LOW(reg) (IOAPIC_REG_IOREDTBL + (reg) * 2)
#define IOREDTBL_HIGH(reg) (IOREDTBL_LOW(reg) + 1)
#define IOREDTBL_LOW_INTERRUPT_MASK BIT(16)
#define IOREDTBL_LOW_TRIGGER_MODE_LEVEL BIT(15)
#define IOREDTBL_LOW_POLARITY_LOW BIT(13)
#define IOREDTBL_LOW_DEST_MODE_LOGCIAL BIT(11)
#define IOAPICID_ID_BITS 4
#define IOAPICID_ID_OFFSET 24
#define IOREDTBL_HIGH_RESERVED_BITS 24
/* Cache what we believe is in the low word of the IOREDTBL. This
* has all the state of trigger modes etc etc */
static uint32_t ioredtbl_state[IOAPIC_IRQ_LINES * CONFIG_MAX_NUM_IOAPIC];
/* Number of IOAPICs in the system */
static uint32_t num_ioapics = 0;
/* In debug mode we track whether an unmasked vector has
* had its mode set. This is to catch bad user level code */
#ifdef DEBUG
static bool_t done_set_mode[IOAPIC_IRQ_LINES * CONFIG_MAX_NUM_IOAPIC] = { 0 };
#endif
static void ioapic_write(uint32_t ioapic, uint32_t reg, uint32_t value)
{
*(volatile uint32_t*)((uint32_t)(PPTR_IOAPIC_START + ioapic * BIT(PAGE_BITS)) + reg) = value;
}
static uint32_t ioapic_read(uint32_t ioapic, uint32_t reg)
{
return *(volatile uint32_t*)((uint32_t)(PPTR_IOAPIC_START + ioapic * BIT(PAGE_BITS)) + reg);
}
static bool_t in_list(uint32_t size, cpu_id_t *list, cpu_id_t target)
{
uint32_t i;
for (i = 0; i < size; i++) {
if (list[i] == target) {
return true;
}
}
return false;
}
static void single_ioapic_init(uint32_t ioapic, cpu_id_t ioapic_id, cpu_id_t delivery_cpu)
{
uint32_t id_reg;
uint32_t i;
/* Write the ID to the ioapic */
ioapic_write(ioapic, IOAPIC_REGSEL, IOAPIC_REG_IOAPICID);
id_reg = ioapic_read(ioapic, IOAPIC_WINDOW);
/* perform mask to preserve the reserved bits */
id_reg &= ~(MASK(IOAPICID_ID_BITS) << IOAPICID_ID_OFFSET);
id_reg |= ioapic_id << IOAPICID_ID_OFFSET;
/* Mask all the IRQs and set default delivery details.
* attempt to deliberately set a trigger mode and level
* setting that is LEAST likely to be correct. This is
* to ensure user code sets it correctly and cannot get
* away with it happening to be correct */
for (i = 0; i < IOAPIC_IRQ_LINES; i++) {
/* Send to desired cpu */
ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_HIGH(i));
ioapic_write(ioapic, IOAPIC_WINDOW, (ioapic_read(ioapic, IOAPIC_WINDOW) & MASK(IOREDTBL_HIGH_RESERVED_BITS)) | (delivery_cpu << IOREDTBL_HIGH_RESERVED_BITS));
/* Mask and set to level trigger high polarity and make the delivery vector */
ioredtbl_state[i] = IOREDTBL_LOW_INTERRUPT_MASK |
IOREDTBL_LOW_TRIGGER_MODE_LEVEL |
(i + IRQ_INT_OFFSET);
ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(i));
/* The upper 16 bits are reserved, so we make sure to preserve them */
ioredtbl_state[i] |= ioapic_read(ioapic, IOAPIC_WINDOW) & ~MASK(16);
ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[i]);
}
}
/* To guarantee we will be able to find enough free apic ids there needs to be less than
* 2^4 cpus + ioapics in the system */
compile_assert(ioapic_id_will_not_overflow, CONFIG_MAX_NUM_NODES + CONFIG_MAX_NUM_IOAPIC < 16);
void ioapic_init(uint32_t num_nodes, cpu_id_t *cpu_list, uint32_t num_ioapic)
{
uint32_t ioapic;
cpu_id_t ioapic_id = 0;
num_ioapics = num_ioapic;
for (ioapic = 0; ioapic < num_ioapic; ioapic++) {
/* Determine the next free apic ID */
while (in_list(num_nodes, cpu_list, ioapic_id)) {
ioapic_id++;
}
/* ioapic id field is 4 bits. this assert passing should be
* guaranteed by the compile assert above this function, hence
* this does not need to be a run time check */
assert(ioapic_id < BIT(4));
/* Init this ioapic */
single_ioapic_init(ioapic, ioapic_id, cpu_list[0]);
/* Increment the id */
ioapic_id++;
}
}
void ioapic_mask_irq(bool_t mask, irq_t irq)
{
uint32_t ioapic = irq / IOAPIC_IRQ_LINES;
uint32_t index = irq % IOAPIC_IRQ_LINES;
if (ioapic >= num_ioapics) {
/* silently ignore requests to non existent parts of the interrupt space */
return;
}
if (mask) {
ioredtbl_state[irq] |= IOREDTBL_LOW_INTERRUPT_MASK;
} else {
ioredtbl_state[irq] &= ~IOREDTBL_LOW_INTERRUPT_MASK;
#ifdef DEBUG
if (!done_set_mode[irq]) {
printf("Unmasking IOAPIC source %d on ioapic %d without ever setting its mode!\n", index, ioapic);
/* Set the flag so we don't repeatedly warn */
done_set_mode[irq] = 1;
}
#endif
}
ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(index));
ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[irq]);
}
void ioapic_set_mode(irq_t irq, bool_t levelTrigger, bool_t polarityLow)
{
uint32_t ioapic = irq / IOAPIC_IRQ_LINES;
uint32_t index = irq % IOAPIC_IRQ_LINES;
if (ioapic >= num_ioapics) {
/* silently ignore requests to non existent parts of the interrupt space */
return;
}
if (levelTrigger) {
ioredtbl_state[irq] |= IOREDTBL_LOW_TRIGGER_MODE_LEVEL;
} else {
ioredtbl_state[irq] &= ~IOREDTBL_LOW_TRIGGER_MODE_LEVEL;
}
if (polarityLow) {
ioredtbl_state[irq] |= IOREDTBL_LOW_POLARITY_LOW;
} else {
ioredtbl_state[irq] &= ~IOREDTBL_LOW_POLARITY_LOW;
}
#ifdef DEBUG
done_set_mode[irq] = 1;
#endif
ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(index));
ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[irq]);
}
#endif /* CONFIG_IOAPIC */

View file

@ -33,6 +33,16 @@ pic_remap_irqs(interrupt_t interrupt)
out8(PIC2_BASE + 1, 0x0);
}
BOOT_CODE void pic_disable(void)
{
/* We assume that pic_remap_irqs has already been called and
* just mask all the irqs */
out8(PIC1_BASE + 1, 0xff);
out8(PIC2_BASE + 1, 0xff);
}
#ifdef CONFIG_IRQ_PIC
void pic_mask_irq(bool_t mask, irq_t irq)
{
uint8_t bit_mask;
@ -84,3 +94,5 @@ void pic_ack_active_irq(void)
/* ack master PIC */
out8(PIC1_BASE, 0x20);
}
#endif

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
#
# Copyright 2014, NICTA
#

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
#
# Copyright 2014, NICTA
#
@ -41,13 +41,14 @@ kernel_header_template = \
#define SYSCALL_{{upper(syscall)}} ({{syscall_number}})
{{py:syscall_number -= 1}}
{{endfor}}
{{py:syscall_max = -len(list)}}
{{endfor}}
#endif
#define SYSCALL_MAX (-1)
#define SYSCALL_MIN ({{syscall_number + 1}})
#else /* C definitions */
#ifndef __ASSEMBLER__
enum syscall {
{{py:syscall_number = -1}}
@ -66,7 +67,7 @@ enum syscall {
};
typedef uint32_t syscall_t;
#endif /* ASSEMBLER */
#endif
#endif /* __ARCH_API_SYSCALL_H */
"""