blob: 2490dc7076ee8a7b4c231307688fb418b8e014a0 [file]
#ifndef __X86_INIT_TABLES_H
#define __X86_INIT_TABLES_H
#include <linux/types.h>
#include <linux/tables.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <asm/bootparam.h>
/**
* struct x86_init_fn - x86 generic kernel init call
*
* Linux x86 features vary in complexity, features may require work done at
* different levels of the full x86 init sequence. Today there are also two
* different possible entry points for Linux on x86, one for bare metal, KVM
* and Xen HVM, and another for Xen PV guests / dom0. Assuming a bootloader
* has set up 64-bit mode, roughly the x86 init sequence follows this path:
*
* Bare metal, KVM, Xen HVM Xen PV / dom0
* startup_64() startup_xen()
* \ /
* x86_64_start_kernel() xen_start_kernel()
* \ /
* x86_64_start_reservations()
* |
* start_kernel()
* [ ... ]
* [ setup_arch() ]
* [ ... ]
* init
*
* x86_64_start_kernel() and xen_start_kernel() are the respective first C code
* entry starting points. The different entry points exist to enable Xen to
* skip a lot of hardware setup already done and managed on behalf of the
* hypervisor, we refer to this as "paravirtualization yielding". The different
* levels of init calls on the x86 init sequence exist to account for these
* slight differences and requirements. These different entry points also share
* a common entry x86 specific path, x86_64_start_reservations().
*
* A generic x86 feature can have different initialization calls, one on each
* of the different main x86 init sequences, but must also address both entry
* points in order to work properly across the board on all supported x86
* subarchitectures. Since x86 features can also have dependencies on other
* setup code or features, x86 features can at times be subordinate to other
* x86 features, or conditions. struct x86_init_fn enables feature developers
* to annotate dependency relationships to ensure subsequent init calls only
* run once a subordinate's dependencies have run. When needed custom
* dependency requirements can also be spelled out through a custom dependency
* checker. In order to account for the dual entry point nature of x86-64 Linux
* for "paravirtualization yielding" and to make annotations for support for
* these explicit each struct x86_init_fn must specify supported
* subarchitectures. The earliest x86-64 code can read the subarchitecture
* though is after load_idt(), as such the earliest we can currently rely on
* subarchitecture for semantics and a common init sequences is on the shared
* common x86_64_start_reservations(). Each struct x86_init_fn is associated
* with a specific special link order number which has been careflly thought
* out by x86 maintainers. You should pick a link order level associated with
* the specific directory your code lies in, a respective macro is used to
* build association to a link oder with a routine, you should use one of the
* provided x86_init_*() macros. You should not use __x86_init() directly.
*
* x86_init_fn enables strong semantics and dependencies to be defined and
* implemented on the full x86 initialization sequence.
*
* @supp_hardware_subarch: must be set, it represents the bitmask of supported
* subarchitectures. We require each struct x86_init_fn to have this set
* to require developer considerations for each supported x86
* subarchitecture and to build strong annotations of different possible
* run time states particularly in consideration for the two main
* different entry points for x86 Linux, to account for paravirtualization
* yielding.
*
* The subarchitecture is read by the kernel at early boot from the
* struct boot_params hardware_subarch. Support for the subarchitecture
* exists as of x86 boot protocol 2.07. The bootloader would have set up
* the respective hardware_subarch on the boot sector as per
* Documentation/x86/boot.txt.
*
* What x86 entry point is used is determined at run time by the
* bootloader. Linux pv_ops was designed to help enable to build one Linux
* binary to support bare metal and different hypervisors. pv_ops setup
* code however is limited in that all pv_ops setup code is run late in
* the x86 init sequence, during setup_arch(). In fact cpu_has_hypervisor
* only works after early_cpu_init() during setup_arch(). If an x86
* feature requires an earlier determination of what hypervisor was used,
* or if it needs to annotate only support for certain hypervisors, the
* x86 hardware_subarch should be set by the bootloader and
* @supp_hardware_subarch set by the x86 feature. Using hardware_subarch
* enables x86 features to fill the semantic gap between the Linux x86
* entry point used and what pv_ops has to offer through a hypervisor
* agnostic mechanism.
*
* Each supported subarchitecture is set using the respective
* X86_SUBARCH_* as a bit in the bitmask. For instance if a feature
* is supported on PC and Xen subarchitectures only you would set this
* bitmask to:
*
* BIT(X86_SUBARCH_PC) |
* BIT(X86_SUBARCH_XEN);
*
* @early_init: required, routine which will run in x86_64_start_reservations()
* after we ensure boot_params.hdr.hardware_subarch is accessible and
* properly set. Memory is not yet available. This the earliest we can
* currently define a common shared callback since all callbacks need to
* check for boot_params.hdr.hardware_subarch and this becomes accessible
* on x86-64 until after load_idt().
*/
struct x86_init_fn {
__u32 supp_hardware_subarch;
void (*early_init)(void);
};
DECLARE_LINKTABLE(struct x86_init_fn, x86_init_fns);
/* Init order levels, we can start at 0000 but reserve 0000-0999 for now */
/*
* X86_INIT_ORDER_EARLY - early kernel init code
*
* This consists of the first parts of the Linux kernel executed.
*/
#define X86_INIT_ORDER_EARLY 1000
/* X86_INIT_ORDER_PLATFORM - platform kernel code
*
* Code the kernel needs to initialize under arch/x86/platform/
* early in boot.
*/
#define X86_INIT_ORDER_PLATFORM 3000
/*
* Use LTO_REFERENCE_INITCALL just in case of issues with old versions of gcc.
* This might not be needed for linker tables due to how we compartamentalize
* sections and then order them at linker time, but just in case.
*/
#define __x86_init(__level, \
__supp_hardware_subarch, \
__early_init) \
static LINKTABLE_INIT_DATA(x86_init_fns, __level) \
__x86_init_fn_##__early_init = { \
.supp_hardware_subarch = __supp_hardware_subarch, \
.early_init = __early_init, \
}; \
LTO_REFERENCE_INITCALL(__x86_init_fn_##__early_init);
#define x86_init_early(__supp_hardware_subarch, \
__early_init) \
__x86_init(X86_INIT_ORDER_EARLY, __supp_hardware_subarch, \
__early_init);
#define x86_init_platform(__supp_hardware_subarch, \
__early_init) \
__x86_init(__name, X86_INIT_ORDER_PLATFORM, __supp_hardware_subarch,\
__early_init);
#define x86_init_early_all(__early_init) \
x86_init_early(X86_SUBARCH_ALL_SUBARCHS, \
__early_init);
#define x86_init_early_pc(__early_init) \
x86_init_early(BIT(X86_SUBARCH_PC), \
__early_init);
#define x86_init_early_xen(__early_init) \
x86_init_early(BIT(X86_SUBARCH_XEN), \
__early_init);
/**
* x86_init_fn_early_init: call all early_init() callbacks
*
* This calls all early_init() callbacks on the x86_init_fns linker table.
*/
void x86_init_fn_early_init(void);
#endif /* __X86_INIT_TABLES_H */