diff mbox series

[2/4] xen/virtual-region: Rework how bugframe linkage works

Message ID 20240318110442.3653997-3-andrew.cooper3@citrix.com (mailing list archive)
State Superseded
Headers show
Series xen/arch: Simplify virtual_region setup | expand

Commit Message

Andrew Cooper March 18, 2024, 11:04 a.m. UTC
The start/stop1/etc linkage scheme predates struct virtual_region, and as
setup_virtual_regions() shows, it's awkward to express in the new scheme.

Change the linker to provide explicit start/stop symbols for each bugframe
type, and change virtual_region to have a stop pointer rather than a count.

This marginly simplifies both do_bug_frame()s and prepare_payload(), but it
massively simplifies setup_virtual_regions() by allowing the compiler to
initialise the .frame[] array at build time.

virtual_region.c is the only user of the linker symbols, and this is unlikely
to change given the purpose of struct virtual_region, so move their externs
out of bug.h

No functional change.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Wei Liu <wl@xen.org>
CC: Stefano Stabellini <sstabellini@kernel.org>
CC: Julien Grall <julien@xen.org>
CC: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
CC: Bertrand Marquis <bertrand.marquis@arm.com>
CC: Michal Orzel <michal.orzel@amd.com>
CC: Oleksii Kurochko <oleksii.kurochko@gmail.com>
CC: Shawn Anastasio <sanastasio@raptorengineering.com>
CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
CC: Ross Lagerwall <ross.lagerwall@citrix.com>
---
 xen/arch/arm/traps.c             |  5 ++--
 xen/common/bug.c                 |  5 ++--
 xen/common/livepatch.c           |  7 +++--
 xen/common/virtual_region.c      | 45 ++++++++++++++------------------
 xen/include/xen/bug.h            |  6 -----
 xen/include/xen/virtual_region.h |  3 +--
 xen/include/xen/xen.lds.h        |  8 +++++-
 7 files changed, 35 insertions(+), 44 deletions(-)

Comments

Jan Beulich March 18, 2024, 1:17 p.m. UTC | #1
On 18.03.2024 12:04, Andrew Cooper wrote:
> The start/stop1/etc linkage scheme predates struct virtual_region, and as
> setup_virtual_regions() shows, it's awkward to express in the new scheme.
> 
> Change the linker to provide explicit start/stop symbols for each bugframe
> type, and change virtual_region to have a stop pointer rather than a count.
> 
> This marginly simplifies both do_bug_frame()s and prepare_payload(), but it
> massively simplifies setup_virtual_regions() by allowing the compiler to
> initialise the .frame[] array at build time.
> 
> virtual_region.c is the only user of the linker symbols, and this is unlikely
> to change given the purpose of struct virtual_region, so move their externs
> out of bug.h
> 
> No functional change.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Reviewed-by: Jan Beulich <jbeulich@suse.com>

Of course ...

> --- a/xen/common/virtual_region.c
> +++ b/xen/common/virtual_region.c
> @@ -9,12 +9,25 @@
>  #include <xen/spinlock.h>
>  #include <xen/virtual_region.h>
>  
> +extern const struct bug_frame
> +    __start_bug_frames_0[], __stop_bug_frames_0[],
> +    __start_bug_frames_1[], __stop_bug_frames_1[],
> +    __start_bug_frames_2[], __stop_bug_frames_2[],
> +    __start_bug_frames_3[], __stop_bug_frames_3[];
> +
>  static struct virtual_region core = {
>      .list = LIST_HEAD_INIT(core.list),
>      .text_start = _stext,
>      .text_end = _etext,
>      .rodata_start = _srodata,
>      .rodata_end = _erodata,
> +
> +    .frame = {
> +        { __start_bug_frames_0, __stop_bug_frames_0 },
> +        { __start_bug_frames_1, __stop_bug_frames_1 },
> +        { __start_bug_frames_2, __stop_bug_frames_2 },
> +        { __start_bug_frames_3, __stop_bug_frames_3 },
> +    },
>  };
>  
>  /* Becomes irrelevant when __init sections are cleared. */
> @@ -22,6 +35,13 @@ static struct virtual_region core_init __initdata = {
>      .list = LIST_HEAD_INIT(core_init.list),
>      .text_start = _sinittext,
>      .text_end = _einittext,
> +
> +    .frame = {
> +        { __start_bug_frames_0, __stop_bug_frames_0 },
> +        { __start_bug_frames_1, __stop_bug_frames_1 },
> +        { __start_bug_frames_2, __stop_bug_frames_2 },
> +        { __start_bug_frames_3, __stop_bug_frames_3 },
> +    },
>  };

... this is now calling yet louder for splitting runtime from init bug
frame records.

