diff mbox series

[v6,6/9] xen/riscv: introduce functionality to work with CPU info

Message ID 77a00222008f8b41d2454e74d1c9247252d7ccd9.1725295716.git.oleksii.kurochko@gmail.com (mailing list archive)
State New
Headers show
Series RISCV device tree mapping | expand

Commit Message

Oleksii Kurochko Sept. 2, 2024, 5:01 p.m. UTC
Introduce struct pcpu_info to store pCPU-related information.
Initially, it includes only processor_id and hart id, but it
will be extended to include guest CPU information and
temporary variables for saving/restoring vCPU registers.

Add set_processor_id() and get_processor_id() functions to set
and retrieve the processor_id stored in pcpu_info.

Define smp_processor_id() to provide accurate information,
replacing the previous "dummy" value of 0.

Initialize tp registers to point to pcpu_info[0].
Set processor_id to 0 for logical CPU 0 and store the physical
CPU ID in pcpu_info[0].

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in V6:
 - update the commit message ( drop outdated information ).
 - s/FIXME commit/FIXME comment in "changes in V5".
 - code style fixes.
 - refactoring of smp_processor_id() and fix BUG_ON() condition inside it.
 - change "mv a0,x0" to "li a0, 0".
 - add __cacheline_aligned to the struct pcpu_info.
 - drop smp_set_bootcpu_id() and smpboot.c as it has only smp_set_bootcpu_id()
   defined at the moment.
 - re-write setup_tp() to assembler.
---
Changes in V5:
 - add hart_id to pcpu_info;
 - add comments to pcpu_info members.
 - define INVALID_HARTID as ULONG_MAX as mhart_id register has MXLEN which is
   equal to 32 for RV-32 and 64 for RV-64.
 - add hart_id to pcpu_info structure.
 - drop cpuid_to_hartid_map[] and use pcpu_info[] for the same purpose.
 - introduce new function setup_tp(cpuid).
 - add the FIXME comment on top of pcpu_info[].
 - setup TP register before start_xen() being called.
 - update the commit message.
 - change "commit message" to "comment" in "Changes in V4" in "update the comment
   above the code of TP..."
---
Changes in V4:
 - wrap id with () inside set_processor_id().
 - code style fixes
 - update BUG_ON(id > NR_CPUS) in smp_processor_id() and drop the comment
   above BUG_ON().
 - s/__cpuid_to_hartid_map/cpuid_to_hartid_map
 - s/cpuid_to_hartid_map/cpuid_to_harti ( here cpuid_to_hartid_map is the name
   of the macros ).
 - update the comment above the code of TP register initialization in
   start_xen().
 - s/smp_setup_processor_id/smp_setup_bootcpu_id
 - update the commit message.
 - cleanup headers which are included in <asm/processor.h>
---
Changes in V3:
 - new patch.
---
 xen/arch/riscv/Makefile                |  1 +
 xen/arch/riscv/include/asm/processor.h | 27 ++++++++++++++++++++++++--
 xen/arch/riscv/include/asm/smp.h       |  9 +++++++++
 xen/arch/riscv/riscv64/asm-offsets.c   |  2 ++
 xen/arch/riscv/riscv64/head.S          | 15 ++++++++++++++
 xen/arch/riscv/setup.c                 |  5 +++++
 xen/arch/riscv/smp.c                   | 15 ++++++++++++++
 7 files changed, 72 insertions(+), 2 deletions(-)
 create mode 100644 xen/arch/riscv/smp.c

Comments

Jan Beulich Sept. 10, 2024, 10:33 a.m. UTC | #1
On 02.09.2024 19:01, Oleksii Kurochko wrote:
> --- a/xen/arch/riscv/include/asm/processor.h
> +++ b/xen/arch/riscv/include/asm/processor.h
> @@ -12,8 +12,31 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -/* TODO: need to be implemeted */
> -#define smp_processor_id() 0
> +#include <xen/bug.h>
> +
> +register struct pcpu_info *tp asm ( "tp" );
> +
> +struct pcpu_info {
> +    unsigned int processor_id; /* Xen CPU id */
> +    unsigned long hart_id; /* physical CPU id */
> +} __cacheline_aligned;

Shouldn't you include xen/cache.h for this, to be sure the header can
be included on its own?

I'm also unconvinced of this placement: Both Arm and x86 have similar
structures (afaict), living in current.h.

