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