1% Copyright 2014, General Dynamics C4 Systems
2%
3% This software may be distributed and modified according to the terms of
4% the GNU General Public License version 2. Note that NO WARRANTY is provided.
5% See "LICENSE_GPLv2.txt" for details.
6%
7% @TAG(GD_GPL)
8%
9
10This module defines the machine-specific interrupt handling routines for x64.
11
12> {-# LANGUAGE CPP #-}
13
14> module SEL4.Object.Interrupt.X64 where
15
16
17\begin{impdetails}
18
19> import Prelude hiding (Word)
20> import SEL4.Machine
21> import SEL4.Model
22> import SEL4.Model.StateData.X64
23> import SEL4.Object.Structures
24> import SEL4.API.Failures
25> import SEL4.API.Types
26>-- import SEL4.API.Invocation
27> import SEL4.API.InvocationLabels
28> import SEL4.API.Invocation.X64 as ArchInv
29> import SEL4.API.InvocationLabels.X64 as ArchLabels
30> import {-# SOURCE #-} SEL4.Object.CNode
31> import {-# SOURCE #-} SEL4.Kernel.CSpace
32> import {-# SOURCE #-} SEL4.Object.Interrupt
33> import qualified SEL4.Machine.Hardware.X64 as Arch
34> import Data.Word (Word8)
35> import Data.Array ((//))
36> import Data.Bits
37
38
39\end{impdetails}
40
41%FIXME: argument order, IRQ shouldn't be last. Fix in C.
42
43%FIXME: remove duplication with decodeIRQControl, move code to generic case. Do this on C first.
44
45> decodeIRQControlInvocation :: Word -> [Word] -> PPtr CTE -> [Capability] ->
46>         KernelF SyscallError ArchInv.IRQControlInvocation
47> decodeIRQControlInvocation label args srcSlot extraCaps =
48>     case (invocationType label, args, extraCaps) of
49>         (ArchInvocationLabel ArchLabels.X64IRQIssueIRQHandlerIOAPIC,
50>                  index:depth:ioapic:pin:level:polarity:irqW:_, cnode:_) -> do
51>
52>             let preIrq = fromIntegral irqW :: Word8
53>             rangeCheck preIrq 0 (fromEnum Arch.maxUserIRQ - fromEnum Arch.minUserIRQ)
54>             let irq = toEnum (fromEnum Arch.minUserIRQ + fromIntegral preIrq) :: IRQ
55>
56>             irqActive <- withoutFailure $ isIRQActive irq
57>             when irqActive $ throw RevokeFirst
58>
59>             destSlot <- lookupTargetSlot cnode (CPtr index)
60>                 (fromIntegral depth)
61>             ensureEmptySlot destSlot
62>
63>             -- from ioapic_map_pin_to_vector
64>             numIOAPICs <- withoutFailure $ gets (x64KSNumIOAPICs . ksArchState)
65>             when (numIOAPICs == 0) $ throw IllegalOperation
66>             rangeCheck ioapic 0 (numIOAPICs - 1)
67>             rangeCheck pin 0 (Arch.ioapicIRQLines - 1)
68>             rangeCheck level (0::Word) 1
69>             rangeCheck polarity (0::Word) 1
70>
71>             -- FIXME check semantics against toEnum, we might want == 0 here
72>             let vector = (fromIntegral $ fromEnum irq) + Arch.irqIntOffset
73>             return $ ArchInv.IssueIRQHandlerIOAPIC irq destSlot srcSlot ioapic
74>                 pin level polarity vector
75>
76>         (ArchInvocationLabel ArchLabels.X64IRQIssueIRQHandlerIOAPIC, _, _) -> throw TruncatedMessage
77>
78>         (ArchInvocationLabel ArchLabels.X64IRQIssueIRQHandlerMSI,
79>                  index:depth:pciBus:pciDev:pciFunc:handle:irqW:_, cnode:_) -> do
80>
81>             let preIrq = fromIntegral irqW :: Word8
82>             rangeCheck preIrq 0 (fromEnum Arch.maxUserIRQ - fromEnum Arch.minUserIRQ)
83>             let irq = toEnum (fromEnum Arch.minUserIRQ + fromIntegral preIrq) :: IRQ
84>
85>             irqActive <- withoutFailure $ isIRQActive irq
86>             when irqActive $ throw RevokeFirst
87>
88>             destSlot <- lookupTargetSlot cnode (CPtr index)
89>                 (fromIntegral depth)
90>
91>             ensureEmptySlot destSlot
92>             rangeCheck pciBus 0 Arch.maxPCIBus
93>             rangeCheck pciDev 0 Arch.maxPCIDev
94>             rangeCheck pciFunc 0 Arch.maxPCIFunc
95>
96>             return $ ArchInv.IssueIRQHandlerMSI irq destSlot srcSlot pciBus
97>                 pciDev pciFunc handle
98>
99>         (ArchInvocationLabel ArchLabels.X64IRQIssueIRQHandlerMSI, _, _) -> throw TruncatedMessage
100
101>         _ -> throw IllegalOperation
102
103updateIRQState sets the arch-specific IRQ state for an IRQ
104
105> updateIRQState :: IRQ -> X64IRQState -> Kernel ()
106> updateIRQState irq irqState = do
107>     irqStates <- gets (x64KSIRQState . ksArchState)
108>     modify (\s -> s { ksArchState = (ksArchState s) { x64KSIRQState = irqStates // [(irq, irqState)]} })
109
110> performIRQControl :: ArchInv.IRQControlInvocation -> KernelP ()
111> performIRQControl (ArchInv.IssueIRQHandlerIOAPIC (IRQ irq) destSlot srcSlot ioapic
112>         pin level polarity vector) = withoutPreemption $ do
113>     doMachineOp $ Arch.ioapicMapPinToVector ioapic pin level polarity vector
114>     irqState <- return $ X64IRQIOAPIC (ioapic .&. mask 5) (pin .&. mask 5) (level .&. 1) (polarity .&. 1) True
115>     updateIRQState (IRQ irq) irqState
116>     -- do same thing as generic path in performIRQControl in Interrupt.lhs
117>     setIRQState IRQSignal (IRQ irq)
118>     cteInsert (IRQHandlerCap (IRQ irq)) srcSlot destSlot
119>     return ()
120>
121> performIRQControl (ArchInv.IssueIRQHandlerMSI (IRQ irq) destSlot srcSlot pciBus
122>         pciDev pciFunc handle) = withoutPreemption $ do
123>     irqState <- return $ X64IRQMSI (pciBus .&. mask 8) (pciDev .&. mask 5) (pciFunc .&. mask 3) (handle .&. mask 32)
124>     updateIRQState (IRQ irq) irqState
125>     -- do same thing as generic path in performIRQControl in Interrupt.lhs
126>     setIRQState IRQSignal (IRQ irq)
127>     cteInsert (IRQHandlerCap (IRQ irq)) srcSlot destSlot
128>     return ()
129
130%FIXME: separate ranges for ISA interrupts and user interrupts
131
132checkIRQ is only used for the legacy PIC interrupt so always fails with the IOAPIC of x86-64
133
134> checkIRQ :: Word -> KernelF SyscallError ()
135> checkIRQ irq = throw IllegalOperation
136
137%FIXME: handle VTD faults
138
139> handleReservedIRQ :: IRQ -> Kernel ()
140> handleReservedIRQ _ = return ()
141
142> initInterruptController :: Kernel ()
143> initInterruptController = return ()
144
145