> +/* tp points to one of these */
> +extern struct pcpu_info pcpu_info[NR_CPUS];
> +
> +#define get_processor_id()      (tp->processor_id)

Iirc it was in response to one of your earlier patches that we removed
get_processor_id() from the other architectures, as being fully
redundant with smp_processor_id(). Is there a particular reason you
re-introduce that now for RISC-V?

> +#define set_processor_id(id)    do { \
> +    tp->processor_id = (id);         \
> +} while (0)
> +
> +static inline unsigned int smp_processor_id(void)
> +{
> +    unsigned int id = get_processor_id();
> +
> +    BUG_ON(id > (NR_CPUS - 1));

The more conventional way of expressing this is >= NR_CPUS.

> @@ -14,6 +16,13 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
>   */
>  #define park_offline_cpus false
>  
> +/*
> + * Mapping between linux logical cpu index and hartid.
> + */
> +#define cpuid_to_hartid(cpu) (pcpu_info[cpu].hart_id)

Does this need to be a macro (rather than an inline function)?

> @@ -72,6 +77,16 @@ FUNC(reset_stack)
>          ret
>  END(reset_stack)
>  
> +/* void setup_tp(unsigned int xen_cpuid); */
> +FUNC(setup_tp)
> +        la      tp, pcpu_info
> +        li      t0, PCPU_INFO_SIZE
> +        mul     t1, a0, t0
> +        add     tp, tp, t1
> +
> +        ret
> +END(setup_tp)

I take it this is going to run (i.e. also for secondary CPUs) ahead of
Xen being able to handle any kind of exception (on the given CPU)? If
so, all is fine here. If not, transiently pointing tp at CPU0's space
is a possible problem.

Jan
Oleksii Kurochko Sept. 11, 2024, 12:05 p.m. UTC | #2
On Tue, 2024-09-10 at 12:33 +0200, Jan Beulich wrote:
> On 02.09.2024 19:01, Oleksii Kurochko wrote:
> > --- a/xen/arch/riscv/include/asm/processor.h
> > +++ b/xen/arch/riscv/include/asm/processor.h
> > @@ -12,8 +12,31 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > -/* TODO: need to be implemeted */
> > -#define smp_processor_id() 0
> > +#include <xen/bug.h>
> > +
> > +register struct pcpu_info *tp asm ( "tp" );
> > +
> > +struct pcpu_info {
> > +    unsigned int processor_id; /* Xen CPU id */
> > +    unsigned long hart_id; /* physical CPU id */
> > +} __cacheline_aligned;
> 
> Shouldn't you include xen/cache.h for this, to be sure the header can
> be included on its own?
Agree, it would be better to include xen/cache.h header.

> 
> I'm also unconvinced of this placement: Both Arm and x86 have similar
> structures (afaict), living in current.h.
Then for consistency it would be better to move this structure to
current.h for RISC-V.

> 
> > +/* tp points to one of these */
> > +extern struct pcpu_info pcpu_info[NR_CPUS];
> > +
> > +#define get_processor_id()      (tp->processor_id)
> 
> Iirc it was in response to one of your earlier patches that we
> removed
> get_processor_id() from the other architectures, as being fully
> redundant with smp_processor_id(). Is there a particular reason you
> re-introduce that now for RISC-V?
No reason, just forgot that we agreed to use only smp_processor_id()
and made a bad rebase of my 'latest' branch on top of the current
staging which doesn't tell me about merge conflict in that place.
I will drop get_processor_id().

> 
> > +#define set_processor_id(id)    do { \
> > +    tp->processor_id = (id);         \
> > +} while (0)
> > +
> > +static inline unsigned int smp_processor_id(void)
> > +{
> > +    unsigned int id = get_processor_id();
> > +
> > +    BUG_ON(id > (NR_CPUS - 1));
> 
> The more conventional way of expressing this is >= NR_CPUS.
> 
> > @@ -14,6 +16,13 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
> >   */
> >  #define park_offline_cpus false
> >  
> > +/*
> > + * Mapping between linux logical cpu index and hartid.
> > + */
> > +#define cpuid_to_hartid(cpu) (pcpu_info[cpu].hart_id)
> 
> Does this need to be a macro (rather than an inline function)?
No, there is no such need. I will use inline function instead.

> 
> > @@ -72,6 +77,16 @@ FUNC(reset_stack)
> >          ret
> >  END(reset_stack)
> >  
> > +/* void setup_tp(unsigned int xen_cpuid); */
> > +FUNC(setup_tp)
> > +        la      tp, pcpu_info
> > +        li      t0, PCPU_INFO_SIZE
> > +        mul     t1, a0, t0
> > +        add     tp, tp, t1
> > +
> > +        ret
> > +END(setup_tp)
> 
> I take it this is going to run (i.e. also for secondary CPUs) ahead
> of
> Xen being able to handle any kind of exception (on the given CPU)?
Yes, I am using it for secondary CPUs and Xen are handling exceptions (
on the given CPU ) fine.

>  If
> so, all is fine here. If not, transiently pointing tp at CPU0's space
> is a possible problem.
I haven't had any problem with that at the moment.

Do you think that it will be better to use DECLARE_PER_CPU() with
updating of setup_tp() instead of pcpu_info[] when SMP will be
introduced?
What kind of problems should I take into account?

~ Oleksii
Jan Beulich Sept. 11, 2024, 12:14 p.m. UTC | #3
On 11.09.2024 14:05, oleksii.kurochko@gmail.com wrote:
> On Tue, 2024-09-10 at 12:33 +0200, Jan Beulich wrote:
>> On 02.09.2024 19:01, Oleksii Kurochko wrote:
>>> @@ -72,6 +77,16 @@ FUNC(reset_stack)
>>>          ret
>>>  END(reset_stack)
>>>  
>>> +/* void setup_tp(unsigned int xen_cpuid); */
>>> +FUNC(setup_tp)
>>> +        la      tp, pcpu_info
>>> +        li      t0, PCPU_INFO_SIZE
>>> +        mul     t1, a0, t0
>>> +        add     tp, tp, t1
>>> +
>>> +        ret
>>> +END(setup_tp)
>>
>> I take it this is going to run (i.e. also for secondary CPUs) ahead
>> of
>> Xen being able to handle any kind of exception (on the given CPU)?
> Yes, I am using it for secondary CPUs and Xen are handling exceptions (
> on the given CPU ) fine.

Yet that wasn't my question. Note in particular the use of "ahead of".

>>  If
>> so, all is fine here. If not, transiently pointing tp at CPU0's space
>> is a possible problem.
> I haven't had any problem with that at the moment.
> 
> Do you think that it will be better to use DECLARE_PER_CPU() with
> updating of setup_tp() instead of pcpu_info[] when SMP will be
> introduced?
> What kind of problems should I take into account?

If exceptions can be handled by Xen already when entering this function,
then the exception handler would need to be setting up tp for itself. If
not, it would use whatever the interrupted context used (or what is
brought into context by hardware while delivering the exception). If I
assumed that tp in principle doesn't need setting up when handling
exceptions (sorry, haven't read up enough yet about how guest -> host
switches work for RISC-V), and if further exceptions can already be
handled upon entering setup_tp(), then keeping tp properly invalid until
it can be set to its correct value will make it easier to diagnose
problems than when - like you do - transiently setting tp to CPU0's
value (and hence risking corruption of its state).

Jan
Oleksii Kurochko Sept. 12, 2024, 9:27 a.m. UTC | #4
On Wed, 2024-09-11 at 14:14 +0200, Jan Beulich wrote:
> On 11.09.2024 14:05, oleksii.kurochko@gmail.com wrote:
> > On Tue, 2024-09-10 at 12:33 +0200, Jan Beulich wrote:
> > > On 02.09.2024 19:01, Oleksii Kurochko wrote:
> > > > @@ -72,6 +77,16 @@ FUNC(reset_stack)
> > > >          ret
> > > >  END(reset_stack)
> > > >  
> > > > +/* void setup_tp(unsigned int xen_cpuid); */
> > > > +FUNC(setup_tp)
> > > > +        la      tp, pcpu_info
> > > > +        li      t0, PCPU_INFO_SIZE
> > > > +        mul     t1, a0, t0
> > > > +        add     tp, tp, t1
> > > > +
> > > > +        ret
> > > > +END(setup_tp)
> > > 
> > > I take it this is going to run (i.e. also for secondary CPUs)
> > > ahead
> > > of
> > > Xen being able to handle any kind of exception (on the given
> > > CPU)?
> > Yes, I am using it for secondary CPUs and Xen are handling
> > exceptions (
> > on the given CPU ) fine.
> 
> Yet that wasn't my question. Note in particular the use of "ahead
> of".
The first executed function for secondary CPU will be
( https://gitlab.com/xen-project/people/olkur/xen/-/blob/latest/xen/arch/riscv/riscv64/head.S?ref_type=heads#L100
) where the first instruction mask all interrupts:
           /*
            * a0 -> started hart id
            * a1 -> private data passed by boot cpu
            */
   ENTRY(secondary_start_sbi)
           /* Mask all interrupts */
           csrw    CSR_SIE, zero
           ...
   	tail    smp_callin
   
Then at the start of smp_callin
( https://gitlab.com/xen-project/people/olkur/xen/-/blob/latest/xen/arch/riscv/smpboot.c?ref_type=heads#L258
) tp register is setup ( in the old way for now using inline assembly I
will switch to setup_tp() later a little bit and call it before 'tail
smp_callin' ) and only after that local irqs are enabled:
   void __init smp_callin(unsigned int cpuid)
   {
       unsigned int hcpu = 1;
   
       for ( ; (hcpu < NR_CPUS) && (cpuid_to_hartid_map(hcpu) != cpuid);
   hcpu++)
       {}
   
       asm volatile ("mv tp, %0" : : "r"((unsigned
   long)&pcpu_info[hcpu]));
   ...
      trap_init(); /* write handle_trap() address to CSR_STVEC */
   ...
      local_irq_enable();
   ...
   
> 
> > >  If
> > > so, all is fine here. If not, transiently pointing tp at CPU0's
> > > space
> > > is a possible problem.
> > I haven't had any problem with that at the moment.
> > 
> > Do you think that it will be better to use DECLARE_PER_CPU() with
> > updating of setup_tp() instead of pcpu_info[] when SMP will be
> > introduced?
> > What kind of problems should I take into account?
> 
> If exceptions can be handled by Xen already when entering this
> function,
> then the exception handler would need to be setting up tp for itself.
> If
> not, it would use whatever the interrupted context used (or what is
> brought into context by hardware while delivering the exception). If
> I
> assumed that tp in principle doesn't need setting up when handling
> exceptions (sorry, haven't read up enough yet about how guest -> host
> switches work for RISC-V), and if further exceptions can already be
> handled upon entering setup_tp(), then keeping tp properly invalid
> until
> it can be set to its correct value will make it easier to diagnose
> problems than when - like you do - transiently setting tp to CPU0's
> value (and hence risking corruption of its state).
Regarding tp in exception handler if it is an exception from Xen it
will be set to 0 ( it is done by switch CSR_SSCRATCH and tp, and
CSR_SSCRATCH is always 0 for Xen and for guest it will be set to
pcpu_info[cpuid] before returning to new
vcpu:https://gitlab.com/xen-project/people/olkur/xen/-/blob/latest/xen/arch/riscv/entry.S?ref_type=heads#L165
) at the start of the handler; otherwise if an exception from Guest it
will set to &pcpu_info[cpuid] which was stored in CSR_SSCRATCH:
https://gitlab.com/xen-project/people/olkur/xen/-/blob/latest/xen/arch/riscv/entry.S?ref_type=heads#L15

As I mentioned above, interrupts will be disabled until tp is set. Even
if they aren’t disabled, tp will be set to 0 because, at the moment the
secondary CPU boots, CSR_SSCRATCH will be 0, which indicates that the
interrupt is from Xen.

> - like you do - transiently setting tp to CPU0's value (and hence >
risking corruption of its state).
I think I’m missing something—why would the secondary CPU have the same
value as CPU0? If we don’t set up the tp register when the secondary
CPU boots, it will contain a default value, which is expected upon
boot. It will retain this value until setup_tp() is called, which will
then set tp to pcpu_info[SECONDARY_CPU_ID].

~ Oleksii
Jan Beulich Sept. 12, 2024, 9:58 a.m. UTC | #5
On 12.09.2024 11:27, oleksii.kurochko@gmail.com wrote:
> As I mentioned above, interrupts will be disabled until tp is set.

Okay, so all good then

> Even
> if they aren’t disabled, tp will be set to 0 because, at the moment the
> secondary CPU boots, CSR_SSCRATCH will be 0, which indicates that the
> interrupt is from Xen.
> 
>> - like you do - transiently setting tp to CPU0's value (and hence >
> risking corruption of its state).
> I think I’m missing something—why would the secondary CPU have the same
> value as CPU0? If we don’t set up the tp register when the secondary
> CPU boots, it will contain a default value, which is expected upon
> boot. It will retain this value until setup_tp() is called, which will
> then set tp to pcpu_info[SECONDARY_CPU_ID].

Just to clarify (shouldn't matter in practice according to what you
said above) - in

FUNC(setup_tp)
        la      tp, pcpu_info
        li      t0, PCPU_INFO_SIZE
        mul     t1, a0, t0
        add     tp, tp, t1
        ret
END(setup_tp)

you start with setting tp to the CPU0 value. You only then adjust tp (3
insns later) to the designated value. If you wanted to play safe, you'd
do it e.g. like this

FUNC(setup_tp)
        la      t0, pcpu_info
        li      t1, PCPU_INFO_SIZE
        mul     t1, a0, t1
        add     tp, t0, t1
        ret
END(setup_tp)

Jan
Oleksii Kurochko Sept. 12, 2024, 4:02 p.m. UTC | #6
On Tue, 2024-09-10 at 12:33 +0200, Jan Beulich wrote:
> > +/*
> > + * Mapping between linux logical cpu index and hartid.
> > + */
> > +#define cpuid_to_hartid(cpu) (pcpu_info[cpu].hart_id)
> 
> Does this need to be a macro (rather than an inline function)?
I started to rework that and I am using this macros for both read
and write. So it will be needed to introduce set and get inline
functions instead of just one macros. I think I will stick to one
macros instead of 2 inline functions.

~ Oleksii
Jan Beulich Sept. 13, 2024, 12:51 p.m. UTC | #7
On 12.09.2024 18:02, oleksii.kurochko@gmail.com wrote:
> On Tue, 2024-09-10 at 12:33 +0200, Jan Beulich wrote:
>>> +/*
>>> + * Mapping between linux logical cpu index and hartid.
>>> + */
>>> +#define cpuid_to_hartid(cpu) (pcpu_info[cpu].hart_id)
>>
>> Does this need to be a macro (rather than an inline function)?
> I started to rework that and I am using this macros for both read
> and write. So it will be needed to introduce set and get inline
> functions instead of just one macros. I think I will stick to one
> macros instead of 2 inline functions.

You may want to consult with Andrew as to use of such a macro on
the lhs of an assignment. I expect he'll ask to avoid such, and
instead indeed go with both a get and a set accessor (unless it
would make sense to simply open-code the few sets that there are
going to be).

Jan
diff mbox series

Patch

diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 81b77b13d6..2f2d6647a2 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -4,6 +4,7 @@  obj-y += mm.o
 obj-$(CONFIG_RISCV_64) += riscv64/
 obj-y += sbi.o
 obj-y += setup.o
+obj-y += smp.o
 obj-y += stubs.o
 obj-y += traps.o
 obj-y += vm_event.o
diff --git a/xen/arch/riscv/include/asm/processor.h b/xen/arch/riscv/include/asm/processor.h
index 3ae164c265..4799243863 100644
--- a/xen/arch/riscv/include/asm/processor.h
+++ b/xen/arch/riscv/include/asm/processor.h
@@ -12,8 +12,31 @@ 
 
 #ifndef __ASSEMBLY__
 
-/* TODO: need to be implemeted */
-#define smp_processor_id() 0
+#include <xen/bug.h>
+
+register struct pcpu_info *tp asm ( "tp" );
+
+struct pcpu_info {
+    unsigned int processor_id; /* Xen CPU id */
+    unsigned long hart_id; /* physical CPU id */
+} __cacheline_aligned;
+
+/* tp points to one of these */
+extern struct pcpu_info pcpu_info[NR_CPUS];
+
+#define get_processor_id()      (tp->processor_id)
+#define set_processor_id(id)    do { \
+    tp->processor_id = (id);         \
+} while (0)
+
+static inline unsigned int smp_processor_id(void)
+{
+    unsigned int id = get_processor_id();
+
+    BUG_ON(id > (NR_CPUS - 1));
+
+    return id;
+}
 
 /* On stack VCPU state */
 struct cpu_user_regs
