提交 7aedbf3c 编写于 作者: V vit9696

OcMemoryLib: Actually fix OcExpandAttributesByMap

上级 4e18dfc7
...@@ -20,7 +20,7 @@ OpenCore Changelog ...@@ -20,7 +20,7 @@ OpenCore Changelog
- Update builtin firmware - Update builtin firmware
- Fixed `PowerTimeoutKernelPanic` on 10.15.4 - Fixed `PowerTimeoutKernelPanic` on 10.15.4
- Fixed 4K section alignment in `OpenRuntime` to fix Linux booting on SKL - Fixed 4K section alignment in `OpenRuntime` to fix Linux booting on SKL
- Introduced `SyncRuntimePermissions` to fix Linux booting on CFL+ - Introduced `SyncRuntimePermissions` to fix multiple memory permission flaws
- Introduced `RebuildAppleMemoryMap` to fix macOS booting on Dell 5490 - Introduced `RebuildAppleMemoryMap` to fix macOS booting on Dell 5490
- Removed `ShrinkMemoryMap` in favour of more advanced `RebuildAppleMemoryMap` - Removed `ShrinkMemoryMap` in favour of more advanced `RebuildAppleMemoryMap`
- Marked `EnableWriteUnprotector` as deprecated on modern systems - Marked `EnableWriteUnprotector` as deprecated on modern systems
......
...@@ -1425,10 +1425,20 @@ To view their current state use \texttt{pmset -g} command in Terminal. ...@@ -1425,10 +1425,20 @@ To view their current state use \texttt{pmset -g} command in Terminal.
\texttt{SyncRuntimePermissions}\\ \texttt{SyncRuntimePermissions}\\
\textbf{Type}: \texttt{plist\ boolean}\\ \textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\ \textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Update memory permissions for \texttt{OpenRuntime} to function. \textbf{Description}: Update memory permissions for runtime environment.
Some firmwares may incorrectly mark \texttt{OpenRuntime} as not executable, this quirks Some firmwares either fail to properly handle runtime permissions:
updates memory map and memory attributes table to correct this. \begin{itemize}
\tightlist
\item They incorrectly mark \texttt{OpenRuntime} as not executable in the memory map.
\item They incorrectly mark \texttt{OpenRuntime} as not executable in the memory
attributes table.
\item They lose entries from the memory attributes table after \texttt{OpenRuntime}
is loaded.
\item They mark items in the memory attributes table as read-write-execute.
\end{itemize}
This quirk tries to update memory map and memory attributes table to correct this.
\emph{Note}: The necessity of this quirk is determined by early boot failures either in \emph{Note}: The necessity of this quirk is determined by early boot failures either in
macOS or in Linux/Windows. In general only firmwares released in 2018 or later are affected. macOS or in Linux/Windows. In general only firmwares released in 2018 or later are affected.
......
\documentclass[]{article} \documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE %DIF LATEXDIFF DIFFERENCE FILE
%DIF DEL PreviousConfiguration.tex Fri Mar 6 09:43:05 2020 %DIF DEL PreviousConfiguration.tex Fri Mar 6 09:43:05 2020
%DIF ADD ../Configuration.tex Fri Apr 3 22:24:21 2020 %DIF ADD ../Configuration.tex Sat Apr 4 23:12:10 2020
\usepackage{lmodern} \usepackage{lmodern}
\usepackage{amssymb,amsmath} \usepackage{amssymb,amsmath}
...@@ -1530,11 +1530,21 @@ To view their current state use \texttt{pmset -g} command in Terminal. ...@@ -1530,11 +1530,21 @@ To view their current state use \texttt{pmset -g} command in Terminal.
\texttt{\DIFadd{SyncRuntimePermissions}}\\ \texttt{\DIFadd{SyncRuntimePermissions}}\\
\textbf{\DIFadd{Type}}\DIFadd{: }\texttt{\DIFadd{plist\ boolean}}\\ \textbf{\DIFadd{Type}}\DIFadd{: }\texttt{\DIFadd{plist\ boolean}}\\
\textbf{\DIFadd{Failsafe}}\DIFadd{: }\texttt{\DIFadd{false}}\\ \textbf{\DIFadd{Failsafe}}\DIFadd{: }\texttt{\DIFadd{false}}\\
\textbf{\DIFadd{Description}}\DIFadd{: Update memory permissions for }\texttt{\DIFadd{OpenRuntime}} \DIFadd{to function. \textbf{\DIFadd{Description}}\DIFadd{: Update memory permissions for runtime environment.
} }
\DIFadd{Some firmwares may incorrectly mark }\texttt{\DIFadd{OpenRuntime}} \DIFadd{as not executable, this quirks \DIFadd{Some firmwares either fail to properly handle runtime permissions:
updates memory map and memory attributes table to correct this. }\begin{itemize}
\tightlist
\item \DIFadd{They incorrectly mark }\texttt{\DIFadd{OpenRuntime}} \DIFadd{as not executable in the memory map.
}\item \DIFadd{They incorrectly mark }\texttt{\DIFadd{OpenRuntime}} \DIFadd{as not executable in the memory
attributes table.
}\item \DIFadd{They lose entries from the memory attributes table after }\texttt{\DIFadd{OpenRuntime}}
\DIFadd{is loaded.
}\item \DIFadd{They mark items in the memory attributes table as read-write-execute.
}\end{itemize}
\DIFadd{This quirk tries to update memory map and memory attributes table to correct this.
} }
\emph{\DIFadd{Note}}\DIFadd{: The necessity of this quirk is determined by early boot failures either in \emph{\DIFadd{Note}}\DIFadd{: The necessity of this quirk is determined by early boot failures either in
......
...@@ -187,14 +187,14 @@ OcExpandAttributesByMap ( ...@@ -187,14 +187,14 @@ OcExpandAttributesByMap (
IN UINTN DescriptorSize IN UINTN DescriptorSize
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINTN MapIndex; UINTN MapIndex;
UINTN MatIndex; UINTN MatIndex;
EFI_PHYSICAL_ADDRESS LastMapAddress; EFI_PHYSICAL_ADDRESS LastMapAddress;
EFI_PHYSICAL_ADDRESS LastMatAddress; EFI_PHYSICAL_ADDRESS LastMatAddress;
EFI_PHYSICAL_ADDRESS NewNextGluedAddress; EFI_PHYSICAL_ADDRESS NewNextGluedAddress;
EFI_PHYSICAL_ADDRESS NextGluedAddress; EFI_PHYSICAL_ADDRESS NextGluedAddress;
BOOLEAN LastMat; BOOLEAN LastMat;
MatIndex = 0; MatIndex = 0;
Status = EFI_NOT_FOUND; Status = EFI_NOT_FOUND;
...@@ -205,119 +205,129 @@ OcExpandAttributesByMap ( ...@@ -205,119 +205,129 @@ OcExpandAttributesByMap (
LastMapAddress = LAST_DESCRIPTOR_ADDR (MemoryMap); LastMapAddress = LAST_DESCRIPTOR_ADDR (MemoryMap);
NextGluedAddress = MemoryMap->PhysicalStart; NextGluedAddress = MemoryMap->PhysicalStart;
LastMat = FALSE;
while (MatIndex < MemoryAttributesTable->NumberOfEntries) { while (MatIndex < MemoryAttributesTable->NumberOfEntries && !LastMat) {
LastMatAddress = LAST_DESCRIPTOR_ADDR (MemoryAttributesEntry);
LastMat = MatIndex + 1 == MemoryAttributesTable->NumberOfEntries;
//
// Skip unsupported MAT type.
// Skip MAT entry relevant to not existent or older MAP entry,
// but only if it is not the last one.
//
if ((MemoryMap->Type != EfiRuntimeServicesCode && MemoryMap->Type != EfiRuntimeServicesData)
|| (LastMatAddress < MemoryMap->PhysicalStart && !LastMat)) {
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
++MatIndex;
continue;
}
// //
// 1. MAT entry at the beginning of MAP entry. // Process MAT with RT code or RT data type, which is the last one or resides at MAP entry or after.
// 2. MAT entry continuing previous MAT entry within MAP entry.
// MAT is required to be smaller or equal than MAP by UEFI spec.
// //
if (NextGluedAddress == MemoryAttributesEntry->PhysicalStart) { LastMatAddress = LAST_DESCRIPTOR_ADDR (MemoryAttributesEntry);
ASSERT (MemoryAttributesEntry->NumberOfPages <= MemoryMap->NumberOfPages); LastMat = MatIndex + 1 == MemoryAttributesTable->NumberOfEntries;
if (LastMatAddress == LastMapAddress) { if ((MemoryMap->Type == EfiRuntimeServicesCode || MemoryMap->Type == EfiRuntimeServicesData)
&& (LastMatAddress >= MemoryMap->PhysicalStart || LastMat)) {
//
// MAT is a suffix of MAP (MAT ends at MAP end).
//
if (NextGluedAddress == MemoryAttributesEntry->PhysicalStart
&& LastMatAddress == LastMapAddress) {
// //
// Completed iterating over this MAP entry. // Completed iterating over this MAP entry.
// //
break; break;
} }
ASSERT (LastMatAddress < LastMapAddress);
NextGluedAddress = LastMatAddress + 1;
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
++MatIndex;
continue;
}
//
// Have a hole between neighbouring MAT entries, 3 variants:
// - MAT is within MAP (but starts later).
// - MAT starts after MAP.
// - No MAT to cover MAP (this is the last MAT entry).
// Need to insert a new MAT entry to cover the hole.
//
if (MemoryAttributesTable->NumberOfEntries >= MaxDescriptors) {
return EFI_OUT_OF_RESOURCES;
}
if (!LastMat) {
//
// Choose the next processed address. This is the closest boundary for us:
// - First MAT address, when MAT is within MAP.
// - Last MAP address, when MAT starts after MAP.
//
NewNextGluedAddress = MIN (LastMapAddress + 1, MemoryAttributesEntry->PhysicalStart);
//
// Copy existing attributes to the right.
//
ASSERT (MemoryAttributesEntry->PhysicalStart > NextGluedAddress);
CopyMem (
NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, MemoryAttributesTable->DescriptorSize),
MemoryAttributesEntry,
(MemoryAttributesTable->NumberOfEntries - MatIndex) * MemoryAttributesTable->DescriptorSize
);
} else {
// //
// Adding up to the end of MAP, nothing to copy. // MAT is a prefix or an infix of MAP:
// 1. MAT entry at the beginning of MAP entry.
// 2. MAT entry continuing previous MAT entry within MAP entry.
// If this MAT is last, we have a hole in the end.
// //
ASSERT (MemoryAttributesEntry->PhysicalStart < NextGluedAddress); if (NextGluedAddress == MemoryAttributesEntry->PhysicalStart && !LastMat) {
NewNextGluedAddress = LastMapAddress + 1; //
} // MAT is required to be smaller or equal than MAP by UEFI spec.
// //
// Write the new attribute. ASSERT (MemoryAttributesEntry->NumberOfPages <= MemoryMap->NumberOfPages);
// NextGluedAddress = LastMatAddress + 1;
MemoryAttributesEntry->Type = OcRealMemoryType (MemoryMap); } else {
MemoryAttributesEntry->PhysicalStart = NextGluedAddress; //
MemoryAttributesEntry->VirtualStart = 0; // Have a hole between neighbouring MAT entries, 3 variants:
MemoryAttributesEntry->NumberOfPages = EFI_SIZE_TO_PAGES (NewNextGluedAddress - NextGluedAddress); // - MAT is within MAP (but starts later).
MemoryAttributesEntry->Attribute = EFI_MEMORY_RUNTIME; // - MAT starts after MAP.
if (MemoryAttributesEntry->Type == EfiRuntimeServicesCode) { // - No MAT fully covers MAP end (this is the last MAT entry).
MemoryAttributesEntry->Attribute |= EFI_MEMORY_RO; // Need to insert a new MAT entry to cover the hole.
} else { //
MemoryAttributesEntry->Attribute |= EFI_MEMORY_XP; if (MemoryAttributesTable->NumberOfEntries >= MaxDescriptors) {
} return EFI_OUT_OF_RESOURCES;
// }
// Increase the amount of entries and mark success.
// if (!LastMat) {
++MemoryAttributesTable->NumberOfEntries; //
Status = EFI_SUCCESS; // Append to the middle.
// // Choose the next processed address. This is the closest boundary for us:
// Choose the next processed address. // - First MAT address, when MAT is within MAP.
// // - Last MAP address, when MAT starts after MAP.
NextGluedAddress = NewNextGluedAddress; //
// NewNextGluedAddress = MIN (MemoryAttributesEntry->PhysicalStart, LastMapAddress + 1);
// Done processing MATs. //
// // Copy existing attributes to the right.
if (NextGluedAddress == LastMapAddress + 1) { //
break; ASSERT (MemoryAttributesEntry->PhysicalStart > NextGluedAddress);
CopyMem (
NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, MemoryAttributesTable->DescriptorSize),
MemoryAttributesEntry,
(MemoryAttributesTable->NumberOfEntries - MatIndex) * MemoryAttributesTable->DescriptorSize
);
} else {
//
// Append to the end.
// Next processed address is the end of MAP.
// There are no MATs left to copy.
//
NewNextGluedAddress = LastMapAddress + 1;
//
// If current MAT is a prefix or an infix of MAP, take it into account.
//
if (MemoryAttributesEntry->PhysicalStart == NextGluedAddress) {
NextGluedAddress = LastMatAddress + 1;
} else {
ASSERT (MemoryAttributesEntry->PhysicalStart < NextGluedAddress);
}
//
// Update current entry the new the last entry we are about to write.
//
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, MemoryAttributesTable->DescriptorSize);
++MatIndex;
}
//
// Write the new attribute.
//
MemoryAttributesEntry->Type = OcRealMemoryType (MemoryMap);
MemoryAttributesEntry->PhysicalStart = NextGluedAddress;
MemoryAttributesEntry->VirtualStart = 0;
MemoryAttributesEntry->NumberOfPages = EFI_SIZE_TO_PAGES (NewNextGluedAddress - NextGluedAddress);
MemoryAttributesEntry->Attribute = EFI_MEMORY_RUNTIME;
if (MemoryAttributesEntry->Type == EfiRuntimeServicesCode) {
MemoryAttributesEntry->Attribute |= EFI_MEMORY_RO;
} else {
MemoryAttributesEntry->Attribute |= EFI_MEMORY_XP;
}
//
// Update the next processed address.
// Increase the amount of MAT entries in the table.
// Report success.
//
NextGluedAddress = NewNextGluedAddress;
++MemoryAttributesTable->NumberOfEntries;
Status = EFI_SUCCESS;
//
// Done processing MATs.
//
if (NextGluedAddress == LastMapAddress + 1) {
break;
}
}
} }
// //
// Process next MAT. // Process next MAT.
// Do not increment if it is the last MAT, as we need to fill holes in the end.
// //
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR ( if (!LastMat) {
MemoryAttributesEntry, MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesTable->DescriptorSize MemoryAttributesEntry,
); MemoryAttributesTable->DescriptorSize
++MatIndex; );
++MatIndex;
}
} }
} }
...@@ -436,15 +446,17 @@ OcRebuildAttributes ( ...@@ -436,15 +446,17 @@ OcRebuildAttributes (
// as executable here. // as executable here.
// REF: https://github.com/acidanthera/bugtracker/issues/491#issuecomment-606835337 // REF: https://github.com/acidanthera/bugtracker/issues/491#issuecomment-606835337
// //
Status = OcUpdateDescriptors ( if (Address != 0) {
MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize, Status = OcUpdateDescriptors (
MemoryAttributesEntry, MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize,
MemoryAttributesTable->DescriptorSize, MemoryAttributesEntry,
Address, MemoryAttributesTable->DescriptorSize,
EfiRuntimeServicesCode, Address,
EFI_MEMORY_RO, EfiRuntimeServicesCode,
EFI_MEMORY_XP EFI_MEMORY_RO,
); EFI_MEMORY_XP
);
}
return Status; return Status;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册