The Pedigree Project 0.1
IoApic.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <config.h>
21
22#if MULTIPROCESSOR
23
24#include "pedigree/kernel/LockGuard.h"
25#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
26#include "pedigree/kernel/processor/VirtualAddressSpace.h"
27
28#include "IoApic.h"
29
30namespace {
31// Delivery Status and Remote IRR are read-only and can change during a
32// redirection-table write, especially when unmasking a pending interrupt.
33constexpr uint32_t RedirectionStatus = (1U << 12) | (1U << 14);
34} // namespace
35
36IoApic::IoApic() : m_IoSpace("I/O APIC"), m_Lock(false), m_GsiBase(0), m_Count(0) {}
37
38IoApic::~IoApic() {}
39
40bool IoApic::initialise(physical_uintptr_t address, uint32_t gsiBase) {
41 if (!address || (address & (PhysicalMemoryManager::getPageSize() - 1))) {
42 return false;
43 }
44 if (!PhysicalMemoryManager::instance().allocateRegion(
45 m_IoSpace, 1,
50 address)) {
51 return false;
52 }
53 m_IoSpace.write32(1, 0);
54 const uint32_t version = m_IoSpace.read32(0x10);
55 const uint32_t count = ((version >> 16) & 0xff) + 1;
56 if (count > UINT32_MAX - gsiBase) {
57 return false;
58 }
59 m_GsiBase = gsiBase;
60 m_Count = count;
61 return true;
62}
63
64bool IoApic::contains(uint32_t gsi) const {
65 return m_Count && gsi >= m_GsiBase && gsi - m_GsiBase < m_Count;
66}
67
68bool IoApic::route(uint32_t gsi, uint8_t vector, uint8_t destination, bool activeLow) {
69 if (!contains(gsi) || vector < 0x20) {
70 return false;
71 }
72 const uint32_t registerNumber = 0x10 + 2 * (gsi - m_GsiBase);
73 const uint32_t low = vector | (1U << 15) | (1U << 16) | (activeLow ? 1U << 13 : 0);
74 const uint32_t high = uint32_t(destination) << 24;
75 LockGuard<Spinlock> guard(m_Lock);
76 m_IoSpace.write32(registerNumber, 0);
77 const uint32_t current = m_IoSpace.read32(0x10);
78 m_IoSpace.write32(current | (1U << 16), 0x10);
79 m_IoSpace.write32(registerNumber + 1, 0);
80 m_IoSpace.write32(high, 0x10);
81 const bool highWritten = m_IoSpace.read32(0x10) == high;
82 m_IoSpace.write32(registerNumber, 0);
83 m_IoSpace.write32(low, 0x10);
84 return highWritten && (m_IoSpace.read32(0x10) & ~RedirectionStatus) == low;
85}
86
87bool IoApic::mask(uint32_t gsi, bool masked) {
88 if (!contains(gsi)) {
89 return false;
90 }
91 const uint32_t registerNumber = 0x10 + 2 * (gsi - m_GsiBase);
92 LockGuard<Spinlock> guard(m_Lock);
93 m_IoSpace.write32(registerNumber, 0);
94 uint32_t low = m_IoSpace.read32(0x10);
95 low = masked ? low | (1U << 16) : low & ~(1U << 16);
96 m_IoSpace.write32(low, 0x10);
97 return (m_IoSpace.read32(0x10) & ~RedirectionStatus) == (low & ~RedirectionStatus);
98}
99
100#endif
static PhysicalMemoryManager & instance()