diff --git a/xen/arch/riscv/include/asm/smp.h b/xen/arch/riscv/include/asm/smp.h
index b1ea91b1eb..11eee67d62 100644
--- a/xen/arch/riscv/include/asm/smp.h
+++ b/xen/arch/riscv/include/asm/smp.h
@@ -5,6 +5,8 @@ 
 #include <xen/cpumask.h>
 #include <xen/percpu.h>
 
+#include <asm/processor.h>
+
 DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_mask);
 DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
 
@@ -14,6 +16,13 @@  DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
  */
 #define park_offline_cpus false
 
+/*
+ * Mapping between linux logical cpu index and hartid.
+ */
+#define cpuid_to_hartid(cpu) (pcpu_info[cpu].hart_id)
+
+void setup_tp(unsigned int cpuid);
+
 #endif
 
 /*
diff --git a/xen/arch/riscv/riscv64/asm-offsets.c b/xen/arch/riscv/riscv64/asm-offsets.c
index 9f663b9510..11400c4697 100644
--- a/xen/arch/riscv/riscv64/asm-offsets.c
+++ b/xen/arch/riscv/riscv64/asm-offsets.c
@@ -50,4 +50,6 @@  void asm_offsets(void)
     OFFSET(CPU_USER_REGS_SSTATUS, struct cpu_user_regs, sstatus);
     OFFSET(CPU_USER_REGS_PREGS, struct cpu_user_regs, pregs);
     BLANK();
+    DEFINE(PCPU_INFO_SIZE, sizeof(struct pcpu_info));
+    BLANK();
 }
diff --git a/xen/arch/riscv/riscv64/head.S b/xen/arch/riscv/riscv64/head.S
index 3261e9fce8..c7d8bf18c5 100644
--- a/xen/arch/riscv/riscv64/head.S
+++ b/xen/arch/riscv/riscv64/head.S
@@ -1,4 +1,5 @@ 
 #include <asm/asm.h>
+#include <asm/asm-offsets.h>
 #include <asm/riscv_encoding.h>
 
         .section .text.header, "ax", %progbits
@@ -55,6 +56,10 @@  FUNC(start)
          */
         jal     reset_stack
 
