49 static constexpr uint32_t BiosOwned = 1U << 16;
50 static constexpr uint32_t OsOwned = 1U << 24;
51 static constexpr uint8_t LegacyCapabilityId = 1;
52 static constexpr size_t DefaultPollLimit = 1000;
57 m_WasBiosOwned(
false),
58 m_RequestWritten(
false),
61 m_SmiMutationAttempted(
false),
62 m_SnapshotValid(
false) {}
71 template <
typename Config>
72 AcquireResult
acquire(uint16_t offset, Config& config,
size_t pollLimit = DefaultPollLimit) {
74 return AcquireResult::AlreadyAttempted;
76 if (!validOffset(offset) || !pollLimit)
77 return AcquireResult::InvalidCapability;
81 if (!config.read32(offset, legsup) || !config.read32(controlOffset(offset), control))
82 return AcquireResult::AccessFailure;
83 if ((legsup & 0xffU) != LegacyCapabilityId)
84 return AcquireResult::InvalidCapability;
87 m_SavedSmiEnables = control & EhciLegacy::SmiEnables;
88 m_WasBiosOwned = (legsup & BiosOwned) != 0;
89 m_SnapshotValid =
true;
95 m_RequestWritten =
true;
96 if (!config.write8(
static_cast<uint16_t
>(offset + 3), 1))
97 return AcquireResult::AccessFailure;
99 bool sawBiosClear =
false;
100 for (
size_t poll = 0; poll < pollLimit; ++poll) {
101 if (!config.read32(offset, legsup))
102 return AcquireResult::AccessFailure;
103 if (!(legsup & BiosOwned)) {
105 if (!(legsup & OsOwned))
106 return AcquireResult::OwnershipMismatch;
109 if (poll + 1 < pollLimit)
113 return AcquireResult::OwnershipTimeout;
116 m_SmiMutationAttempted =
true;
117 if (!EhciLegacy::disableSmis(
119 [&config](uint16_t registerOffset, uint32_t& value) {
120 return config.read32(registerOffset, value);
122 [&config](uint16_t registerOffset, uint32_t value) {
123 return config.write32(registerOffset, value);
125 return AcquireResult::SmiDisableFailure;
129 m_Acquired = m_WasBiosOwned;
130 return m_WasBiosOwned ? AcquireResult::Acquired : AcquireResult::AlreadyUnowned;
142 template <
typename Config>
144 if (!m_SnapshotValid || m_Acquired || !m_WasBiosOwned ||
145 (!m_RequestWritten && !m_SmiMutationAttempted))
146 return ReleaseResult::NotOwned;
147 return releaseInternal(config,
true, pollLimit);
157 template <
typename Config>
158 ReleaseResult
release(Config& config,
bool callerQuiescedOrNeverTouched,
159 size_t pollLimit = DefaultPollLimit) {
160 if (!callerQuiescedOrNeverTouched)
161 return ReleaseResult::NotQuiesced;
162 return releaseInternal(config,
false, pollLimit);
165 uint16_t offset()
const {
169 uint32_t savedSmiEnables()
const {
170 return m_SavedSmiEnables;
173 bool wasBiosOwned()
const {
174 return m_WasBiosOwned;
177 bool requested()
const {
178 return m_RequestWritten;
181 bool acquired()
const {
185 bool disabled()
const {
190 static constexpr uint16_t ControlOffset = 4;
192 static bool validOffset(uint16_t offset) {
193 return offset >= 0x40 && offset <= 0xf8 && !(offset & 3);
196 static uint16_t controlOffset(uint16_t offset) {
197 return static_cast<uint16_t
>(offset + ControlOffset);
202 m_SavedSmiEnables = 0;
203 m_WasBiosOwned =
false;
204 m_RequestWritten =
false;
207 m_SmiMutationAttempted =
false;
208 m_SnapshotValid =
false;
211 template <
typename Config>
212 bool restoreSmis(Config& config) {
213 if (!m_SnapshotValid ||
214 !config.write32(controlOffset(m_Offset), EhciLegacy::AcknowledgeStatus | m_SavedSmiEnables))
217 uint32_t control = 0;
218 if (!config.read32(controlOffset(m_Offset), control))
220 return (control & EhciLegacy::SmiEnables) == m_SavedSmiEnables;
223 template <
typename Config>
224 ReleaseResult releaseInternal(Config& config,
bool allowUnacquired,
size_t pollLimit) {
225 if (!m_SnapshotValid || !pollLimit)
226 return ReleaseResult::NotOwned;
228 if (!m_WasBiosOwned) {
232 return ReleaseResult::NotOwned;
235 if (!m_RequestWritten)
236 return ReleaseResult::NotOwned;
238 if (!m_Acquired && !allowUnacquired)
239 return ReleaseResult::NotOwned;
247 if (m_SmiMutationAttempted) {
248 if (!restoreSmis(config))
249 return ReleaseResult::AccessFailure;
251 uint32_t liveLegsup = 0;
252 if (!config.read32(m_Offset, liveLegsup))
253 return ReleaseResult::AccessFailure;
254 if (!(liveLegsup & BiosOwned) && !restoreSmis(config))
255 return ReleaseResult::AccessFailure;
258 if (!config.write8(
static_cast<uint16_t
>(m_Offset + 3), 0))
259 return ReleaseResult::AccessFailure;
262 if (!config.read32(m_Offset, legsup))
263 return ReleaseResult::AccessFailure;
264 if (legsup & OsOwned)
265 return ReleaseResult::AccessFailure;
267 bool firmwareConfirmed = (legsup & BiosOwned) != 0;
268 for (
size_t poll = 0; !firmwareConfirmed && poll < pollLimit; ++poll) {
269 if (!config.read32(m_Offset, legsup))
270 return ReleaseResult::AccessFailure;
271 firmwareConfirmed = (legsup & BiosOwned) != 0;
272 if (!firmwareConfirmed && poll + 1 < pollLimit)
277 return firmwareConfirmed ? ReleaseResult::FirmwareConfirmed : ReleaseResult::Released;
281 uint32_t m_SavedSmiEnables;
283 bool m_RequestWritten;
286 bool m_SmiMutationAttempted;
287 bool m_SnapshotValid;