iccrpr[x] = 0xff;
cpuEnabled[x] = false;
cpuPriority[x] = 0xff;
- cpuBpr[x] = 0;
+ cpuBpr[x] = GICC_BPR_MINIMUM;
// Initialize cpu highest int
cpuHighestInt[x] = SPURIOUS_INT;
postIntEvent[x] = new PostIntEvent(*this, x);
case GICC_PMR:
cpuPriority[ctx] = data;
break;
- case GICC_BPR:
- cpuBpr[ctx] = data;
+ case GICC_BPR: {
+ auto bpr = data & 0x7;
+ if (bpr < GICC_BPR_MINIMUM)
+ bpr = GICC_BPR_MINIMUM;
+ cpuBpr[ctx] = bpr;
break;
+ }
case GICC_EOIR: {
const IAR iar = data;
if (iar.ack_id < SGI_MAX) {
return ULL(0x0101010101010101) << cpu;
}
+uint8_t
+Pl390::getCpuPriority(unsigned cpu)
+{
+ // see Table 3-2 in IHI0048B.b (GICv2)
+ // mask some low-order priority bits per BPR value
+ // NB: the GIC prioritization scheme is upside down:
+ // lower values are higher priority; masking off bits
+ // actually creates a higher priority, not lower.
+ return cpuPriority[cpu] & (0xff00 >> (7 - cpuBpr[cpu]));
+}
+
void
Pl390::updateIntState(int hint)
{
/*@todo use hint to do less work. */
int highest_int = SPURIOUS_INT;
// Priorities below that set in GICC_PMR can be ignored
- uint8_t highest_pri = cpuPriority[cpu];
+ uint8_t highest_pri = getCpuPriority(cpu);
// Check SGIs
for (int swi = 0; swi < SGI_MAX; swi++) {
/* @todo make this work for more than one cpu, need to handle 1:N, N:N
* models */
- if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
+ if (enabled && cpuEnabled[cpu] &&
+ (highest_pri < getCpuPriority(cpu)) &&
!(getActiveInt(cpu, intNumToWord(highest_int))
& (1 << intNumToBit(highest_int)))) {
static const int INT_LINES_MAX = 1020;
static const int GLOBAL_INT_LINES = INT_LINES_MAX - SGI_MAX - PPI_MAX;
+ /** minimum value for Binary Point Register ("IMPLEMENTATION DEFINED");
+ chosen for consistency with Linux's in-kernel KVM GIC model */
+ static const int GICC_BPR_MINIMUM = 2;
+
BitUnion32(SWI)
Bitfield<3,0> sgi_id;
Bitfield<23,16> cpu_list;
/** CPU priority */
uint8_t cpuPriority[CPU_MAX];
+ uint8_t getCpuPriority(unsigned cpu); // BPR-adjusted priority value
/** Binary point registers */
uint8_t cpuBpr[CPU_MAX];