+        /* Xen's boot cpu id is equal to 0 so setup TP register for it */
+        li      a0, 0
+        jal     setup_tp
+
         /* restore hart_id ( bootcpu_id ) and dtb address */
         mv      a0, s0
         mv      a1, s1
@@ -72,6 +77,16 @@  FUNC(reset_stack)
         ret
 END(reset_stack)
 
+/* void setup_tp(unsigned int xen_cpuid); */
+FUNC(setup_tp)
+        la      tp, pcpu_info
+        li      t0, PCPU_INFO_SIZE
+        mul     t1, a0, t0
+        add     tp, tp, t1
+
+        ret
+END(setup_tp)
+
         .section .text.ident, "ax", %progbits
 
 FUNC(turn_on_mmu)
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index 13f0e8c77d..540a3a608e 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -8,6 +8,7 @@ 
 #include <public/version.h>
 
 #include <asm/early_printk.h>
+#include <asm/smp.h>
 #include <asm/traps.h>
 
 void arch_get_xen_caps(xen_capabilities_info_t *info)
@@ -40,6 +41,10 @@  void __init noreturn start_xen(unsigned long bootcpu_id,
 {
     remove_identity_mapping();
 
+    set_processor_id(0);
+
+    cpuid_to_hartid(0) = bootcpu_id;
+
     trap_init();
 
 #ifdef CONFIG_SELF_TESTS
diff --git a/xen/arch/riscv/smp.c b/xen/arch/riscv/smp.c
new file mode 100644
index 0000000000..4ca6a4e892
--- /dev/null
+++ b/xen/arch/riscv/smp.c
@@ -0,0 +1,15 @@ 
+#include <xen/smp.h>
+
+/*
+ * FIXME: make pcpu_info[] dynamically allocated when necessary
+ *        functionality will be ready
+ */
+/*
+ * tp points to one of these per cpu.
+ *
+ * hart_id would be valid (no matter which value) if its
+ * processor_id field is valid (less than NR_CPUS).
+ */
+struct pcpu_info pcpu_info[NR_CPUS] = { [0 ... NR_CPUS - 1] = {
+    .processor_id = NR_CPUS,
+}};