1/* @title: Bootstage Runtime Patched Conditionals */
2#pragma once
3#include <bootstage.h>
4#include <compiler.h>
5#include <linker/symbols.h>
6#include <stdbool.h>
7
8enum bootstage_condition {
9 BOOTSTAGE_CONDITION_EQ,
10 BOOTSTAGE_CONDITION_LE,
11 BOOTSTAGE_CONDITION_LT,
12 BOOTSTAGE_CONDITION_GE,
13 BOOTSTAGE_CONDITION_GT,
14};
15
16struct bootstage_condition_entry {
17 void *code;
18 void *target;
19 enum bootstage_condition cond;
20 enum bootstage stage;
21};
22
23/* Essentially, the syntax we strive to achieve is
24 *
25 * BOOTSTAGE_IF_LE(cond) {} , such as
26 * BOOTSTAGE_IF_LT(BOOTSTAGE_LATE) {
27 * blah blah blah;
28 * }
29 *
30 */
31
32/* WARN: stage == BOOTSTAGE_EARLY_FB DOES NOT WORK, because at FB we don't
33 * have the kernel mapping in our control, and we can't write to it then
34 *
35 * NOTE: in theory, we could walk the early page tables and change perms,
36 * but this is tricky, and unless I have a super-hot-path that checks
37 * EARLY_FB, I don't see this as super useful */
38#define BOOTSTAGE_COND(cond, stage) \
39 ({ \
40 __label__ l_yes, l_done; \
41 bool _taken = false; \
42 asm goto("1:\n\t" \
43 ".byte 0xe9\n\t" \
44 ".long %l[l_yes] - (1b + 5)\n\t" \
45 ".pushsection .kernel_bootstage_condition_entries,\"aw\"\n\t" \
46 ".balign 8\n\t" \
47 ".quad 1b\n\t" \
48 ".quad %l[l_yes]\n\t" \
49 ".long %c[op]\n\t" \
50 ".long %c[stg]\n\t" \
51 ".popsection\n\t" \
52 : \
53 : [op] "i"(cond), [stg] "i"(stage) \
54 : \
55 : l_yes); \
56 goto l_done; \
57 l_yes: \
58 _taken = true; \
59 l_done: \
60 _taken; \
61 })
62
63#define BOOTSTAGE_IF_EQ(stage) \
64 if (BOOTSTAGE_COND(BOOTSTAGE_CONDITION_EQ, stage))
65#define BOOTSTAGE_IF_LE(stage) \
66 if (BOOTSTAGE_COND(BOOTSTAGE_CONDITION_LE, stage))
67#define BOOTSTAGE_IF_LT(stage) \
68 if (BOOTSTAGE_COND(BOOTSTAGE_CONDITION_LT, stage))
69#define BOOTSTAGE_IF_GE(stage) \
70 if (BOOTSTAGE_COND(BOOTSTAGE_CONDITION_GE, stage))
71#define BOOTSTAGE_IF_GT(stage) \
72 if (BOOTSTAGE_COND(BOOTSTAGE_CONDITION_GT, stage))
73
74LINKER_SECTION_DEFINE(struct bootstage_condition_entry,
75 bootstage_condition_entries);
76