1-- 2-- Copyright 2014, General Dynamics C4 Systems 3-- 4-- This software may be distributed and modified according to the terms of 5-- the GNU General Public License version 2. Note that NO WARRANTY is provided. 6-- See "LICENSE_GPLv2.txt" for details. 7-- 8-- @TAG(GD_GPL) 9-- 10 11{-# LANGUAGE EmptyDataDecls, ForeignFunctionInterface, GeneralizedNewtypeDeriving #-} 12 13module SEL4.Machine.Hardware.ARM.KZM where 14 15import Prelude hiding (Word) 16import SEL4.Machine.RegisterSet 17import Foreign.Ptr 18import Data.Bits 19import Data.Word(Word8) 20import Data.Ix 21import SEL4.Machine.Hardware.ARM.Callbacks 22 23 24newtype IRQ = IRQ Word8 25 deriving (Enum, Ord, Ix, Eq, Show) 26 27instance Bounded IRQ where 28 minBound = IRQ 0 29 maxBound = IRQ 31 30 31kernelBase :: VPtr 32kernelBase = VPtr 0xf0000000 33 34physBase = 0x80000000 35physMappingOffset = 0xf0000000 - physBase 36 37ptrFromPAddr :: PAddr -> PPtr a 38ptrFromPAddr (PAddr addr) = PPtr $ addr + physMappingOffset 39 40addrFromPPtr :: PPtr a -> PAddr 41addrFromPPtr (PPtr ptr) = PAddr $ ptr - physMappingOffset 42 43pageColourBits :: Int 44pageColourBits = 0 -- qemu has no cache 45 46getMemoryRegions :: Ptr CallbackData -> IO [(PAddr, PAddr)] 47getMemoryRegions _ = return [(0x80000000, 0x80000000 + (0x8 `shiftL` 24))] 48 49getDeviceRegions :: Ptr CallbackData -> IO [(PAddr, PAddr)] 50getDeviceRegions _ = return devices 51 where devices = [ 52 (0x53f98000, 0x53f99000) -- second SP804; kernel uses first 53 ] 54 55timerPPtr = PPtr 0xfff00000 56timerAddr = PAddr 0x53f94000 57timerIRQ = IRQ 28 58 59avicPPtr = PPtr 0xfff01000 60avicAddr = PAddr 0x68000000 61 62getKernelDevices :: Ptr CallbackData -> IO [(PAddr, PPtr Word)] 63getKernelDevices _ = return devices 64 where devices = [ 65 (timerAddr, timerPPtr), -- kernel timer 66 (avicAddr, avicPPtr) -- interrupt controller 67 ] 68 69maskInterrupt :: Ptr CallbackData -> Bool -> IRQ -> IO () 70maskInterrupt env mask (IRQ irq) = do 71 let value = fromIntegral irq 72 offset <- return $ if (mask == True) then 0xc else 0x8 73 storeWordCallback env (avicAddr + offset) value 74 75-- We don't need to acknowledge interrupts explicitly because we don't use 76-- the vectored interrupt controller. 77ackInterrupt :: Ptr CallbackData -> IRQ -> IO () 78ackInterrupt _ _ = return () 79 80foreign import ccall unsafe "qemu_run_devices" 81 runDevicesCallback :: Ptr CallbackData -> IO () 82 83interruptCallback :: Ptr CallbackData -> IO (Maybe IRQ) 84interruptCallback env = do 85 -- No need to call back to the simulator here; we just check the PIC's 86 -- active interrupt register. This will probably work for real ARMs too, 87 -- as long as we're not using vectored interrupts 88 active <- loadWordCallback env (avicAddr + 64) 89 return $ if active == 0xFFFF0000 90 then Nothing 91 else (Just $ IRQ $ fromIntegral (active `shiftR` 16)) 92 93getActiveIRQ :: Ptr CallbackData -> IO (Maybe IRQ) 94getActiveIRQ env = do 95 runDevicesCallback env 96 interruptCallback env 97 98-- 1kHz tick; qemu's SP804s always run at 1MHz 99timerFreq :: Word 100timerFreq = 100 101 102timerLimit :: Word 103timerLimit = 1000000 `div` timerFreq 104 105configureTimer :: Ptr CallbackData -> IO IRQ 106configureTimer env = do 107 -- enabled, periodic, interrupts enabled 108 storeWordCallback env timerAddr 0 109 let timerCtrl = bit 24 .|. bit 17 .|. bit 3 .|. bit 2 .|. bit 1 110 storeWordCallback env timerAddr timerCtrl 111 storeWordCallback env (timerAddr+0x8) (100 * 1000 * 1000) 112 storeWordCallback env (timerAddr+0xc) 0 113 storeWordCallback env (timerAddr+0x4) 1 114 let timerCtrl2 = timerCtrl .|. 1 115 storeWordCallback env timerAddr timerCtrl2 116 return timerIRQ 117 118initIRQController :: Ptr CallbackData -> IO () 119initIRQController env = runDevicesCallback env 120 121resetTimer :: Ptr CallbackData -> IO () 122resetTimer env = storeWordCallback env (timerAddr+0x4) 1 123 124isbCallback :: Ptr CallbackData -> IO () 125isbCallback _ = return () 126 127dsbCallback :: Ptr CallbackData -> IO () 128dsbCallback _ = return () 129 130dmbCallback :: Ptr CallbackData -> IO () 131dmbCallback _ = return () 132 133cacheCleanByVACallback :: Ptr CallbackData -> VPtr -> PAddr -> IO () 134cacheCleanByVACallback _cptr _mva _pa = return () 135 136cacheCleanByVA_PoUCallback :: Ptr CallbackData -> VPtr -> PAddr -> IO () 137cacheCleanByVA_PoUCallback _cptr _mva _pa = return () 138 139cacheInvalidateByVACallback :: Ptr CallbackData -> VPtr -> PAddr -> IO () 140cacheInvalidateByVACallback _cptr _mva _pa = return () 141 142cacheInvalidateByVA_ICallback :: Ptr CallbackData -> VPtr -> PAddr -> IO () 143cacheInvalidateByVA_ICallback _cptr _mva _pa = return () 144 145cacheInvalidate_I_PoUCallback :: Ptr CallbackData -> IO () 146cacheInvalidate_I_PoUCallback _ = return () 147 148cacheCleanInvalidateByVACallback :: 149 Ptr CallbackData -> VPtr -> PAddr -> IO () 150cacheCleanInvalidateByVACallback _cptr _mva _pa = return () 151 152branchFlushCallback :: Ptr CallbackData -> VPtr -> PAddr -> IO () 153branchFlushCallback _cptr _mva _pa = return () 154 155cacheClean_D_PoUCallback :: Ptr CallbackData -> IO () 156cacheClean_D_PoUCallback _ = return () 157 158cacheCleanInvalidate_D_PoCCallback :: Ptr CallbackData -> IO () 159cacheCleanInvalidate_D_PoCCallback _ = return () 160 161cacheCleanInvalidate_D_PoUCallback :: Ptr CallbackData -> IO () 162cacheCleanInvalidate_D_PoUCallback _ = return () 163 164cacheCleanInvalidateL2RangeCallback :: 165 Ptr CallbackData -> PAddr -> PAddr -> IO () 166cacheCleanInvalidateL2RangeCallback _ _ _ = return () 167 168cacheInvalidateL2RangeCallback :: Ptr CallbackData -> PAddr -> PAddr -> IO () 169cacheInvalidateL2RangeCallback _ _ _ = return () 170 171cacheCleanL2RangeCallback :: Ptr CallbackData -> PAddr -> PAddr -> IO () 172cacheCleanL2RangeCallback _ _ _ = return () 173 174-- For the ARM1136 175cacheLine :: Int 176cacheLine = 32 177 178cacheLineBits :: Int 179cacheLineBits = 5 180