Jan
Andrew Cooper March 18, 2024, 1:24 p.m. UTC | #2
On 18/03/2024 1:17 pm, Jan Beulich wrote:
> On 18.03.2024 12:04, Andrew Cooper wrote:
>> The start/stop1/etc linkage scheme predates struct virtual_region, and as
>> setup_virtual_regions() shows, it's awkward to express in the new scheme.
>>
>> Change the linker to provide explicit start/stop symbols for each bugframe
>> type, and change virtual_region to have a stop pointer rather than a count.
>>
>> This marginly simplifies both do_bug_frame()s and prepare_payload(), but it
>> massively simplifies setup_virtual_regions() by allowing the compiler to
>> initialise the .frame[] array at build time.
>>
>> virtual_region.c is the only user of the linker symbols, and this is unlikely
>> to change given the purpose of struct virtual_region, so move their externs
>> out of bug.h
>>
>> No functional change.
>>
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> Reviewed-by: Jan Beulich <jbeulich@suse.com>

Thanks.

>
> Of course ...
>
>> --- a/xen/common/virtual_region.c
>> +++ b/xen/common/virtual_region.c
>> @@ -9,12 +9,25 @@
>>  #include <xen/spinlock.h>
>>  #include <xen/virtual_region.h>
>>  
>> +extern const struct bug_frame
>> +    __start_bug_frames_0[], __stop_bug_frames_0[],
>> +    __start_bug_frames_1[], __stop_bug_frames_1[],
>> +    __start_bug_frames_2[], __stop_bug_frames_2[],
>> +    __start_bug_frames_3[], __stop_bug_frames_3[];
>> +
>>  static struct virtual_region core = {
>>      .list = LIST_HEAD_INIT(core.list),
>>      .text_start = _stext,
>>      .text_end = _etext,
>>      .rodata_start = _srodata,
>>      .rodata_end = _erodata,
>> +
>> +    .frame = {
>> +        { __start_bug_frames_0, __stop_bug_frames_0 },
>> +        { __start_bug_frames_1, __stop_bug_frames_1 },
>> +        { __start_bug_frames_2, __stop_bug_frames_2 },
>> +        { __start_bug_frames_3, __stop_bug_frames_3 },
>> +    },
>>  };
>>  
>>  /* Becomes irrelevant when __init sections are cleared. */
>> @@ -22,6 +35,13 @@ static struct virtual_region core_init __initdata = {
>>      .list = LIST_HEAD_INIT(core_init.list),
>>      .text_start = _sinittext,
>>      .text_end = _einittext,
>> +
>> +    .frame = {
>> +        { __start_bug_frames_0, __stop_bug_frames_0 },
>> +        { __start_bug_frames_1, __stop_bug_frames_1 },
>> +        { __start_bug_frames_2, __stop_bug_frames_2 },
>> +        { __start_bug_frames_3, __stop_bug_frames_3 },
>> +    },
>>  };
> ... this is now calling yet louder for splitting runtime from init bug
> frame records.

How do you propose we do this?

We can probably do it for *.init.o objects by renaming the bugframe
sections too, but unless we can do it for *every* bugframe emitted in
all init code, splitting this will break things.

~Andrew
Jan Beulich March 18, 2024, 1:31 p.m. UTC | #3
On 18.03.2024 14:24, Andrew Cooper wrote:
> On 18/03/2024 1:17 pm, Jan Beulich wrote:
>> On 18.03.2024 12:04, Andrew Cooper wrote:
>>> --- a/xen/common/virtual_region.c
>>> +++ b/xen/common/virtual_region.c
>>> @@ -9,12 +9,25 @@
>>>  #include <xen/spinlock.h>
>>>  #include <xen/virtual_region.h>
>>>  
>>> +extern const struct bug_frame
>>> +    __start_bug_frames_0[], __stop_bug_frames_0[],
>>> +    __start_bug_frames_1[], __stop_bug_frames_1[],
>>> +    __start_bug_frames_2[], __stop_bug_frames_2[],
>>> +    __start_bug_frames_3[], __stop_bug_frames_3[];
>>> +
>>>  static struct virtual_region core = {
>>>      .list = LIST_HEAD_INIT(core.list),
>>>      .text_start = _stext,
>>>      .text_end = _etext,
>>>      .rodata_start = _srodata,
>>>      .rodata_end = _erodata,
>>> +
>>> +    .frame = {
>>> +        { __start_bug_frames_0, __stop_bug_frames_0 },
>>> +        { __start_bug_frames_1, __stop_bug_frames_1 },
>>> +        { __start_bug_frames_2, __stop_bug_frames_2 },
>>> +        { __start_bug_frames_3, __stop_bug_frames_3 },
>>> +    },
>>>  };
>>>  
>>>  /* Becomes irrelevant when __init sections are cleared. */
>>> @@ -22,6 +35,13 @@ static struct virtual_region core_init __initdata = {
>>>      .list = LIST_HEAD_INIT(core_init.list),
>>>      .text_start = _sinittext,
>>>      .text_end = _einittext,
>>> +
>>> +    .frame = {
>>> +        { __start_bug_frames_0, __stop_bug_frames_0 },
>>> +        { __start_bug_frames_1, __stop_bug_frames_1 },
>>> +        { __start_bug_frames_2, __stop_bug_frames_2 },
>>> +        { __start_bug_frames_3, __stop_bug_frames_3 },
>>> +    },
>>>  };
>> ... this is now calling yet louder for splitting runtime from init bug
>> frame records.
> 
> How do you propose we do this?
> 
> We can probably do it for *.init.o objects by renaming the bugframe
> sections too, but unless we can do it for *every* bugframe emitted in
> all init code, splitting this will break things.

