|
Replace traditional `#ifndef`/`#define`/`#endif` include guards with
`#pragma` once.
`#pragma once` is a widely supported preprocessor directive that
prevents header files from being included multiple times. It is
supported by all toolchains used to build edk2: GCC, Clang/LLVM, and
MSVC.
Note: Headers taken directly from external projects, such as those
in OvmfPkg/Include/IndustryStandard/Xen/ were not modified since they
may be periodically re-synced and do not follow other edk2 coding
stadards.
Compared to macro-based include guards, `#pragma once`:
- Eliminates the risk of macro name collisions or copy/paste errors
where two headers inadvertently use the same guard macro.
- Eliminate inconsistency in the way include guard macros are named
(e.g., some files use `__FILE_H__`, others use `FILE_H_`, etc.).
- Reduces boilerplate (three lines replaced by one).
- Avoids polluting the macro namespace with guard symbols.
- Can improve build times as the preprocessor can skip re-opening the
file entirely, rather than re-reading it to find the matching
`#endif` ("multiple-include optimization").
- Note that some compilers may already optimize traditional include
guards, by recognzining the idiomatic pattern.
This change is made acknowledging that overall portability of the
code will technically be reduced, as `#pragma once` is not part of the
C/C++ standards.
However, this is considered acceptable given:
1. edk2 already defines a subset of supported compilers in
BaseTools/Conf/tools_def.template, all of which have supported
`#pragma once` for over two decades.
2. There have been concerns raised to the project about inconsistent
include guard naming and potential macro collisions.
Approximate compiler support dates:
- MSVC: Supported since Visual C++ 4.2 (1996)
- GCC: Supported since 3.4 (2004)
(http://gnu.ist.utl.pt/software/gcc/gcc-3.4/changes.html)
- Clang (LLVM based): Since initial release in 2007
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
|
|
UEFI requires us to support nested interrupts, but provides no way for
an interrupt handler to call RestoreTPL() without implicitly
re-enabling interrupts. In a virtual machine, it is possible for a
large burst of interrupts to arrive. We must prevent such a burst
from leading to stack underrun, while continuing to allow nested
interrupts to occur.
This can be achieved by allowing, when provably safe to do so, an
inner interrupt handler to return from the interrupt without restoring
the TPL and with interrupts remaining disabled after IRET, with the
deferred call to RestoreTPL() then being issued from the outer
interrupt handler. This is necessarily messy and involves direct
manipulation of the interrupt stack frame, and so should not be
implemented as open-coded logic within each interrupt handler.
Add the Nested Interrupt TPL Library (NestedInterruptTplLib) to
provide helper functions that can be used by nested interrupt handlers
in place of RaiseTPL()/RestoreTPL().
Example call tree for a timer interrupt occurring at TPL_APPLICATION
with a nested timer interrupt that makes its own call to RestoreTPL():
outer TimerInterruptHandler()
InterruptedTPL == TPL_APPLICATION
...
IsrState->InProgressRestoreTPL = TPL_APPLICATION;
gBS->RestoreTPL (TPL_APPLICATION);
EnableInterrupts();
dispatch a TPL_CALLBACK event
gEfiCurrentTpl = TPL_CALLBACK;
nested timer interrupt occurs
inner TimerInterruptHandler()
InterruptedTPL == TPL_CALLBACK
...
IsrState->InProgressRestoreTPL = TPL_CALLBACK;
gBS->RestoreTPL (TPL_CALLBACK);
EnableInterrupts();
DisableInterrupts();
IsrState->InProgressRestoreTPL = TPL_APPLICATION;
IRET re-enables interrupts
... finish dispatching TPL_CALLBACK events ...
gEfiCurrentTpl = TPL_APPLICATION;
DisableInterrupts();
IsrState->InProgressRestoreTPL = 0;
sees IsrState->DeferredRestoreTPL == FALSE and returns
IRET re-enables interrupts
Example call tree for a timer interrupt occurring at TPL_APPLICATION
with a nested timer interrupt that defers its call to RestoreTPL() to
the outer instance of the interrupt handler:
outer TimerInterruptHandler()
InterruptedTPL == TPL_APPLICATION
...
IsrState->InProgressRestoreTPL = TPL_APPLICATION;
gBS->RestoreTPL (TPL_APPLICATION);
EnableInterrupts();
dispatch a TPL_CALLBACK event
... finish dispatching TPL_CALLBACK events ...
gEfiCurrentTpl = TPL_APPLICATION;
nested timer interrupt occurs
inner TimerInterruptHandler()
InterruptedTPL == TPL_APPLICATION;
...
sees InterruptedTPL == IsrState->InProgressRestoreTPL
IsrState->DeferredRestoreTPL = TRUE;
DisableInterruptsOnIret();
IRET returns without re-enabling interrupts
DisableInterrupts();
IsrState->InProgressRestoreTPL = 0;
sees IsrState->DeferredRestoreTPL == TRUE and loops
IsrState->InProgressRestoreTPL = TPL_APPLICATION;
gBS->RestoreTPL (TPL_APPLICATION); <-- deferred call
EnableInterrupts();
DisableInterrupts();
IsrState->InProgressRestoreTPL = 0;
sees IsrState->DeferredRestoreTPL == FALSE and returns
IRET re-enables interrupts
Cc: Paolo Bonzini <pbonzini@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=4162
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Acked-by: Laszlo Ersek <lersek@redhat.com>
|