summaryrefslogtreecommitdiff
path: root/ArmPkg/Drivers/PL390Gic/PL390GicSec.c
blob: 25038bd63fcb8dcc2daff7ab71e92c7050c8c85b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** @file
*
*  Copyright (c) 2011-2012, ARM Limited. All rights reserved.
*  
*  This program and the accompanying materials                          
*  are licensed and made available under the terms and conditions of the BSD License         
*  which accompanies this distribution.  The full text of the license may be found at        
*  http://opensource.org/licenses/bsd-license.php                                            
*
*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
*
**/

#include <Base.h>
#include <Library/ArmLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/ArmGicLib.h>

/*
 * This function configures the all interrupts to be Non-secure.
 *
 */
VOID
EFIAPI
ArmGicSetupNonSecure (
  IN  UINTN         MpId,
  IN  INTN          GicDistributorBase,
  IN  INTN          GicInterruptInterfaceBase
  )
{
  UINTN InterruptId;
  UINTN CachedPriorityMask;
  UINTN Index;

  CachedPriorityMask = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR);

  // Set priority Mask so that no interrupts get through to CPU
  MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0);

  // Check if there are any pending interrupts
  //TODO: could be extended to take Peripheral interrupts into consideration, but at the moment only SGI's are taken into consideration.
  while(0 != (MmioRead32 (GicDistributorBase + ARM_GIC_ICDICPR) & 0xF)) {
    // Some of the SGI's are still pending, read Ack register and send End of Interrupt Signal
    InterruptId = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR);

    // Write to End of interrupt signal
    MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, InterruptId);
  }

  // Only the primary core should set the Non Secure bit to the SPIs (Shared Peripheral Interrupt).
  if (IS_PRIMARY_CORE(MpId)) {
    // Ensure all GIC interrupts are Non-Secure
    for (Index = 0; Index < (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32); Index++) {
      MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), 0xffffffff);
    }
  } else {
    // The secondary cores only set the Non Secure bit to their banked PPIs
    MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR, 0xffffffff);
  }

  // Ensure all interrupts can get through the priority mask
  MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, CachedPriorityMask);
}

/*
 * This function configures the interrupts set by the mask to be secure.
 *
 */
VOID
EFIAPI
ArmGicSetSecureInterrupts (
  IN  UINTN         GicDistributorBase,
  IN  UINTN*        GicSecureInterruptMask,
  IN  UINTN         GicSecureInterruptMaskSize
  )
{
  UINTN  Index;
  UINT32 InterruptStatus;

  // We must not have more interrupts defined by the mask than the number of available interrupts
  ASSERT(GicSecureInterruptMaskSize <= (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32));

  // Set all the interrupts defined by the mask as Secure
  for (Index = 0; Index < GicSecureInterruptMaskSize; Index++) {
    InterruptStatus = MmioRead32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4));
    MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), InterruptStatus & (~GicSecureInterruptMask[Index]));
  }
}

VOID
EFIAPI
ArmGicEnableInterruptInterface (
  IN  INTN          GicInterruptInterfaceBase
  )
{
  // Set Priority Mask to allow interrupts
  MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0x000000FF);

  // Enable CPU interface in Secure world
  // Enable CPU inteface in Non-secure World
  // Signal Secure Interrupts to CPU using FIQ line *
  MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR,
      ARM_GIC_ICCICR_ENABLE_SECURE |
      ARM_GIC_ICCICR_ENABLE_NS |
      ARM_GIC_ICCICR_SIGNAL_SECURE_TO_FIQ);
}

VOID
EFIAPI
ArmGicDisableInterruptInterface (
  IN  INTN          GicInterruptInterfaceBase
  )
{
  UINT32    ControlValue;

  // Disable CPU interface in Secure world and Non-secure World
  ControlValue = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR);
  MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, ControlValue & ~(ARM_GIC_ICCICR_ENABLE_SECURE | ARM_GIC_ICCICR_ENABLE_NS));
}

VOID
EFIAPI
ArmGicEnableDistributor (
  IN  INTN          GicDistributorBase
  )
{
  // Turn on the GIC distributor
  MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 1);
}