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