On halfway recent toolchains we can pass -Wa,--sectname-subst and then
construct section names derived from the containing text ones.

Jan
Ross Lagerwall March 18, 2024, 5:20 p.m. UTC | #4
On Mon, Mar 18, 2024 at 11:04 AM Andrew Cooper
<andrew.cooper3@citrix.com> wrote:
>
> The start/stop1/etc linkage scheme predates struct virtual_region, and as
> setup_virtual_regions() shows, it's awkward to express in the new scheme.
>
> Change the linker to provide explicit start/stop symbols for each bugframe
> type, and change virtual_region to have a stop pointer rather than a count.
>
> This marginly simplifies both do_bug_frame()s and prepare_payload(), but it
> massively simplifies setup_virtual_regions() by allowing the compiler to
> initialise the .frame[] array at build time.
>
> virtual_region.c is the only user of the linker symbols, and this is unlikely
> to change given the purpose of struct virtual_region, so move their externs
> out of bug.h
>
> No functional change.
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Reviewed-by: Ross Lagerwall <ross.lagerwall@citrix.com>
diff mbox series

Patch

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 9cffe7f79005..a8039087c805 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1226,10 +1226,9 @@  int do_bug_frame(const struct cpu_user_regs *regs, vaddr_t pc)
         for ( id = 0; id < BUGFRAME_NR; id++ )
         {
             const struct bug_frame *b;
-            unsigned int i;
 
-            for ( i = 0, b = region->frame[id].bugs;
-                  i < region->frame[id].n_bugs; b++, i++ )
+            for ( b = region->frame[id].start;
+                  b < region->frame[id].stop; b++ )
             {
                 if ( ((vaddr_t)bug_loc(b)) == pc )
                 {
diff --git a/xen/common/bug.c b/xen/common/bug.c
index c43e7c439735..b7c5d8fd4d4a 100644
--- a/xen/common/bug.c
+++ b/xen/common/bug.c
@@ -25,10 +25,9 @@  int do_bug_frame(const struct cpu_user_regs *regs, unsigned long pc)
     for ( id = 0; id < BUGFRAME_NR; id++ )
     {
         const struct bug_frame *b;
-        size_t i;
 
-        for ( i = 0, b = region->frame[id].bugs;
-              i < region->frame[id].n_bugs; b++, i++ )
+        for ( b = region->frame[id].start;
+              b < region->frame[id].stop; b++ )
         {
             if ( bug_loc(b) == pc )
             {
diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
index cabfb6391117..351a3e0b9a60 100644
--- a/xen/common/livepatch.c
+++ b/xen/common/livepatch.c
@@ -804,12 +804,11 @@  static int prepare_payload(struct payload *payload,
         if ( !sec )
             continue;
 
-        if ( !section_ok(elf, sec, sizeof(*region->frame[i].bugs)) )
+        if ( !section_ok(elf, sec, sizeof(*region->frame[i].start)) )
             return -EINVAL;
 
-        region->frame[i].bugs = sec->load_addr;
-        region->frame[i].n_bugs = sec->sec->sh_size /
-                                  sizeof(*region->frame[i].bugs);
+        region->frame[i].start = sec->load_addr;
+        region->frame[i].stop  = sec->load_addr + sec->sec->sh_size;
     }
 
     sec = livepatch_elf_sec_by_name(elf, ".altinstructions");
diff --git a/xen/common/virtual_region.c b/xen/common/virtual_region.c
index b4325bcda71e..eb9645daa99d 100644
--- a/xen/common/virtual_region.c
+++ b/xen/common/virtual_region.c
@@ -9,12 +9,25 @@ 
 #include <xen/spinlock.h>
 #include <xen/virtual_region.h>
 
+extern const struct bug_frame
+    __start_bug_frames_0[], __stop_bug_frames_0[],
+    __start_bug_frames_1[], __stop_bug_frames_1[],
+    __start_bug_frames_2[], __stop_bug_frames_2[],
+    __start_bug_frames_3[], __stop_bug_frames_3[];
+
 static struct virtual_region core = {
     .list = LIST_HEAD_INIT(core.list),
     .text_start = _stext,
     .text_end = _etext,
     .rodata_start = _srodata,
     .rodata_end = _erodata,
+
+    .frame = {
+        { __start_bug_frames_0, __stop_bug_frames_0 },
+        { __start_bug_frames_1, __stop_bug_frames_1 },
+        { __start_bug_frames_2, __stop_bug_frames_2 },
+        { __start_bug_frames_3, __stop_bug_frames_3 },
+    },
 };
 
 /* Becomes irrelevant when __init sections are cleared. */
@@ -22,6 +35,13 @@  static struct virtual_region core_init __initdata = {
     .list = LIST_HEAD_INIT(core_init.list),
     .text_start = _sinittext,
     .text_end = _einittext,
+
+    .frame = {
+        { __start_bug_frames_0, __stop_bug_frames_0 },
+        { __start_bug_frames_1, __stop_bug_frames_1 },
+        { __start_bug_frames_2, __stop_bug_frames_2 },
+        { __start_bug_frames_3, __stop_bug_frames_3 },
+    },
 };
 
 /*
@@ -133,31 +153,6 @@  void __init unregister_init_virtual_region(void)
 void __init setup_virtual_regions(const struct exception_table_entry *start,
                                   const struct exception_table_entry *end)
 {
-    size_t sz;
-    unsigned int i;
-    static const struct bug_frame *const __initconstrel bug_frames[] = {
-        __start_bug_frames,
-        __stop_bug_frames_0,
-        __stop_bug_frames_1,
-        __stop_bug_frames_2,
-        __stop_bug_frames_3,
-        NULL
-    };
-
-    for ( i = 1; bug_frames[i]; i++ )
-    {
-        const struct bug_frame *s;
-
-        s = bug_frames[i - 1];
-        sz = bug_frames[i] - s;
-
-        core.frame[i - 1].n_bugs = sz;
-        core.frame[i - 1].bugs = s;
-
-        core_init.frame[i - 1].n_bugs = sz;
-        core_init.frame[i - 1].bugs = s;
-    }
-
     core_init.ex = core.ex = start;
     core_init.ex_end = core.ex_end = end;
 
diff --git a/xen/include/xen/bug.h b/xen/include/xen/bug.h
index 77fe1e1ba840..99814c4bef36 100644
--- a/xen/include/xen/bug.h
+++ b/xen/include/xen/bug.h
@@ -155,12 +155,6 @@  int do_bug_frame(const struct cpu_user_regs *regs, unsigned long pc);
 
 #endif /* CONFIG_GENERIC_BUG_FRAME */
 
-extern const struct bug_frame __start_bug_frames[],
-                              __stop_bug_frames_0[],
-                              __stop_bug_frames_1[],
-                              __stop_bug_frames_2[],
-                              __stop_bug_frames_3[];
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __XEN_BUG_H__ */
diff --git a/xen/include/xen/virtual_region.h b/xen/include/xen/virtual_region.h
index dcdc95ba494c..c8a90e3ef26d 100644
--- a/xen/include/xen/virtual_region.h
+++ b/xen/include/xen/virtual_region.h
@@ -29,8 +29,7 @@  struct virtual_region
     symbols_lookup_t *symbols_lookup;
 
     struct {
-        const struct bug_frame *bugs; /* The pointer to array of bug frames. */
-        size_t n_bugs;          /* The number of them. */
+        const struct bug_frame *start, *stop; /* Pointers to array of bug frames. */
     } frame[BUGFRAME_NR];
 
     const struct exception_table_entry *ex;
diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h
index decd6db5fc6d..96f86ac58f38 100644
--- a/xen/include/xen/xen.lds.h
+++ b/xen/include/xen/xen.lds.h
@@ -105,13 +105,19 @@ 
 /* List of constructs other than *_SECTIONS in alphabetical order. */
 
 #define BUGFRAMES                               \
-    __start_bug_frames = .;                     \
+    __start_bug_frames_0 = .;                   \
     *(.bug_frames.0)                            \
     __stop_bug_frames_0 = .;                    \
+                                                \
+    __start_bug_frames_1 = .;                   \
     *(.bug_frames.1)                            \
     __stop_bug_frames_1 = .;                    \
+                                                \
+    __start_bug_frames_2 = .;                   \
     *(.bug_frames.2)                            \
     __stop_bug_frames_2 = .;                    \
+                                                \
+    __start_bug_frames_3 = .;                   \
     *(.bug_frames.3)                            \
     __stop_bug_frames_3 = .;