aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@kernel.org>2015-11-25 15:01:24 -0800
committerLuis R. Rodriguez <mcgrof@kernel.org>2016-02-11 08:42:16 -0800
commite8036fd259991a930c70c8e495149bfe23a00eb3 (patch)
tree08b82939f628daa8a68fab89d95cf8d814898c76
parent5f1fb82afba714f0a9ef2c36ffce332d9fe0b46a (diff)
downloadlinker-tables-e8036fd259991a930c70c8e495149bfe23a00eb3.tar.gz
init: add supp_hardware_subarch feature detection
A typical issue when introducing new x86 features that require early init code modifications is not handling the different x86 supported subarchitectures. Code review typically addresses this, but regressions are known to have escaped code review, one example is cr4 shadow setup [0] which on Xen caused crashes, another more current was kasan [1], this later one is still known to be broken for Xen and will crash Xen on bootup when enabled. A typical knee-jerk reaction to this problem is to simply disable the feature through Kconfig when certain conflicting subarchitectures are compiled in, this however restricts the kernel binary. To address this at run time we can require feature subarchitecture capabilities annotated. By requiring these annotations we can avoid redundant code checks that would otherwise have handled incompatibitlies in different code segements for a feature, but more importantly this also forces clear developer awareness over required subarchitecture consideations upon development. As with the asm-generic solutions which enable generic architecture feature code to advance without requiring all architectures to implement required components, we enable x86 features to advance as different subarchitectures are supported. A subarch feature detection mechanism also allows us to clean up the feature depends() callback through the IOMMU init development solution considerably. [0] 5054daa285bea ("x86/xen: Initialize cr4 shadow for 64-bit PV(H) guests") [1] https://lkml.kernel.org/r/CAB=NE6Xs5fepzNtymzT4CueeJZ0KMPETpda114DpL4eMtDswtw@mail.gmail.com Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
-rw-r--r--bootparam.h14
-rw-r--r--driver.c2
-rw-r--r--init.c15
-rw-r--r--init.h14
-rw-r--r--kasan.c26
-rw-r--r--memory.c1
-rw-r--r--pci.c4
-rw-r--r--x86.c5
-rw-r--r--xen-driver.c13
-rw-r--r--xen.c9
10 files changed, 56 insertions, 47 deletions
diff --git a/bootparam.h b/bootparam.h
index a696c3a..a7ef342 100644
--- a/bootparam.h
+++ b/bootparam.h
@@ -1,3 +1,6 @@
+#ifndef __BOOTPARAM_H
+#define __BOOTPARAM_H
+
#include <linux/types.h>
struct setup_header {
@@ -16,3 +19,14 @@ enum {
X86_SUBARCH_CE4100,
X86_NR_SUBARCHS,
};
+
+#define X86_SUBARCH_ALL_SUBARCHS \
+ ( \
+ BIT(X86_SUBARCH_PC) | \
+ BIT(X86_SUBARCH_LGUEST) | \
+ BIT(X86_SUBARCH_XEN) | \
+ BIT(X86_SUBARCH_INTEL_MID) | \
+ BIT(X86_SUBARCH_CE4100) \
+ )
+
+#endif /* __BOOTPARAM_H */
diff --git a/driver.c b/driver.c
index 4c6715e..726f6f9 100644
--- a/driver.c
+++ b/driver.c
@@ -3,6 +3,7 @@
#include "init.h"
#include "pci.h"
+#include "kernel.h"
static int early_init_driver(void) {
sleep(2);
@@ -15,6 +16,7 @@ static int detect_driver(void) {
}
struct init_fn driver_init_fn __init_fn(INIT_EARLY) = {
+ .supp_hardware_subarch = BIT(X86_SUBARCH_PC),
.detect = detect_driver,
.depend = detect_pci,
.early_init = early_init_driver,
diff --git a/init.c b/init.c
index 179fdf9..35eac61 100644
--- a/init.c
+++ b/init.c
@@ -2,7 +2,20 @@
#include <unistd.h>
#include <errno.h>
+#include "kernel.h"
#include "init.h"
+#include "setup.h"
+
+static bool x86_init_supports_subarch(struct init_fn *fn)
+{
+ if (!fn->supp_hardware_subarch) {
+ printf("Init sequence fails to declares supported subarchs: %s\n", fn->name);
+ WARN_ON(1);
+ }
+ if (BIT(boot_params.hdr.hardware_subarch) & fn->supp_hardware_subarch)
+ return true;
+ return false;
+}
int early_init(void)
{
@@ -14,6 +27,8 @@ int early_init(void)
printf("Number of init entries: %d\n", num_inits);
for_each_table_entry(init_fn, INIT_FNS) {
+ if (!x86_init_supports_subarch(init_fn))
+ continue;
if (!init_fn->detect)
init_fn->flags |= INIT_DETECTED;
else {
diff --git a/init.h b/init.h
index 25acd22..3f5d7d6 100644
--- a/init.h
+++ b/init.h
@@ -39,8 +39,21 @@
* mode and even after setup_arch(), which is not Xen specific.
*
* Further evaluation of this use is currently being done.
+ *
+ * Must be set, it represents the bitmask of supported subarchitectures.
+ * We require each init sequence to have this set to require developer
+ * considerations for each supported x86 subarchitecture, and to avoid
+ * unexpected unsupported running feature code in unsupported or vetted
+ * subarchitectures.
+ *
+ * Each supported subarchitecture is set using the respective
+ * X86_SUBARCH_* as a bit in the bitmask. For instance if a feature
+ * is supported only PC and Xen only you would set this bitmask to:
+ * BIT(X86_SUBARCH_PC) |
+ * BIT(X86_SUBARCH_XEN);
*/
struct init_fn {
+ __u32 supp_hardware_subarch;
int (*detect)(void);
int (*depend)(void);
int (*early_init)(void); /* No memory allocate available. */
@@ -51,7 +64,6 @@ struct init_fn {
#define INIT_FINISH_IF_DETECTED (1<<0)
#define INIT_DETECTED (1<<1)
int flags;
- __u32 supp_hardware_subarch;
};
/** Initialisation function table */
diff --git a/kasan.c b/kasan.c
index 8a22998..d5fedc7 100644
--- a/kasan.c
+++ b/kasan.c
@@ -3,29 +3,21 @@
#include <errno.h>
#include "init.h"
#include "kernel.h"
-
-static bool __is_kasan_setup = false;
+#include "bootparam.h"
int kasan_early_init(void) {
printf("Early init for Kasan...\n");
- __is_kasan_setup = true;
return 0;
}
-bool is_kasan_setup(void)
-{
- return __is_kasan_setup;
-}
-
-int kasan_init(void)
+void kasan_init(void)
{
- if (!__is_kasan_setup) {
- printf("Kasan was not set up...\n");
- BUG();
- return -EINVAL;
- }
-
printf("Calling setup_arch work for Kasan...\n");
-
- return 0;
}
+
+struct init_fn kasan_init_fn __init_fn(INIT_EARLY) = {
+ .supp_hardware_subarch = BIT(X86_SUBARCH_PC),
+ .early_init = kasan_early_init,
+ .setup_arch = kasan_init,
+ .name = "Kasan",
+};
diff --git a/memory.c b/memory.c
index a433c84..c379c04 100644
--- a/memory.c
+++ b/memory.c
@@ -15,6 +15,7 @@ static int detect_memory(void) {
}
struct init_fn memory_init_fn __init_fn(INIT_EARLY) = {
+ .supp_hardware_subarch = X86_SUBARCH_ALL_SUBARCHS,
.detect = detect_memory,
.early_init = early_init_memory,
.name = "Memory",
diff --git a/pci.c b/pci.c
index 30b524b..9e41703 100644
--- a/pci.c
+++ b/pci.c
@@ -18,11 +18,9 @@ int detect_pci(void) {
}
struct init_fn pci_init_fn __init_fn(INIT_NORMAL) = {
+ .supp_hardware_subarch = X86_SUBARCH_ALL_SUBARCHS,
.detect = detect_pci,
.early_init = early_init_pci,
.name = "PCI buses",
.critical = true,
- .supp_hardware_subarch =
- X86_SUBARCH_PC |
- X86_SUBARCH_XEN,
};
diff --git a/x86.c b/x86.c
index 6c46649..4d65005 100644
--- a/x86.c
+++ b/x86.c
@@ -50,10 +50,6 @@ static int x86_64_start_kernel(void)
return ret;
}
- ret = kasan_early_init();
- if (ret)
- return ret;
-
return x86_64_start_reservations();
}
@@ -66,5 +62,4 @@ int startup_64(void)
void setup_arch(void)
{
setup_arch_init();
- kasan_init();
}
diff --git a/xen-driver.c b/xen-driver.c
index 08e8fc5..d3d0c4f 100644
--- a/xen-driver.c
+++ b/xen-driver.c
@@ -11,19 +11,8 @@ static int early_xen_init_driver(void) {
return 0;
}
-static int detect_xen_driver(void) {
- /* XXX: replace with a hook annotation, this is fragile as
- * it requires the developer to know and it means some folks
- * may not be setting these checks elsewhere.
- */
- if (!booting_xen())
- return 0;
-
- return 1;
-}
-
struct init_fn driver_xen_init_fn __init_fn(INIT_NORMAL) = {
- .detect = detect_xen_driver,
+ .supp_hardware_subarch = BIT(X86_SUBARCH_XEN),
.depend = detect_pci,
.early_init = early_xen_init_driver,
.name = "Xen Driver",
diff --git a/xen.c b/xen.c
index 9c0a9eb..68269eb 100644
--- a/xen.c
+++ b/xen.c
@@ -6,19 +6,10 @@
extern struct init_fn __tbl[], __tbl_end[];
-static bool __booting_xen = false;
-
-bool booting_xen(void)
-{
- return __booting_xen;
-}
-
int startup_xen(void)
{
int ret;
- __booting_xen = true;
-
sort_table(__tbl, __tbl_end);
check_table_entries(__tbl, __tbl_end);