diff mbox series

[v3,3/5] xen/ppc: Define minimal stub headers required for full build

Message ID dd3d9c5d9ec94f9e1747ccc0fbf82629a58bddcb.1693590982.git.sanastasio@raptorengineering.com (mailing list archive)
State Superseded
Headers show
Series ppc: Enable full Xen build | expand

Commit Message

Shawn Anastasio Sept. 1, 2023, 6:25 p.m. UTC
Additionally, change inclusion of asm/ headers to corresponding xen/ ones
throughout arch/ppc now that they work.

Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
---
v3:
  - Drop procarea.h
  - Add SPDX headers to all headers touched or added by this patch
  - (altp2m.h) Use ASSERT_UNREACHABLE for function that is meant to
    stay unimplemented
  - (current.h) Consistently use plain C types in struct cpu_info
  - (current.h) Fix formatting of inline asm in get_cpu_info()
  - (device.h) Drop unnecessary DEVICE_GIC enumeration inherited from
    ARM
  - (div64.h) Drop underscore-prefixed macro variables, fix formatting
  - (domain.h) Drop unnecessary space after cast in guest_mode()
  - (guest_access.h) Clean up line wrapping of functions w/ many
    parameters
  - (guest_atomics.h) Avoid overly-long stub macros
  - (grant_table.h) Add include guard + SPDX
  - (hypercall.h) Add include guard + SPDX
  - (mem_access.h) Add include guard + SPDX
  - (mm.h) BUG_ON("unimplemented") for mfn_to_gfn/set_gpfn_from_mfn
  - (mm.h) Define PDX_GROUP_SHIFT in terms of XEN_PT_SHIFT_LVL_3
  - (monitor.h) BUG_ON("unimplemented") for arch_monitor_get_capabilities
  - (system.h) Fix formatting of inline assembly + macros
  - (time.h) Fix too-deep indentation

v2:
  - Use BUG_ON("unimplemented") instead of BUG() for unimplemented functions
    to make searching easier.
  - (altp2m.h) Drop Intel license in favor of an SPDX header
  - (altp2m.h) Drop <xen/sched.h> include in favor of <xen/bug.h> and
    forward declarations of struct domain and struct vcpu.
  - (bug.h) Add TODO comments above BUG and BUG_FRAME implementations
  - (desc.h) Drop desc.h
  - (mm.h) Drop <asm/config.h> include
  - (mm.h) Drop PGC_static definition
  - (mm.h) Drop max_page definition
  - (mm.h/mm-radix.c) Drop total_pages definition
  - (monitor.h) Drop <xen/sched.h> and <public/domctl.h> includes in favor
    of just <xen/errno.h>
  - (page.h) Drop PAGE_ALIGN definition
  - (percpu.h) Drop <xen/types.h> include
  - (procarea.h) Drop license text in favor of SPDX header
  - (procarea.h) Drop unnecessary forward declarations and <xen/types.h>
    include
  - (processor.h) Fix macro parameter naming (drop leading underscore)
  - (processor.h) Add explanation comment to cpu_relax()
  - (regs.h) Drop stray hunk adding <xen/types.h> include
  - (system.h) Drop license text in favor of SPDX header
  - (system.h) Drop <xen/config.h> include
  - (opal.c) Drop stray hunk changing opal.c includes

 xen/arch/ppc/Kconfig                     |   1 +
 xen/arch/ppc/include/asm/altp2m.h        |  25 +++
 xen/arch/ppc/include/asm/bug.h           |   9 +
 xen/arch/ppc/include/asm/cache.h         |   2 +
 xen/arch/ppc/include/asm/config.h        |  10 +
 xen/arch/ppc/include/asm/cpufeature.h    |  10 +
 xen/arch/ppc/include/asm/current.h       |  43 ++++
 xen/arch/ppc/include/asm/delay.h         |  12 ++
 xen/arch/ppc/include/asm/device.h        |  53 +++++
 xen/arch/ppc/include/asm/div64.h         |  14 ++
 xen/arch/ppc/include/asm/domain.h        |  47 +++++
 xen/arch/ppc/include/asm/event.h         |  36 ++++
 xen/arch/ppc/include/asm/flushtlb.h      |  24 +++
 xen/arch/ppc/include/asm/grant_table.h   |   5 +
 xen/arch/ppc/include/asm/guest_access.h  |  68 +++++++
 xen/arch/ppc/include/asm/guest_atomics.h |  23 +++
 xen/arch/ppc/include/asm/hardirq.h       |  19 ++
 xen/arch/ppc/include/asm/hypercall.h     |   5 +
 xen/arch/ppc/include/asm/io.h            |  16 ++
 xen/arch/ppc/include/asm/iocap.h         |   8 +
 xen/arch/ppc/include/asm/iommu.h         |   8 +
 xen/arch/ppc/include/asm/irq.h           |  33 +++
 xen/arch/ppc/include/asm/mem_access.h    |   5 +
 xen/arch/ppc/include/asm/mm.h            | 248 ++++++++++++++++++++++-
 xen/arch/ppc/include/asm/monitor.h       |  43 ++++
 xen/arch/ppc/include/asm/nospec.h        |  15 ++
 xen/arch/ppc/include/asm/numa.h          |  26 +++
 xen/arch/ppc/include/asm/p2m.h           | 105 ++++++++++
 xen/arch/ppc/include/asm/page.h          |  18 ++
 xen/arch/ppc/include/asm/paging.h        |   7 +
 xen/arch/ppc/include/asm/pci.h           |   7 +
 xen/arch/ppc/include/asm/percpu.h        |  24 +++
 xen/arch/ppc/include/asm/processor.h     |  10 +
 xen/arch/ppc/include/asm/random.h        |   9 +
 xen/arch/ppc/include/asm/setup.h         |   6 +
 xen/arch/ppc/include/asm/smp.h           |  18 ++
 xen/arch/ppc/include/asm/softirq.h       |   8 +
 xen/arch/ppc/include/asm/spinlock.h      |  15 ++
 xen/arch/ppc/include/asm/system.h        | 224 +++++++++++++++++++-
 xen/arch/ppc/include/asm/time.h          |  21 ++
 xen/arch/ppc/include/asm/vm_event.h      |  49 +++++
 xen/arch/ppc/include/asm/xenoprof.h      |   0
 xen/arch/ppc/mm-radix.c                  |   2 +-
 xen/arch/ppc/tlb-radix.c                 |   2 +-
 xen/include/public/hvm/save.h            |   2 +
 xen/include/public/pmu.h                 |   2 +
 xen/include/public/xen.h                 |   2 +
 47 files changed, 1335 insertions(+), 4 deletions(-)
 create mode 100644 xen/arch/ppc/include/asm/altp2m.h
 create mode 100644 xen/arch/ppc/include/asm/cpufeature.h
 create mode 100644 xen/arch/ppc/include/asm/current.h
 create mode 100644 xen/arch/ppc/include/asm/delay.h
 create mode 100644 xen/arch/ppc/include/asm/device.h
 create mode 100644 xen/arch/ppc/include/asm/div64.h
 create mode 100644 xen/arch/ppc/include/asm/domain.h
 create mode 100644 xen/arch/ppc/include/asm/event.h
 create mode 100644 xen/arch/ppc/include/asm/flushtlb.h
 create mode 100644 xen/arch/ppc/include/asm/grant_table.h
 create mode 100644 xen/arch/ppc/include/asm/guest_access.h
 create mode 100644 xen/arch/ppc/include/asm/guest_atomics.h
 create mode 100644 xen/arch/ppc/include/asm/hardirq.h
 create mode 100644 xen/arch/ppc/include/asm/hypercall.h
 create mode 100644 xen/arch/ppc/include/asm/io.h
 create mode 100644 xen/arch/ppc/include/asm/iocap.h
 create mode 100644 xen/arch/ppc/include/asm/iommu.h
 create mode 100644 xen/arch/ppc/include/asm/irq.h
 create mode 100644 xen/arch/ppc/include/asm/mem_access.h
 create mode 100644 xen/arch/ppc/include/asm/monitor.h
 create mode 100644 xen/arch/ppc/include/asm/nospec.h
 create mode 100644 xen/arch/ppc/include/asm/numa.h
 create mode 100644 xen/arch/ppc/include/asm/p2m.h
 create mode 100644 xen/arch/ppc/include/asm/paging.h
 create mode 100644 xen/arch/ppc/include/asm/pci.h
 create mode 100644 xen/arch/ppc/include/asm/percpu.h
 create mode 100644 xen/arch/ppc/include/asm/random.h
 create mode 100644 xen/arch/ppc/include/asm/setup.h
 create mode 100644 xen/arch/ppc/include/asm/smp.h
 create mode 100644 xen/arch/ppc/include/asm/softirq.h
 create mode 100644 xen/arch/ppc/include/asm/spinlock.h
 create mode 100644 xen/arch/ppc/include/asm/time.h
 create mode 100644 xen/arch/ppc/include/asm/vm_event.h
 create mode 100644 xen/arch/ppc/include/asm/xenoprof.h

--
2.30.2

Comments

Jan Beulich Sept. 5, 2023, 3:52 p.m. UTC | #1
On 01.09.2023 20:25, Shawn Anastasio wrote:
> --- /dev/null
> +++ b/xen/arch/ppc/include/asm/device.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_PPC_DEVICE_H__
> +#define __ASM_PPC_DEVICE_H__
> +
> +enum device_type
> +{
> +    DEV_DT,
> +    DEV_PCI,
> +};
> +
> +struct device {
> +    enum device_type type;
> +#ifdef CONFIG_HAS_DEVICE_TREE
> +    struct dt_device_node *of_node; /* Used by drivers imported from Linux */
> +#endif
> +};
> +
> +enum device_class
> +{
> +    DEVICE_SERIAL,
> +    DEVICE_IOMMU,
> +    DEVICE_PCI_HOSTBRIDGE,
> +    /* Use for error */
> +    DEVICE_UNKNOWN,
> +};
> +
> +struct device_desc {
> +    /* Device name */
> +    const char *name;
> +    /* Device class */
> +    enum device_class class;
> +    /* List of devices supported by this driver */
> +    const struct dt_device_match *dt_match;
> +    /*
> +     * Device initialization.
> +     *
> +     * -EAGAIN is used to indicate that device probing is deferred.
> +     */
> +    int (*init)(struct dt_device_node *dev, const void *data);
> +};
> +
> +typedef struct device device_t;
> +
> +#define DT_DEVICE_START(_name, _namestr, _class)                    \

Nit: Underscore-prefixed macro parameter names again.

> --- a/xen/arch/ppc/include/asm/mm.h
> +++ b/xen/arch/ppc/include/asm/mm.h
> @@ -1,10 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
>  #ifndef _ASM_PPC_MM_H
>  #define _ASM_PPC_MM_H
> 
> +#include <public/xen.h>
> +#include <xen/pdx.h>
> +#include <xen/types.h>
> +#include <asm/config.h>
>  #include <asm/page-bits.h>
> +#include <asm/page.h>
> +
> +void setup_initial_pagetables(void);
> 
>  #define pfn_to_paddr(pfn) ((paddr_t)(pfn) << PAGE_SHIFT)
>  #define paddr_to_pfn(pa)  ((unsigned long)((pa) >> PAGE_SHIFT))
> +#define paddr_to_pdx(pa)    mfn_to_pdx(maddr_to_mfn(pa))
> +#define gfn_to_gaddr(gfn)   pfn_to_paddr(gfn_x(gfn))
> +#define gaddr_to_gfn(ga)    _gfn(paddr_to_pfn(ga))
> +#define mfn_to_maddr(mfn)   pfn_to_paddr(mfn_x(mfn))
> +#define maddr_to_mfn(ma)    _mfn(paddr_to_pfn(ma))
> +#define vmap_to_mfn(va)     maddr_to_mfn(virt_to_maddr((vaddr_t)va))
> +#define vmap_to_page(va)    mfn_to_page(vmap_to_mfn(va))
> 
>  #define virt_to_maddr(va) ((paddr_t)((vaddr_t)(va) & PADDR_MASK))
>  #define maddr_to_virt(pa) ((void *)((paddr_t)(pa) | XEN_VIRT_START))

Is it intentional that the additions don't align, padding-wise, with the
surrounding #define-s?

> @@ -13,6 +28,237 @@
>  #define __pa(x)             (virt_to_maddr(x))
>  #define __va(x)             (maddr_to_virt(x))
> 
> -void setup_initial_pagetables(void);
> +/* Convert between Xen-heap virtual addresses and machine frame numbers. */
> +#define __virt_to_mfn(va) (virt_to_maddr(va) >> PAGE_SHIFT)
> +#define __mfn_to_virt(mfn) (maddr_to_virt((paddr_t)(mfn) << PAGE_SHIFT))
> +
> +/* Convert between Xen-heap virtual addresses and page-info structures. */
> +static inline struct page_info *virt_to_page(const void *v)
> +{
> +    BUG_ON("unimplemented");
> +    return NULL;
> +}
> +
> +/*
> + * We define non-underscored wrappers for above conversion functions.
> + * These are overriden in various source files while underscored version
> + * remain intact.
> + */
> +#define virt_to_mfn(va)     __virt_to_mfn(va)
> +#define mfn_to_virt(mfn)    __mfn_to_virt(mfn)

Is the comment really applicable? The only non-arch-specific file still
doing so is xenoprof.c, and I'm not sure you mean to support xenoprof
on PPC. PPC-specific files would better be introduced in a type-safe way
right from the beginning.

> +#define PG_shift(idx)   (BITS_PER_LONG - (idx))
> +#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
> +
> +#define PGT_none          PG_mask(0, 1)  /* no special uses of this page   */
> +#define PGT_writable_page PG_mask(1, 1)  /* has writable mappings?         */
> +#define PGT_type_mask     PG_mask(1, 1)  /* Bits 31 or 63.                 */
> +
> + /* 2-bit count of uses of this frame as its current type. */
> +#define PGT_count_mask    PG_mask(3, 3)
> +
> +/* Cleared when the owning guest 'frees' this page. */
> +#define _PGC_allocated    PG_shift(1)
> +#define PGC_allocated     PG_mask(1, 1)
> +/* Page is Xen heap? */
> +#define _PGC_xen_heap     PG_shift(2)
> +#define PGC_xen_heap      PG_mask(1, 2)
> +/* Page is broken? */
> +#define _PGC_broken       PG_shift(7)
> +#define PGC_broken        PG_mask(1, 7)
> + /* Mutually-exclusive page states: { inuse, offlining, offlined, free }. */
> +#define PGC_state         PG_mask(3, 9)
> +#define PGC_state_inuse   PG_mask(0, 9)
> +#define PGC_state_offlining PG_mask(1, 9)
> +#define PGC_state_offlined PG_mask(2, 9)
> +#define PGC_state_free    PG_mask(3, 9)
> +#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
> +/* Page is not reference counted */
> +#define _PGC_extra        PG_shift(10)
> +#define PGC_extra         PG_mask(1, 10)
> +
> +/* Count of references to this frame. */
> +#define PGC_count_width   PG_shift(10)
> +#define PGC_count_mask    ((1UL<<PGC_count_width)-1)
> +
> +/*
> + * Page needs to be scrubbed. Since this bit can only be set on a page that is
> + * free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
> + */
> +#define _PGC_need_scrub   _PGC_allocated
> +#define PGC_need_scrub    PGC_allocated
> +
> +#define is_xen_heap_page(page) ((page)->count_info & PGC_xen_heap)
> +#define is_xen_heap_mfn(mfn) \
> +    (mfn_valid(mfn) && is_xen_heap_page(mfn_to_page(mfn)))
> +
> +#define is_xen_fixed_mfn(mfn)                                   \
> +    ((mfn_to_maddr(mfn) >= virt_to_maddr(&_start)) &&           \
> +     (mfn_to_maddr(mfn) <= virt_to_maddr((vaddr_t)_end - 1)))

Please use (or, preferred, do not use) & and cast consistently on _start
and _end.

> +#define page_get_owner(_p)    (_p)->v.inuse.domain
> +#define page_set_owner(_p,_d) ((_p)->v.inuse.domain = (_d))
> +
> +/* TODO: implement */
> +#define mfn_valid(mfn) ({ (void) (mfn); 0; })
> +
> +#define domain_set_alloc_bitsize(d) ((void)(d))
> +#define domain_clamp_alloc_bitsize(d, b) (b)
> +
> +#define PFN_ORDER(pfn_) ((pfn_)->v.free.order)
> +
> +struct page_info
> +{
> +    /* Each frame can be threaded onto a doubly-linked list. */
> +    struct page_list_entry list;
> +
> +    /* Reference count and various PGC_xxx flags and fields. */
> +    unsigned long count_info;
> +
> +    /* Context-dependent fields follow... */
> +    union {
> +        /* Page is in use: ((count_info & PGC_count_mask) != 0). */
> +        struct {
> +            /* Type reference count and various PGT_xxx flags and fields. */
> +            unsigned long type_info;
> +        } inuse;
> +        /* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
> +        union {
> +            struct {
> +                /*
> +                 * Index of the first *possibly* unscrubbed page in the buddy.
> +                 * One more bit than maximum possible order to accommodate
> +                 * INVALID_DIRTY_IDX.
> +                 */
> +#define INVALID_DIRTY_IDX ((1UL << (MAX_ORDER + 1)) - 1)
> +                unsigned long first_dirty:MAX_ORDER + 1;
> +
> +                /* Do TLBs need flushing for safety before next page use? */
> +                bool need_tlbflush:1;
> +
> +#define BUDDY_NOT_SCRUBBING    0
> +#define BUDDY_SCRUBBING        1
> +#define BUDDY_SCRUB_ABORT      2
> +                unsigned long scrub_state:2;
> +            };
> +
> +            unsigned long val;
> +        } free;
> +
> +    } u;
> +
> +    union {
> +        /* Page is in use, but not as a shadow. */
> +        struct {
> +            /* Owner of this page (zero if page is anonymous). */
> +            struct domain *domain;

Since this is a pointer, NULL (instead of zero) would seem more appropriate
in the comment.

> +        } inuse;
> +
> +        /* Page is on a free list. */
> +        struct {
> +            /* Order-size of the free chunk this page is the head of. */
> +            unsigned int order;
> +        } free;
> +
> +    } v;
> +
> +    union {
> +        /*
> +         * Timestamp from 'TLB clock', used to avoid extra safety flushes.
> +         * Only valid for: a) free pages, and b) pages with zero type count
> +         */
> +        u32 tlbflush_timestamp;
> +    };
> +    u64 pad;

uint<N>_t please (or unsigned int/long).

> --- /dev/null
> +++ b/xen/arch/ppc/include/asm/monitor.h
> @@ -0,0 +1,43 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Derived from xen/arch/arm/include/asm/monitor.h */
> +#ifndef __ASM_PPC_MONITOR_H__
> +#define __ASM_PPC_MONITOR_H__
> +
> +#include <public/domctl.h>
> +#include <xen/errno.h>
> +
> +static inline
> +void arch_monitor_allow_userspace(struct domain *d, bool allow_userspace)
> +{
> +}
> +
> +static inline
> +int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
> +{
> +    /* No arch-specific monitor ops on PPC. */
> +    return -EOPNOTSUPP;
> +}
> +
> +int arch_monitor_domctl_event(struct domain *d,
> +                              struct xen_domctl_monitor_op *mop);
> +
> +static inline
> +int arch_monitor_init_domain(struct domain *d)
> +{
> +    /* No arch-specific domain initialization on PPC. */
> +    return 0;
> +}
> +
> +static inline
> +void arch_monitor_cleanup_domain(struct domain *d)
> +{
> +    /* No arch-specific domain cleanup on PPC. */
> +}
> +
> +static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
> +{
> +    BUG_ON("unimplemented");
> +    return 0;
> +}
> +
> +#endif /* __ASM_PPC_MONITOR_H__ */

From a formal perspective you'll need Tamas's ack for this file, so you
may want to Cc him. (Also for vm_event.h, unless the generic solution
there doesn't land first.)

> --- /dev/null
> +++ b/xen/arch/ppc/include/asm/p2m.h
> @@ -0,0 +1,105 @@
> +#ifndef __ASM_PPC_P2M_H__
> +#define __ASM_PPC_P2M_H__
> +
> +#include <asm/page-bits.h>
> +
> +#define paddr_bits PADDR_BITS
> +
> +/*
> + * List of possible type for each page in the p2m entry.
> + * The number of available bit per page in the pte for this purpose is 4 bits.
> + * So it's possible to only have 16 fields. If we run out of value in the
> + * future, it's possible to use higher value for pseudo-type and don't store
> + * them in the p2m entry.
> + */
> +typedef enum {
> +    p2m_invalid = 0,    /* Nothing mapped here */
> +    p2m_ram_rw,         /* Normal read/write guest RAM */
> +    p2m_ram_ro,         /* Read-only; writes are silently dropped */
> +    p2m_mmio_direct_dev,/* Read/write mapping of genuine Device MMIO area */
> +    p2m_mmio_direct_nc, /* Read/write mapping of genuine MMIO area non-cacheable */
> +    p2m_mmio_direct_c,  /* Read/write mapping of genuine MMIO area cacheable */

Didn't you agree to drop at least what's clear Arm-specific?

> --- a/xen/arch/ppc/include/asm/system.h
> +++ b/xen/arch/ppc/include/asm/system.h
> @@ -1,6 +1,228 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) IBM Corp. 2005
> + * Copyright (C) Raptor Engineering LLC
> + *
> + * Authors: Jimi Xenidis <jimix@watson.ibm.com>
> + *          Shawn Anastasio <sanastasio@raptorengineering.com>
> + */
> +
>  #ifndef _ASM_SYSTEM_H_
>  #define _ASM_SYSTEM_H_
> 
> -#define smp_wmb() __asm__ __volatile__ ( "lwsync" : : : "memory" )
> +#include <xen/lib.h>
> +#include <asm/memory.h>
> +#include <asm/time.h>
> +#include <asm/processor.h>
> +#include <asm/msr.h>
> +
> +#define xchg(ptr,x) 							                               \
> +({									                                           \
> +	__typeof__(*(ptr)) _x_ = (x);					                           \

Hard tabs look to have slipped in here.

> +	(__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr)));    \
> +})
> +
> +#define build_xchg(fn, type, ldinsn, stinsn) \
> +static inline unsigned long fn(volatile type *m, unsigned long val)            \
> +{                                                                              \
> +    unsigned long dummy;                                                       \
> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER                                    \
> +                   "1: " ldinsn " %0,0,%3\n"                                   \
> +                   stinsn " %2,0,%3\n"                                         \
> +                   "2:  bne- 1b"                                               \
> +                   PPC_ATOMIC_EXIT_BARRIER                                     \
> +                   : "=&r" (dummy), "=m" (*m)                                  \
> +                   : "r" (val), "r" (m)                                        \
> +                   : "cc", "memory" );                                         \
> +    return dummy;                                                              \
> +}
> +
> +build_xchg(__xchg_u8, uint8_t, "lbarx", "stbcx.")
> +build_xchg(__xchg_u16, uint16_t, "lharx", "sthcx.")
> +build_xchg(__xchg_u32, uint32_t, "lwarx", "stwcx.")
> +build_xchg(__xchg_u64, uint64_t, "ldarx", "stdcx.")
> +
> +#undef build_xchg
> +
> +/*
> + * This function doesn't exist, so you'll get a linker error
> + * if something tries to do an invalid xchg().
> + */
> +extern void __xchg_called_with_bad_pointer(void);
> +
> +static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
> +                                   int size)
> +{
> +    switch (size) {

Nit: Since the file looks like it wants to use Xen style:

    switch ( size )
    {

please.

> +    case 1:
> +        return __xchg_u8(ptr, x);
> +    case 2:
> +        return __xchg_u16(ptr, x);
> +    case 4:
> +        return __xchg_u32(ptr, x);
> +    case 8:
> +        return __xchg_u64(ptr, x);
> +    }
> +    __xchg_called_with_bad_pointer();
> +    return x;
> +}
> +
> +
> +static inline unsigned long __cmpxchg_u32(volatile int *p, int old, int new)
> +{
> +    unsigned int prev;
> +
> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
> +                   "1: lwarx   %0,0,%2\n"
> +                   "cmpw    0,%0,%3\n"
> +                   "bne-    2f\n "
> +                   "stwcx.  %4,0,%2\n"
> +                   "bne-    1b\n"
> +                   PPC_ATOMIC_EXIT_BARRIER "\n"
> +                   "2:"
> +                   : "=&r" (prev), "=m" (*p)
> +                   : "r" (p), "r" (old), "r" (new), "m" (*p)
> +                   : "cc", "memory" );
> +
> +    return prev;
> +}
> +
> +static inline unsigned long __cmpxchg_u64(volatile long *p, unsigned long old,
> +                                          unsigned long new)
> +{
> +    unsigned long prev;
> +
> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
> +                   "1: ldarx   %0,0,%2\n"
> +                   "cmpd    0,%0,%3\n"
> +                   "bne-    2f\n"
> +                   "stdcx.  %4,0,%2\n"
> +                   "bne-    1b"
> +                   PPC_ATOMIC_EXIT_BARRIER "\n"
> +                   "2:"
> +                   : "=&r" (prev), "=m" (*p)
> +                   : "r" (p), "r" (old), "r" (new), "m" (*p)
> +                   : "cc", "memory" );
> +
> +    return prev;
> +}
> +
> +/* This function doesn't exist, so you'll get a linker error
> +   if something tries to do an invalid cmpxchg().  */
> +extern void __cmpxchg_called_with_bad_pointer(void);
> +
> +static always_inline unsigned long __cmpxchg(
> +    volatile void *ptr,
> +    unsigned long old,
> +    unsigned long new,
> +    int size)
> +{
> +    switch (size) {
> +    case 2:
> +        BUG_ON("unimplemented"); return 0; /* XXX implement __cmpxchg_u16 ? */
> +    case 4:
> +        return __cmpxchg_u32(ptr, old, new);
> +    case 8:
> +        return __cmpxchg_u64(ptr, old, new);
> +    }
> +    __cmpxchg_called_with_bad_pointer();
> +    return old;
> +}
> +
> +#define cmpxchg_user(ptr,o,n) cmpxchg(ptr,o,n)
> +
> +#define cmpxchg(ptr,o,n)                         \
> +  ({                                     \
> +     __typeof__(*(ptr)) _o_ = (o);                   \
> +     __typeof__(*(ptr)) _n_ = (n);                   \
> +     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,       \
> +                    (unsigned long)_n_, sizeof(*(ptr))); \

Not: Style (multiple previously mentioned issues).

> +  })
> +
> +
> +/*
> + * Memory barrier.
> + * The sync instruction guarantees that all memory accesses initiated
> + * by this processor have been performed (with respect to all other
> + * mechanisms that access memory).  The eieio instruction is a barrier
> + * providing an ordering (separately) for (a) cacheable stores and (b)
> + * loads and stores to non-cacheable memory (e.g. I/O devices).
> + *
> + * mb() prevents loads and stores being reordered across this point.
> + * rmb() prevents loads being reordered across this point.
> + * wmb() prevents stores being reordered across this point.
> + * read_barrier_depends() prevents data-dependent loads being reordered
> + *  across this point (nop on PPC).
> + *
> + * We have to use the sync instructions for mb(), since lwsync doesn't
> + * order loads with respect to previous stores.  Lwsync is fine for
> + * rmb(), though.
> + * For wmb(), we use sync since wmb is used in drivers to order
> + * stores to system memory with respect to writes to the device.
> + * However, smp_wmb() can be a lighter-weight eieio barrier on
> + * SMP since it is only used to order updates to system memory.
> + */
> +#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
> +#define rmb()  __asm__ __volatile__ ("lwsync" : : : "memory")
> +#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")

Nit: Missing blanks.

> +#define read_barrier_depends()  do { } while(0)
> +
> +#define set_mb(var, value)  do { var = value; smp_mb(); } while (0)
> +#define set_wmb(var, value) do { var = value; smp_wmb(); } while (0)
> +
> +#define smp_mb__before_atomic()    smp_mb()
> +#define smp_mb__after_atomic()     smp_mb()
> +
> +#ifdef CONFIG_SMP
> +#define smp_mb()    mb()
> +#define smp_rmb()   rmb()
> +#define smp_wmb()   __asm__ __volatile__ ("lwsync" : : : "memory")
> +#define smp_read_barrier_depends()  read_barrier_depends()
> +#else
> +#define smp_mb()    __asm__ __volatile__("": : :"memory")
> +#define smp_rmb()   __asm__ __volatile__("": : :"memory")
> +#define smp_wmb()   __asm__ __volatile__("": : :"memory")

And more missing blanks (further below from here).

> +#define smp_read_barrier_depends()  do { } while(0)
> +#endif /* CONFIG_SMP */
> +
> +#define local_save_flags(flags) ((flags) = mfmsr())
> +#define local_irq_restore(flags) do { \
> +        __asm__ __volatile__("": : :"memory"); \
> +        mtmsrd((flags)); \
> +} while(0)
> +
> +static inline void local_irq_disable(void)
> +{
> +    unsigned long msr;
> +    msr = mfmsr();
> +    mtmsrd(msr & ~MSR_EE);
> +    asm volatile ( "" : : : "memory" );

That's simply barrier(), isn't it? Please avoid open-coding. (More
further down.)

> --- /dev/null
> +++ b/xen/arch/ppc/include/asm/time.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_PPC_TIME_H__
> +#define __ASM_PPC_TIME_H__
> +
> +#include <xen/lib.h>
> +#include <asm/processor.h>
> +#include <asm/regs.h>
> +
> +struct vcpu;
> +
> +/* TODO: implement */
> +static inline void force_update_vcpu_system_time(struct vcpu *v) { BUG_ON("unimplemented"); }

Nit: Too long line.

Jan
Shawn Anastasio Sept. 8, 2023, 10:05 p.m. UTC | #2
On 9/5/23 10:52 AM, Jan Beulich wrote:
> On 01.09.2023 20:25, Shawn Anastasio wrote:
>> --- /dev/null
>> +++ b/xen/arch/ppc/include/asm/device.h
>> @@ -0,0 +1,53 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +#ifndef __ASM_PPC_DEVICE_H__
>> +#define __ASM_PPC_DEVICE_H__
>> +
>> +enum device_type
>> +{
>> +    DEV_DT,
>> +    DEV_PCI,
>> +};
>> +
>> +struct device {
>> +    enum device_type type;
>> +#ifdef CONFIG_HAS_DEVICE_TREE
>> +    struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>> +#endif
>> +};
>> +
>> +enum device_class
>> +{
>> +    DEVICE_SERIAL,
>> +    DEVICE_IOMMU,
>> +    DEVICE_PCI_HOSTBRIDGE,
>> +    /* Use for error */
>> +    DEVICE_UNKNOWN,
>> +};
>> +
>> +struct device_desc {
>> +    /* Device name */
>> +    const char *name;
>> +    /* Device class */
>> +    enum device_class class;
>> +    /* List of devices supported by this driver */
>> +    const struct dt_device_match *dt_match;
>> +    /*
>> +     * Device initialization.
>> +     *
>> +     * -EAGAIN is used to indicate that device probing is deferred.
>> +     */
>> +    int (*init)(struct dt_device_node *dev, const void *data);
>> +};
>> +
>> +typedef struct device device_t;
>> +
>> +#define DT_DEVICE_START(_name, _namestr, _class)                    \
> 
> Nit: Underscore-prefixed macro parameter names again.
>

Will fix.

>> --- a/xen/arch/ppc/include/asm/mm.h
>> +++ b/xen/arch/ppc/include/asm/mm.h
>> @@ -1,10 +1,25 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>  #ifndef _ASM_PPC_MM_H
>>  #define _ASM_PPC_MM_H
>>
>> +#include <public/xen.h>
>> +#include <xen/pdx.h>
>> +#include <xen/types.h>
>> +#include <asm/config.h>
>>  #include <asm/page-bits.h>
>> +#include <asm/page.h>
>> +
>> +void setup_initial_pagetables(void);
>>
>>  #define pfn_to_paddr(pfn) ((paddr_t)(pfn) << PAGE_SHIFT)
>>  #define paddr_to_pfn(pa)  ((unsigned long)((pa) >> PAGE_SHIFT))
>> +#define paddr_to_pdx(pa)    mfn_to_pdx(maddr_to_mfn(pa))
>> +#define gfn_to_gaddr(gfn)   pfn_to_paddr(gfn_x(gfn))
>> +#define gaddr_to_gfn(ga)    _gfn(paddr_to_pfn(ga))
>> +#define mfn_to_maddr(mfn)   pfn_to_paddr(mfn_x(mfn))
>> +#define maddr_to_mfn(ma)    _mfn(paddr_to_pfn(ma))
>> +#define vmap_to_mfn(va)     maddr_to_mfn(virt_to_maddr((vaddr_t)va))
>> +#define vmap_to_page(va)    mfn_to_page(vmap_to_mfn(va))
>>
>>  #define virt_to_maddr(va) ((paddr_t)((vaddr_t)(va) & PADDR_MASK))
>>  #define maddr_to_virt(pa) ((void *)((paddr_t)(pa) | XEN_VIRT_START))
> 
> Is it intentional that the additions don't align, padding-wise, with the
> surrounding #define-s?
>

No -- good catch. I'll adjust the padding to line up properly.

>> @@ -13,6 +28,237 @@
>>  #define __pa(x)             (virt_to_maddr(x))
>>  #define __va(x)             (maddr_to_virt(x))
>>
>> -void setup_initial_pagetables(void);
>> +/* Convert between Xen-heap virtual addresses and machine frame numbers. */
>> +#define __virt_to_mfn(va) (virt_to_maddr(va) >> PAGE_SHIFT)
>> +#define __mfn_to_virt(mfn) (maddr_to_virt((paddr_t)(mfn) << PAGE_SHIFT))
>> +
>> +/* Convert between Xen-heap virtual addresses and page-info structures. */
>> +static inline struct page_info *virt_to_page(const void *v)
>> +{
>> +    BUG_ON("unimplemented");
>> +    return NULL;
>> +}
>> +
>> +/*
>> + * We define non-underscored wrappers for above conversion functions.
>> + * These are overriden in various source files while underscored version
>> + * remain intact.
>> + */
>> +#define virt_to_mfn(va)     __virt_to_mfn(va)
>> +#define mfn_to_virt(mfn)    __mfn_to_virt(mfn)
> 
> Is the comment really applicable? The only non-arch-specific file still
> doing so is xenoprof.c, and I'm not sure you mean to support xenoprof
> on PPC. PPC-specific files would better be introduced in a type-safe way
> right from the beginning.
>

To be clear, you're suggesting that I define virt_to_mfn and mfn_to_virt
to operate on the type-safe mfn_t wrapper? When doing this,
xen/include/xen/domain_page.h:63 fails to build, since it seems to
assume that these macros do not use the type-safe mfn_t:

  static inline void *map_domain_page_global(mfn_t mfn)
  {
      return mfn_to_virt(mfn_x(mfn));
  }

If the comment is no longer accurate I can drop it, but there definitely
seems to be an assumption in the codebase that these macros operate on
raw unsigned longs rather than mfn_t.

>> +#define PG_shift(idx)   (BITS_PER_LONG - (idx))
>> +#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
>> +
>> +#define PGT_none          PG_mask(0, 1)  /* no special uses of this page   */
>> +#define PGT_writable_page PG_mask(1, 1)  /* has writable mappings?         */
>> +#define PGT_type_mask     PG_mask(1, 1)  /* Bits 31 or 63.                 */
>> +
>> + /* 2-bit count of uses of this frame as its current type. */
>> +#define PGT_count_mask    PG_mask(3, 3)
>> +
>> +/* Cleared when the owning guest 'frees' this page. */
>> +#define _PGC_allocated    PG_shift(1)
>> +#define PGC_allocated     PG_mask(1, 1)
>> +/* Page is Xen heap? */
>> +#define _PGC_xen_heap     PG_shift(2)
>> +#define PGC_xen_heap      PG_mask(1, 2)
>> +/* Page is broken? */
>> +#define _PGC_broken       PG_shift(7)
>> +#define PGC_broken        PG_mask(1, 7)
>> + /* Mutually-exclusive page states: { inuse, offlining, offlined, free }. */
>> +#define PGC_state         PG_mask(3, 9)
>> +#define PGC_state_inuse   PG_mask(0, 9)
>> +#define PGC_state_offlining PG_mask(1, 9)
>> +#define PGC_state_offlined PG_mask(2, 9)
>> +#define PGC_state_free    PG_mask(3, 9)
>> +#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
>> +/* Page is not reference counted */
>> +#define _PGC_extra        PG_shift(10)
>> +#define PGC_extra         PG_mask(1, 10)
>> +
>> +/* Count of references to this frame. */
>> +#define PGC_count_width   PG_shift(10)
>> +#define PGC_count_mask    ((1UL<<PGC_count_width)-1)
>> +
>> +/*
>> + * Page needs to be scrubbed. Since this bit can only be set on a page that is
>> + * free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
>> + */
>> +#define _PGC_need_scrub   _PGC_allocated
>> +#define PGC_need_scrub    PGC_allocated
>> +
>> +#define is_xen_heap_page(page) ((page)->count_info & PGC_xen_heap)
>> +#define is_xen_heap_mfn(mfn) \
>> +    (mfn_valid(mfn) && is_xen_heap_page(mfn_to_page(mfn)))
>> +
>> +#define is_xen_fixed_mfn(mfn)                                   \
>> +    ((mfn_to_maddr(mfn) >= virt_to_maddr(&_start)) &&           \
>> +     (mfn_to_maddr(mfn) <= virt_to_maddr((vaddr_t)_end - 1)))
> 
> Please use (or, preferred, do not use) & and cast consistently on _start
> and _end.
>

Will fix.

>> +#define page_get_owner(_p)    (_p)->v.inuse.domain
>> +#define page_set_owner(_p,_d) ((_p)->v.inuse.domain = (_d))
>> +
>> +/* TODO: implement */
>> +#define mfn_valid(mfn) ({ (void) (mfn); 0; })
>> +
>> +#define domain_set_alloc_bitsize(d) ((void)(d))
>> +#define domain_clamp_alloc_bitsize(d, b) (b)
>> +
>> +#define PFN_ORDER(pfn_) ((pfn_)->v.free.order)
>> +
>> +struct page_info
>> +{
>> +    /* Each frame can be threaded onto a doubly-linked list. */
>> +    struct page_list_entry list;
>> +
>> +    /* Reference count and various PGC_xxx flags and fields. */
>> +    unsigned long count_info;
>> +
>> +    /* Context-dependent fields follow... */
>> +    union {
>> +        /* Page is in use: ((count_info & PGC_count_mask) != 0). */
>> +        struct {
>> +            /* Type reference count and various PGT_xxx flags and fields. */
>> +            unsigned long type_info;
>> +        } inuse;
>> +        /* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
>> +        union {
>> +            struct {
>> +                /*
>> +                 * Index of the first *possibly* unscrubbed page in the buddy.
>> +                 * One more bit than maximum possible order to accommodate
>> +                 * INVALID_DIRTY_IDX.
>> +                 */
>> +#define INVALID_DIRTY_IDX ((1UL << (MAX_ORDER + 1)) - 1)
>> +                unsigned long first_dirty:MAX_ORDER + 1;
>> +
>> +                /* Do TLBs need flushing for safety before next page use? */
>> +                bool need_tlbflush:1;
>> +
>> +#define BUDDY_NOT_SCRUBBING    0
>> +#define BUDDY_SCRUBBING        1
>> +#define BUDDY_SCRUB_ABORT      2
>> +                unsigned long scrub_state:2;
>> +            };
>> +
>> +            unsigned long val;
>> +        } free;
>> +
>> +    } u;
>> +
>> +    union {
>> +        /* Page is in use, but not as a shadow. */
>> +        struct {
>> +            /* Owner of this page (zero if page is anonymous). */
>> +            struct domain *domain;
> 
> Since this is a pointer, NULL (instead of zero) would seem more appropriate
> in the comment.
>

Will update comment.

>> +        } inuse;
>> +
>> +        /* Page is on a free list. */
>> +        struct {
>> +            /* Order-size of the free chunk this page is the head of. */
>> +            unsigned int order;
>> +        } free;
>> +
>> +    } v;
>> +
>> +    union {
>> +        /*
>> +         * Timestamp from 'TLB clock', used to avoid extra safety flushes.
>> +         * Only valid for: a) free pages, and b) pages with zero type count
>> +         */
>> +        u32 tlbflush_timestamp;
>> +    };
>> +    u64 pad;
> 
> uint<N>_t please (or unsigned int/long).
>

Will use uint<N>_t.

>> --- /dev/null
>> +++ b/xen/arch/ppc/include/asm/monitor.h
>> @@ -0,0 +1,43 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/* Derived from xen/arch/arm/include/asm/monitor.h */
>> +#ifndef __ASM_PPC_MONITOR_H__
>> +#define __ASM_PPC_MONITOR_H__
>> +
>> +#include <public/domctl.h>
>> +#include <xen/errno.h>
>> +
>> +static inline
>> +void arch_monitor_allow_userspace(struct domain *d, bool allow_userspace)
>> +{
>> +}
>> +
>> +static inline
>> +int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
>> +{
>> +    /* No arch-specific monitor ops on PPC. */
>> +    return -EOPNOTSUPP;
>> +}
>> +
>> +int arch_monitor_domctl_event(struct domain *d,
>> +                              struct xen_domctl_monitor_op *mop);
>> +
>> +static inline
>> +int arch_monitor_init_domain(struct domain *d)
>> +{
>> +    /* No arch-specific domain initialization on PPC. */
>> +    return 0;
>> +}
>> +
>> +static inline
>> +void arch_monitor_cleanup_domain(struct domain *d)
>> +{
>> +    /* No arch-specific domain cleanup on PPC. */
>> +}
>> +
>> +static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
>> +{
>> +    BUG_ON("unimplemented");
>> +    return 0;
>> +}
>> +
>> +#endif /* __ASM_PPC_MONITOR_H__ */
> 
>>From a formal perspective you'll need Tamas's ack for this file, so you
> may want to Cc him. (Also for vm_event.h, unless the generic solution
> there doesn't land first.)
>

My apologies, meant to CC him but forgot. Will do for next version of
series.

>> --- /dev/null
>> +++ b/xen/arch/ppc/include/asm/p2m.h
>> @@ -0,0 +1,105 @@
>> +#ifndef __ASM_PPC_P2M_H__
>> +#define __ASM_PPC_P2M_H__
>> +
>> +#include <asm/page-bits.h>
>> +
>> +#define paddr_bits PADDR_BITS
>> +
>> +/*
>> + * List of possible type for each page in the p2m entry.
>> + * The number of available bit per page in the pte for this purpose is 4 bits.
>> + * So it's possible to only have 16 fields. If we run out of value in the
>> + * future, it's possible to use higher value for pseudo-type and don't store
>> + * them in the p2m entry.
>> + */
>> +typedef enum {
>> +    p2m_invalid = 0,    /* Nothing mapped here */
>> +    p2m_ram_rw,         /* Normal read/write guest RAM */
>> +    p2m_ram_ro,         /* Read-only; writes are silently dropped */
>> +    p2m_mmio_direct_dev,/* Read/write mapping of genuine Device MMIO area */
>> +    p2m_mmio_direct_nc, /* Read/write mapping of genuine MMIO area non-cacheable */
>> +    p2m_mmio_direct_c,  /* Read/write mapping of genuine MMIO area cacheable */
> 
> Didn't you agree to drop at least what's clear Arm-specific?
>

Yes -- that was an oversight. Will fix.

>> --- a/xen/arch/ppc/include/asm/system.h
>> +++ b/xen/arch/ppc/include/asm/system.h
>> @@ -1,6 +1,228 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Copyright (C) IBM Corp. 2005
>> + * Copyright (C) Raptor Engineering LLC
>> + *
>> + * Authors: Jimi Xenidis <jimix@watson.ibm.com>
>> + *          Shawn Anastasio <sanastasio@raptorengineering.com>
>> + */
>> +
>>  #ifndef _ASM_SYSTEM_H_
>>  #define _ASM_SYSTEM_H_
>>
>> -#define smp_wmb() __asm__ __volatile__ ( "lwsync" : : : "memory" )
>> +#include <xen/lib.h>
>> +#include <asm/memory.h>
>> +#include <asm/time.h>
>> +#include <asm/processor.h>
>> +#include <asm/msr.h>
>> +
>> +#define xchg(ptr,x) 							                               \
>> +({									                                           \
>> +	__typeof__(*(ptr)) _x_ = (x);					                           \
> 
> Hard tabs look to have slipped in here.
>

Good eye. Will fix.

>> +	(__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr)));    \
>> +})
>> +
>> +#define build_xchg(fn, type, ldinsn, stinsn) \
>> +static inline unsigned long fn(volatile type *m, unsigned long val)            \
>> +{                                                                              \
>> +    unsigned long dummy;                                                       \
>> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER                                    \
>> +                   "1: " ldinsn " %0,0,%3\n"                                   \
>> +                   stinsn " %2,0,%3\n"                                         \
>> +                   "2:  bne- 1b"                                               \
>> +                   PPC_ATOMIC_EXIT_BARRIER                                     \
>> +                   : "=&r" (dummy), "=m" (*m)                                  \
>> +                   : "r" (val), "r" (m)                                        \
>> +                   : "cc", "memory" );                                         \
>> +    return dummy;                                                              \
>> +}
>> +
>> +build_xchg(__xchg_u8, uint8_t, "lbarx", "stbcx.")
>> +build_xchg(__xchg_u16, uint16_t, "lharx", "sthcx.")
>> +build_xchg(__xchg_u32, uint32_t, "lwarx", "stwcx.")
>> +build_xchg(__xchg_u64, uint64_t, "ldarx", "stdcx.")
>> +
>> +#undef build_xchg
>> +
>> +/*
>> + * This function doesn't exist, so you'll get a linker error
>> + * if something tries to do an invalid xchg().
>> + */
>> +extern void __xchg_called_with_bad_pointer(void);
>> +
>> +static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
>> +                                   int size)
>> +{
>> +    switch (size) {
> 
> Nit: Since the file looks like it wants to use Xen style:
> 
>     switch ( size )
>     {
> 
> please.
>

Will do.

>> +    case 1:
>> +        return __xchg_u8(ptr, x);
>> +    case 2:
>> +        return __xchg_u16(ptr, x);
>> +    case 4:
>> +        return __xchg_u32(ptr, x);
>> +    case 8:
>> +        return __xchg_u64(ptr, x);
>> +    }
>> +    __xchg_called_with_bad_pointer();
>> +    return x;
>> +}
>> +
>> +
>> +static inline unsigned long __cmpxchg_u32(volatile int *p, int old, int new)
>> +{
>> +    unsigned int prev;
>> +
>> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
>> +                   "1: lwarx   %0,0,%2\n"
>> +                   "cmpw    0,%0,%3\n"
>> +                   "bne-    2f\n "
>> +                   "stwcx.  %4,0,%2\n"
>> +                   "bne-    1b\n"
>> +                   PPC_ATOMIC_EXIT_BARRIER "\n"
>> +                   "2:"
>> +                   : "=&r" (prev), "=m" (*p)
>> +                   : "r" (p), "r" (old), "r" (new), "m" (*p)
>> +                   : "cc", "memory" );
>> +
>> +    return prev;
>> +}
>> +
>> +static inline unsigned long __cmpxchg_u64(volatile long *p, unsigned long old,
>> +                                          unsigned long new)
>> +{
>> +    unsigned long prev;
>> +
>> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
>> +                   "1: ldarx   %0,0,%2\n"
>> +                   "cmpd    0,%0,%3\n"
>> +                   "bne-    2f\n"
>> +                   "stdcx.  %4,0,%2\n"
>> +                   "bne-    1b"
>> +                   PPC_ATOMIC_EXIT_BARRIER "\n"
>> +                   "2:"
>> +                   : "=&r" (prev), "=m" (*p)
>> +                   : "r" (p), "r" (old), "r" (new), "m" (*p)
>> +                   : "cc", "memory" );
>> +
>> +    return prev;
>> +}
>> +
>> +/* This function doesn't exist, so you'll get a linker error
>> +   if something tries to do an invalid cmpxchg().  */
>> +extern void __cmpxchg_called_with_bad_pointer(void);
>> +
>> +static always_inline unsigned long __cmpxchg(
>> +    volatile void *ptr,
>> +    unsigned long old,
>> +    unsigned long new,
>> +    int size)
>> +{
>> +    switch (size) {
>> +    case 2:
>> +        BUG_ON("unimplemented"); return 0; /* XXX implement __cmpxchg_u16 ? */
>> +    case 4:
>> +        return __cmpxchg_u32(ptr, old, new);
>> +    case 8:
>> +        return __cmpxchg_u64(ptr, old, new);
>> +    }
>> +    __cmpxchg_called_with_bad_pointer();
>> +    return old;
>> +}
>> +
>> +#define cmpxchg_user(ptr,o,n) cmpxchg(ptr,o,n)
>> +
>> +#define cmpxchg(ptr,o,n)                         \
>> +  ({                                     \
>> +     __typeof__(*(ptr)) _o_ = (o);                   \
>> +     __typeof__(*(ptr)) _n_ = (n);                   \
>> +     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,       \
>> +                    (unsigned long)_n_, sizeof(*(ptr))); \
> 
> Not: Style (multiple previously mentioned issues).
>

Will clean up.

>> +  })
>> +
>> +
>> +/*
>> + * Memory barrier.
>> + * The sync instruction guarantees that all memory accesses initiated
>> + * by this processor have been performed (with respect to all other
>> + * mechanisms that access memory).  The eieio instruction is a barrier
>> + * providing an ordering (separately) for (a) cacheable stores and (b)
>> + * loads and stores to non-cacheable memory (e.g. I/O devices).
>> + *
>> + * mb() prevents loads and stores being reordered across this point.
>> + * rmb() prevents loads being reordered across this point.
>> + * wmb() prevents stores being reordered across this point.
>> + * read_barrier_depends() prevents data-dependent loads being reordered
>> + *  across this point (nop on PPC).
>> + *
>> + * We have to use the sync instructions for mb(), since lwsync doesn't
>> + * order loads with respect to previous stores.  Lwsync is fine for
>> + * rmb(), though.
>> + * For wmb(), we use sync since wmb is used in drivers to order
>> + * stores to system memory with respect to writes to the device.
>> + * However, smp_wmb() can be a lighter-weight eieio barrier on
>> + * SMP since it is only used to order updates to system memory.
>> + */
>> +#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
>> +#define rmb()  __asm__ __volatile__ ("lwsync" : : : "memory")
>> +#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
> 
> Nit: Missing blanks.
>

Will fix.

>> +#define read_barrier_depends()  do { } while(0)
>> +
>> +#define set_mb(var, value)  do { var = value; smp_mb(); } while (0)
>> +#define set_wmb(var, value) do { var = value; smp_wmb(); } while (0)
>> +
>> +#define smp_mb__before_atomic()    smp_mb()
>> +#define smp_mb__after_atomic()     smp_mb()
>> +
>> +#ifdef CONFIG_SMP
>> +#define smp_mb()    mb()
>> +#define smp_rmb()   rmb()
>> +#define smp_wmb()   __asm__ __volatile__ ("lwsync" : : : "memory")
>> +#define smp_read_barrier_depends()  read_barrier_depends()
>> +#else
>> +#define smp_mb()    __asm__ __volatile__("": : :"memory")
>> +#define smp_rmb()   __asm__ __volatile__("": : :"memory")
>> +#define smp_wmb()   __asm__ __volatile__("": : :"memory")
> 
> And more missing blanks (further below from here).
>

Will fix, along with removal of dead !CONFIG_SMP path.

>> +#define smp_read_barrier_depends()  do { } while(0)
>> +#endif /* CONFIG_SMP */
>> +
>> +#define local_save_flags(flags) ((flags) = mfmsr())
>> +#define local_irq_restore(flags) do { \
>> +        __asm__ __volatile__("": : :"memory"); \
>> +        mtmsrd((flags)); \
>> +} while(0)
>> +
>> +static inline void local_irq_disable(void)
>> +{
>> +    unsigned long msr;
>> +    msr = mfmsr();
>> +    mtmsrd(msr & ~MSR_EE);
>> +    asm volatile ( "" : : : "memory" );
> 
> That's simply barrier(), isn't it? Please avoid open-coding. (More
> further down.)
>

Good call. Will change all occurrences to barrier().

>> --- /dev/null
>> +++ b/xen/arch/ppc/include/asm/time.h
>> @@ -0,0 +1,21 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +#ifndef __ASM_PPC_TIME_H__
>> +#define __ASM_PPC_TIME_H__
>> +
>> +#include <xen/lib.h>
>> +#include <asm/processor.h>
>> +#include <asm/regs.h>
>> +
>> +struct vcpu;
>> +
>> +/* TODO: implement */
>> +static inline void force_update_vcpu_system_time(struct vcpu *v) { BUG_ON("unimplemented"); }
> 
> Nit: Too long line.
>

Will fix.

> Jan

Thanks,
Shawn
Jan Beulich Sept. 11, 2023, 6:26 a.m. UTC | #3
On 09.09.2023 00:05, Shawn Anastasio wrote:
> On 9/5/23 10:52 AM, Jan Beulich wrote:
>> On 01.09.2023 20:25, Shawn Anastasio wrote:
>>> @@ -13,6 +28,237 @@
>>>  #define __pa(x)             (virt_to_maddr(x))
>>>  #define __va(x)             (maddr_to_virt(x))
>>>
>>> -void setup_initial_pagetables(void);
>>> +/* Convert between Xen-heap virtual addresses and machine frame numbers. */
>>> +#define __virt_to_mfn(va) (virt_to_maddr(va) >> PAGE_SHIFT)
>>> +#define __mfn_to_virt(mfn) (maddr_to_virt((paddr_t)(mfn) << PAGE_SHIFT))
>>> +
>>> +/* Convert between Xen-heap virtual addresses and page-info structures. */
>>> +static inline struct page_info *virt_to_page(const void *v)
>>> +{
>>> +    BUG_ON("unimplemented");
>>> +    return NULL;
>>> +}
>>> +
>>> +/*
>>> + * We define non-underscored wrappers for above conversion functions.
>>> + * These are overriden in various source files while underscored version
>>> + * remain intact.
>>> + */
>>> +#define virt_to_mfn(va)     __virt_to_mfn(va)
>>> +#define mfn_to_virt(mfn)    __mfn_to_virt(mfn)
>>
>> Is the comment really applicable? The only non-arch-specific file still
>> doing so is xenoprof.c, and I'm not sure you mean to support xenoprof
>> on PPC. PPC-specific files would better be introduced in a type-safe way
>> right from the beginning.
>>
> 
> To be clear, you're suggesting that I define virt_to_mfn and mfn_to_virt
> to operate on the type-safe mfn_t wrapper? When doing this,
> xen/include/xen/domain_page.h:63 fails to build, since it seems to
> assume that these macros do not use the type-safe mfn_t:
> 
>   static inline void *map_domain_page_global(mfn_t mfn)
>   {
>       return mfn_to_virt(mfn_x(mfn));
>   }

Oh, I see. That's a result of (at least) 41c48004d1d8 ("xen/mm: Use
__virt_to_mfn in map_domain_page instead of virt_to_mfn") not going far
enough and f46b6197344f ("xen: Convert page_to_mfn and mfn_to_page to
use typesafe MFN") not properly doing the intended conversion. Let me
(try to) make a patch, once again ...

> If the comment is no longer accurate I can drop it, but there definitely
> seems to be an assumption in the codebase that these macros operate on
> raw unsigned longs rather than mfn_t.

Well, the comment is new (in PPC), so it cannot really be "no longer
accurate". It (sadly) still is accurate in Arm, but I was hoping we
would be able to do better in new ports.

Jan
diff mbox series

Patch

diff --git a/xen/arch/ppc/Kconfig b/xen/arch/ppc/Kconfig
index ab116ffb2a..a6eae597af 100644
--- a/xen/arch/ppc/Kconfig
+++ b/xen/arch/ppc/Kconfig
@@ -1,6 +1,7 @@ 
 config PPC
 	def_bool y
 	select HAS_DEVICE_TREE
+	select HAS_PDX

 config PPC64
 	def_bool y
diff --git a/xen/arch/ppc/include/asm/altp2m.h b/xen/arch/ppc/include/asm/altp2m.h
new file mode 100644
index 0000000000..bd5c9aa415
--- /dev/null
+++ b/xen/arch/ppc/include/asm/altp2m.h
@@ -0,0 +1,25 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_ALTP2M_H__
+#define __ASM_PPC_ALTP2M_H__
+
+#include <xen/bug.h>
+
+struct domain;
+struct vcpu;
+
+/* Alternate p2m on/off per domain */
+static inline bool altp2m_active(const struct domain *d)
+{
+    /* Not implemented on PPC. */
+    return false;
+}
+
+/* Alternate p2m VCPU */
+static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v)
+{
+    /* Not implemented on PPC, should not be reached. */
+    ASSERT_UNREACHABLE();
+    return 0;
+}
+
+#endif /* __ASM_PPC_ALTP2M_H__ */
diff --git a/xen/arch/ppc/include/asm/bug.h b/xen/arch/ppc/include/asm/bug.h
index e5e874b31c..35d4568402 100644
--- a/xen/arch/ppc/include/asm/bug.h
+++ b/xen/arch/ppc/include/asm/bug.h
@@ -4,6 +4,7 @@ 
 #define _ASM_PPC_BUG_H

 #include <xen/stringify.h>
+#include <asm/processor.h>

 /*
  * Power ISA guarantees that an instruction consisting of all zeroes is
@@ -15,4 +16,12 @@ 

 #define BUG_FN_REG r0

+/* TODO: implement this properly */
+#define BUG() do { \
+    die(); \
+} while (0)
+
+/* TODO: implement this properly */
+#define BUG_FRAME(type, line, ptr, second_frame, msg) do { } while (0)
+
 #endif /* _ASM_PPC_BUG_H */
diff --git a/xen/arch/ppc/include/asm/cache.h b/xen/arch/ppc/include/asm/cache.h
index 8a0a6b7b17..0d7323d789 100644
--- a/xen/arch/ppc/include/asm/cache.h
+++ b/xen/arch/ppc/include/asm/cache.h
@@ -3,4 +3,6 @@ 
 #ifndef _ASM_PPC_CACHE_H
 #define _ASM_PPC_CACHE_H

+#define __read_mostly __section(".data.read_mostly")
+
 #endif /* _ASM_PPC_CACHE_H */
diff --git a/xen/arch/ppc/include/asm/config.h b/xen/arch/ppc/include/asm/config.h
index 30438d22d2..a11a09c570 100644
--- a/xen/arch/ppc/include/asm/config.h
+++ b/xen/arch/ppc/include/asm/config.h
@@ -1,3 +1,4 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef __PPC_CONFIG_H__
 #define __PPC_CONFIG_H__

@@ -41,6 +42,15 @@ 

 #define XEN_VIRT_START _AC(0xc000000000000000, UL)

+#define VMAP_VIRT_START (XEN_VIRT_START + GB(1))
+#define VMAP_VIRT_SIZE  GB(1)
+
+#define FRAMETABLE_VIRT_START  (XEN_VIRT_START + GB(32))
+#define FRAMETABLE_SIZE        GB(32)
+#define FRAMETABLE_NR          (FRAMETABLE_SIZE / sizeof(*frame_table))
+
+#define HYPERVISOR_VIRT_START  XEN_VIRT_START
+
 #define SMP_CACHE_BYTES (1 << 6)

 #define STACK_ORDER 0
diff --git a/xen/arch/ppc/include/asm/cpufeature.h b/xen/arch/ppc/include/asm/cpufeature.h
new file mode 100644
index 0000000000..1c5946512b
--- /dev/null
+++ b/xen/arch/ppc/include/asm/cpufeature.h
@@ -0,0 +1,10 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_CPUFEATURE_H__
+#define __ASM_PPC_CPUFEATURE_H__
+
+static inline int cpu_nr_siblings(unsigned int cpu)
+{
+    return 1;
+}
+
+#endif /* __ASM_PPC_CPUFEATURE_H__ */
diff --git a/xen/arch/ppc/include/asm/current.h b/xen/arch/ppc/include/asm/current.h
new file mode 100644
index 0000000000..0ca06033f9
--- /dev/null
+++ b/xen/arch/ppc/include/asm/current.h
@@ -0,0 +1,43 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_CURRENT_H__
+#define __ASM_PPC_CURRENT_H__
+
+#include <xen/percpu.h>
+
+#ifndef __ASSEMBLY__
+
+struct vcpu;
+
+/* Which VCPU is "current" on this PCPU. */
+DECLARE_PER_CPU(struct vcpu *, curr_vcpu);
+
+#define current            (this_cpu(curr_vcpu))
+#define set_current(vcpu)  do { current = (vcpu); } while (0)
+#define get_cpu_current(cpu)  (per_cpu(curr_vcpu, cpu))
+
+/* Per-VCPU state that lives at the top of the stack */
+struct cpu_info {
+    struct cpu_user_regs guest_cpu_user_regs;
+    unsigned long elr;
+    unsigned int flags;
+};
+
+static inline struct cpu_info *get_cpu_info(void)
+{
+#ifdef __clang__
+    unsigned long sp;
+
+    asm ( "mr %0, 1" : "=r" (sp) );
+#else
+    register unsigned long sp asm ("r1");
+#endif
+
+    return (struct cpu_info *)((sp & ~(STACK_SIZE - 1)) +
+                               STACK_SIZE - sizeof(struct cpu_info));
+}
+
+#define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PPC_CURRENT_H__ */
diff --git a/xen/arch/ppc/include/asm/delay.h b/xen/arch/ppc/include/asm/delay.h
new file mode 100644
index 0000000000..da6635888b
--- /dev/null
+++ b/xen/arch/ppc/include/asm/delay.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_DELAY_H__
+#define __ASM_PPC_DELAY_H__
+
+#include <xen/lib.h>
+
+static inline void udelay(unsigned long usecs)
+{
+    BUG_ON("unimplemented");
+}
+
+#endif /* __ASM_PPC_DELAY_H__ */
diff --git a/xen/arch/ppc/include/asm/device.h b/xen/arch/ppc/include/asm/device.h
new file mode 100644
index 0000000000..b0cbfc1648
--- /dev/null
+++ b/xen/arch/ppc/include/asm/device.h
@@ -0,0 +1,53 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_DEVICE_H__
+#define __ASM_PPC_DEVICE_H__
+
+enum device_type
+{
+    DEV_DT,
+    DEV_PCI,
+};
+
+struct device {
+    enum device_type type;
+#ifdef CONFIG_HAS_DEVICE_TREE
+    struct dt_device_node *of_node; /* Used by drivers imported from Linux */
+#endif
+};
+
+enum device_class
+{
+    DEVICE_SERIAL,
+    DEVICE_IOMMU,
+    DEVICE_PCI_HOSTBRIDGE,
+    /* Use for error */
+    DEVICE_UNKNOWN,
+};
+
+struct device_desc {
+    /* Device name */
+    const char *name;
+    /* Device class */
+    enum device_class class;
+    /* List of devices supported by this driver */
+    const struct dt_device_match *dt_match;
+    /*
+     * Device initialization.
+     *
+     * -EAGAIN is used to indicate that device probing is deferred.
+     */
+    int (*init)(struct dt_device_node *dev, const void *data);
+};
+
+typedef struct device device_t;
+
+#define DT_DEVICE_START(_name, _namestr, _class)                    \
+static const struct device_desc __dev_desc_##_name __used           \
+__section(".dev.info") = {                                          \
+    .name = _namestr,                                               \
+    .class = _class,                                                \
+
+#define DT_DEVICE_END                                               \
+};
+
+#endif /* __ASM_PPC_DEVICE_H__ */
diff --git a/xen/arch/ppc/include/asm/div64.h b/xen/arch/ppc/include/asm/div64.h
new file mode 100644
index 0000000000..d213e50585
--- /dev/null
+++ b/xen/arch/ppc/include/asm/div64.h
@@ -0,0 +1,14 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_DIV64_H__
+#define __ASM_PPC_DIV64_H__
+
+#include <xen/types.h>
+
+#define do_div(n, base) ({                       \
+    uint32_t base_ = (base);                     \
+    uint32_t rem_ = (uint64_t)(n) % base_;       \
+    (n) = (uint64_t)(n) / base_;                 \
+    rem_;                                        \
+})
+
+#endif /* __ASM_PPC_DIV64_H__ */
diff --git a/xen/arch/ppc/include/asm/domain.h b/xen/arch/ppc/include/asm/domain.h
new file mode 100644
index 0000000000..573276d0a8
--- /dev/null
+++ b/xen/arch/ppc/include/asm/domain.h
@@ -0,0 +1,47 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_DOMAIN_H__
+#define __ASM_PPC_DOMAIN_H__
+
+#include <xen/xmalloc.h>
+#include <public/hvm/params.h>
+
+struct hvm_domain
+{
+    uint64_t              params[HVM_NR_PARAMS];
+};
+
+#define is_domain_direct_mapped(d) ((void)(d), 0)
+
+/* TODO: Implement */
+#define guest_mode(r) ({ (void)(r); BUG_ON("unimplemented"); 0; })
+
+struct arch_vcpu_io {
+};
+
+struct arch_vcpu {
+};
+
+struct arch_domain {
+    struct hvm_domain hvm;
+};
+
+#include <xen/sched.h>
+
+static inline struct vcpu_guest_context *alloc_vcpu_guest_context(void)
+{
+    return xmalloc(struct vcpu_guest_context);
+}
+
+static inline void free_vcpu_guest_context(struct vcpu_guest_context *vgc)
+{
+    xfree(vgc);
+}
+
+struct guest_memory_policy {};
+static inline void update_guest_memory_policy(struct vcpu *v,
+                                              struct guest_memory_policy *gmp)
+{}
+
+static inline void arch_vcpu_block(struct vcpu *v) {}
+
+#endif /* __ASM_PPC_DOMAIN_H__ */
diff --git a/xen/arch/ppc/include/asm/event.h b/xen/arch/ppc/include/asm/event.h
new file mode 100644
index 0000000000..1b95ee4f61
--- /dev/null
+++ b/xen/arch/ppc/include/asm/event.h
@@ -0,0 +1,36 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_EVENT_H__
+#define __ASM_PPC_EVENT_H__
+
+#include <xen/lib.h>
+
+/* TODO: implement */
+static inline void vcpu_kick(struct vcpu *v) { BUG_ON("unimplemented"); }
+static inline void vcpu_mark_events_pending(struct vcpu *v) { BUG_ON("unimplemented"); }
+static inline void vcpu_update_evtchn_irq(struct vcpu *v) { BUG_ON("unimplemented"); }
+static inline void vcpu_block_unless_event_pending(struct vcpu *v) { BUG_ON("unimplemented"); }
+
+static inline int vcpu_event_delivery_is_enabled(struct vcpu *v)
+{
+    BUG_ON("unimplemented");
+    return 0;
+}
+
+/* No arch specific virq definition now. Default to global. */
+static inline bool arch_virq_is_global(unsigned int virq)
+{
+    return true;
+}
+
+static inline int local_events_need_delivery(void)
+{
+    BUG_ON("unimplemented");
+    return 0;
+}
+
+static inline void local_event_delivery_enable(void)
+{
+    BUG_ON("unimplemented");
+}
+
+#endif /* __ASM_PPC_EVENT_H__ */
diff --git a/xen/arch/ppc/include/asm/flushtlb.h b/xen/arch/ppc/include/asm/flushtlb.h
new file mode 100644
index 0000000000..afcb740783
--- /dev/null
+++ b/xen/arch/ppc/include/asm/flushtlb.h
@@ -0,0 +1,24 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_FLUSHTLB_H__
+#define __ASM_PPC_FLUSHTLB_H__
+
+#include <xen/cpumask.h>
+
+/*
+ * Filter the given set of CPUs, removing those that definitely flushed their
+ * TLB since @page_timestamp.
+ */
+/* XXX lazy implementation just doesn't clear anything.... */
+static inline void tlbflush_filter(cpumask_t *mask, uint32_t page_timestamp) {}
+
+#define tlbflush_current_time()                 (0)
+
+static inline void page_set_tlbflush_timestamp(struct page_info *page)
+{
+    page->tlbflush_timestamp = tlbflush_current_time();
+}
+
+/* Flush specified CPUs' TLBs */
+void arch_flush_tlb_mask(const cpumask_t *mask);
+
+#endif /* __ASM_PPC_FLUSHTLB_H__ */
diff --git a/xen/arch/ppc/include/asm/grant_table.h b/xen/arch/ppc/include/asm/grant_table.h
new file mode 100644
index 0000000000..d0ff58dd3d
--- /dev/null
+++ b/xen/arch/ppc/include/asm/grant_table.h
@@ -0,0 +1,5 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_GRANT_TABLE_H__
+#define __ASM_PPC_GRANT_TABLE_H__
+
+#endif /* __ASM_PPC_GRANT_TABLE_H__ */
diff --git a/xen/arch/ppc/include/asm/guest_access.h b/xen/arch/ppc/include/asm/guest_access.h
new file mode 100644
index 0000000000..6546931911
--- /dev/null
+++ b/xen/arch/ppc/include/asm/guest_access.h
@@ -0,0 +1,68 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_GUEST_ACCESS_H__
+#define __ASM_PPC_GUEST_ACCESS_H__
+
+#include <xen/mm.h>
+
+/* TODO */
+
+static inline unsigned long raw_copy_to_guest(
+    void *to,
+    const void *from,
+    unsigned int len)
+{
+    BUG_ON("unimplemented");
+}
+static inline unsigned long raw_copy_to_guest_flush_dcache(
+    void *to,
+    const void *from,
+    unsigned int len)
+{
+    BUG_ON("unimplemented");
+}
+static inline unsigned long raw_copy_from_guest(
+    void *to,
+    const void *from,
+    unsigned int len)
+{
+    BUG_ON("unimplemented");
+}
+static inline unsigned long raw_clear_guest(void *to, unsigned int len)
+{
+    BUG_ON("unimplemented");
+}
+
+/* Copy data to guest physical address, then clean the region. */
+static inline unsigned long copy_to_guest_phys_flush_dcache(
+    struct domain *d,
+    paddr_t gpa,
+    void *buf,
+    unsigned int len)
+{
+    BUG_ON("unimplemented");
+}
+
+static inline int access_guest_memory_by_gpa(
+    struct domain *d,
+    paddr_t gpa,
+    void *buf,
+    uint32_t size,
+    bool is_write)
+{
+    BUG_ON("unimplemented");
+}
+
+
+#define __raw_copy_to_guest raw_copy_to_guest
+#define __raw_copy_from_guest raw_copy_from_guest
+#define __raw_clear_guest raw_clear_guest
+
+/*
+ * Pre-validate a guest handle.
+ * Allows use of faster __copy_* functions.
+ */
+/* All PPC guests are paging mode external and hence safe */
+#define guest_handle_okay(hnd, nr) (1)
+#define guest_handle_subrange_okay(hnd, first, last) (1)
+
+#endif /* __ASM_PPC_GUEST_ACCESS_H__ */
diff --git a/xen/arch/ppc/include/asm/guest_atomics.h b/xen/arch/ppc/include/asm/guest_atomics.h
new file mode 100644
index 0000000000..1190e10bbb
--- /dev/null
+++ b/xen/arch/ppc/include/asm/guest_atomics.h
@@ -0,0 +1,23 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_GUEST_ATOMICS_H__
+#define __ASM_PPC_GUEST_ATOMICS_H__
+
+#include <xen/lib.h>
+
+/* TODO: implement */
+#define unimplemented_guest_bit_op(d, nr, p) ({                                \
+    (void)(d);                                                                 \
+    (void)(nr);                                                                \
+    (void)(p);                                                                 \
+    BUG_ON("unimplemented");                                                   \
+    false;                                                                     \
+})
+
+#define guest_test_bit(d, nr, p)            unimplemented_guest_bit_op(d, nr, p)
+#define guest_clear_bit(d, nr, p)           unimplemented_guest_bit_op(d, nr, p)
+#define guest_set_bit(d, nr, p)             unimplemented_guest_bit_op(d, nr, p)
+#define guest_test_and_set_bit(d, nr, p)    unimplemented_guest_bit_op(d, nr, p)
+#define guest_test_and_clear_bit(d, nr, p)  unimplemented_guest_bit_op(d, nr, p)
+#define guest_test_and_change_bit(d, nr, p) unimplemented_guest_bit_op(d, nr, p)
+
+#endif /* __ASM_PPC_GUEST_ATOMICS_H__ */
diff --git a/xen/arch/ppc/include/asm/hardirq.h b/xen/arch/ppc/include/asm/hardirq.h
new file mode 100644
index 0000000000..343efc7e69
--- /dev/null
+++ b/xen/arch/ppc/include/asm/hardirq.h
@@ -0,0 +1,19 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_HARDIRQ_H__
+#define __ASM_PPC_HARDIRQ_H__
+
+#include <xen/cache.h>
+
+typedef struct {
+        unsigned long __softirq_pending;
+        unsigned int __local_irq_count;
+} __cacheline_aligned irq_cpustat_t;
+
+#include <xen/irq_cpustat.h>    /* Standard mappings for irq_cpustat_t above */
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
+#define irq_enter()     (local_irq_count(smp_processor_id())++)
+#define irq_exit()      (local_irq_count(smp_processor_id())--)
+
+#endif /* __ASM_PPC_HARDIRQ_H__ */
diff --git a/xen/arch/ppc/include/asm/hypercall.h b/xen/arch/ppc/include/asm/hypercall.h
new file mode 100644
index 0000000000..1e8ca0ce9c
--- /dev/null
+++ b/xen/arch/ppc/include/asm/hypercall.h
@@ -0,0 +1,5 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_HYPERCALL_H__
+#define __ASM_PPC_HYPERCALL_H__
+
+#endif /* __ASM_PPC_HYPERCALL_H__ */
diff --git a/xen/arch/ppc/include/asm/io.h b/xen/arch/ppc/include/asm/io.h
new file mode 100644
index 0000000000..85b5b27157
--- /dev/null
+++ b/xen/arch/ppc/include/asm/io.h
@@ -0,0 +1,16 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_IO_H__
+#define __ASM_PPC_IO_H__
+
+#include <xen/lib.h>
+
+/* TODO */
+#define readb(c)        ({ (void)(c); BUG_ON("unimplemented"); 0; })
+#define readw(c)        ({ (void)(c); BUG_ON("unimplemented"); 0; })
+#define readl(c)        ({ (void)(c); BUG_ON("unimplemented"); 0; })
+
+#define writeb(v,c)     ({ (void)(v); (void)(c); BUG_ON("unimplemented"); })
+#define writew(v,c)     ({ (void)(v); (void)(c); BUG_ON("unimplemented"); })
+#define writel(v,c)     ({ (void)(v); (void)(c); BUG_ON("unimplemented"); })
+
+#endif /* __ASM_PPC_IO_H__ */
diff --git a/xen/arch/ppc/include/asm/iocap.h b/xen/arch/ppc/include/asm/iocap.h
new file mode 100644
index 0000000000..76bf13a70f
--- /dev/null
+++ b/xen/arch/ppc/include/asm/iocap.h
@@ -0,0 +1,8 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_IOCAP_H__
+#define __ASM_PPC_IOCAP_H__
+
+#define cache_flush_permitted(d)                        \
+    (!rangeset_is_empty((d)->iomem_caps))
+
+#endif /* __ASM_PPC_IOCAP_H__ */
diff --git a/xen/arch/ppc/include/asm/iommu.h b/xen/arch/ppc/include/asm/iommu.h
new file mode 100644
index 0000000000..024ead3473
--- /dev/null
+++ b/xen/arch/ppc/include/asm/iommu.h
@@ -0,0 +1,8 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_IOMMU_H__
+#define __ASM_PPC_IOMMU_H__
+
+struct arch_iommu {
+};
+
+#endif /* __ASM_PPC_IOMMU_H__ */
diff --git a/xen/arch/ppc/include/asm/irq.h b/xen/arch/ppc/include/asm/irq.h
new file mode 100644
index 0000000000..5c37d0cf25
--- /dev/null
+++ b/xen/arch/ppc/include/asm/irq.h
@@ -0,0 +1,33 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_IRQ_H__
+#define __ASM_PPC_IRQ_H__
+
+#include <xen/lib.h>
+#include <xen/device_tree.h>
+#include <public/device_tree_defs.h>
+
+/* TODO */
+#define nr_irqs 0U
+#define nr_static_irqs 0
+#define arch_hwdom_irqs(domid) 0U
+
+#define domain_pirq_to_irq(d, pirq) (pirq)
+
+struct arch_pirq {
+};
+
+struct arch_irq_desc {
+    unsigned int type;
+};
+
+static inline void arch_move_irqs(struct vcpu *v)
+{
+    BUG_ON("unimplemented");
+}
+
+static inline int platform_get_irq(const struct dt_device_node *device, int index)
+{
+    BUG_ON("unimplemented");
+}
+
+#endif /* __ASM_PPC_IRQ_H__ */
diff --git a/xen/arch/ppc/include/asm/mem_access.h b/xen/arch/ppc/include/asm/mem_access.h
new file mode 100644
index 0000000000..e7986dfdbd
--- /dev/null
+++ b/xen/arch/ppc/include/asm/mem_access.h
@@ -0,0 +1,5 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_MEM_ACCESS_H__
+#define __ASM_PPC_MEM_ACCESS_H__
+
+#endif /* __ASM_PPC_MEM_ACCESS_H__ */
diff --git a/xen/arch/ppc/include/asm/mm.h b/xen/arch/ppc/include/asm/mm.h
index c85a7ed686..124cfaddc2 100644
--- a/xen/arch/ppc/include/asm/mm.h
+++ b/xen/arch/ppc/include/asm/mm.h
@@ -1,10 +1,25 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef _ASM_PPC_MM_H
 #define _ASM_PPC_MM_H

+#include <public/xen.h>
+#include <xen/pdx.h>
+#include <xen/types.h>
+#include <asm/config.h>
 #include <asm/page-bits.h>
+#include <asm/page.h>
+
+void setup_initial_pagetables(void);

 #define pfn_to_paddr(pfn) ((paddr_t)(pfn) << PAGE_SHIFT)
 #define paddr_to_pfn(pa)  ((unsigned long)((pa) >> PAGE_SHIFT))
+#define paddr_to_pdx(pa)    mfn_to_pdx(maddr_to_mfn(pa))
+#define gfn_to_gaddr(gfn)   pfn_to_paddr(gfn_x(gfn))
+#define gaddr_to_gfn(ga)    _gfn(paddr_to_pfn(ga))
+#define mfn_to_maddr(mfn)   pfn_to_paddr(mfn_x(mfn))
+#define maddr_to_mfn(ma)    _mfn(paddr_to_pfn(ma))
+#define vmap_to_mfn(va)     maddr_to_mfn(virt_to_maddr((vaddr_t)va))
+#define vmap_to_page(va)    mfn_to_page(vmap_to_mfn(va))

 #define virt_to_maddr(va) ((paddr_t)((vaddr_t)(va) & PADDR_MASK))
 #define maddr_to_virt(pa) ((void *)((paddr_t)(pa) | XEN_VIRT_START))
@@ -13,6 +28,237 @@ 
 #define __pa(x)             (virt_to_maddr(x))
 #define __va(x)             (maddr_to_virt(x))

-void setup_initial_pagetables(void);
+/* Convert between Xen-heap virtual addresses and machine frame numbers. */
+#define __virt_to_mfn(va) (virt_to_maddr(va) >> PAGE_SHIFT)
+#define __mfn_to_virt(mfn) (maddr_to_virt((paddr_t)(mfn) << PAGE_SHIFT))
+
+/* Convert between Xen-heap virtual addresses and page-info structures. */
+static inline struct page_info *virt_to_page(const void *v)
+{
+    BUG_ON("unimplemented");
+    return NULL;
+}
+
+/*
+ * We define non-underscored wrappers for above conversion functions.
+ * These are overriden in various source files while underscored version
+ * remain intact.
+ */
+#define virt_to_mfn(va)     __virt_to_mfn(va)
+#define mfn_to_virt(mfn)    __mfn_to_virt(mfn)
+
+#define PG_shift(idx)   (BITS_PER_LONG - (idx))
+#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
+
+#define PGT_none          PG_mask(0, 1)  /* no special uses of this page   */
+#define PGT_writable_page PG_mask(1, 1)  /* has writable mappings?         */
+#define PGT_type_mask     PG_mask(1, 1)  /* Bits 31 or 63.                 */
+
+ /* 2-bit count of uses of this frame as its current type. */
+#define PGT_count_mask    PG_mask(3, 3)
+
+/* Cleared when the owning guest 'frees' this page. */
+#define _PGC_allocated    PG_shift(1)
+#define PGC_allocated     PG_mask(1, 1)
+/* Page is Xen heap? */
+#define _PGC_xen_heap     PG_shift(2)
+#define PGC_xen_heap      PG_mask(1, 2)
+/* Page is broken? */
+#define _PGC_broken       PG_shift(7)
+#define PGC_broken        PG_mask(1, 7)
+ /* Mutually-exclusive page states: { inuse, offlining, offlined, free }. */
+#define PGC_state         PG_mask(3, 9)
+#define PGC_state_inuse   PG_mask(0, 9)
+#define PGC_state_offlining PG_mask(1, 9)
+#define PGC_state_offlined PG_mask(2, 9)
+#define PGC_state_free    PG_mask(3, 9)
+#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
+/* Page is not reference counted */
+#define _PGC_extra        PG_shift(10)
+#define PGC_extra         PG_mask(1, 10)
+
+/* Count of references to this frame. */
+#define PGC_count_width   PG_shift(10)
+#define PGC_count_mask    ((1UL<<PGC_count_width)-1)
+
+/*
+ * Page needs to be scrubbed. Since this bit can only be set on a page that is
+ * free (i.e. in PGC_state_free) we can reuse PGC_allocated bit.
+ */
+#define _PGC_need_scrub   _PGC_allocated
+#define PGC_need_scrub    PGC_allocated
+
+#define is_xen_heap_page(page) ((page)->count_info & PGC_xen_heap)
+#define is_xen_heap_mfn(mfn) \
+    (mfn_valid(mfn) && is_xen_heap_page(mfn_to_page(mfn)))
+
+#define is_xen_fixed_mfn(mfn)                                   \
+    ((mfn_to_maddr(mfn) >= virt_to_maddr(&_start)) &&           \
+     (mfn_to_maddr(mfn) <= virt_to_maddr((vaddr_t)_end - 1)))
+
+#define page_get_owner(_p)    (_p)->v.inuse.domain
+#define page_set_owner(_p,_d) ((_p)->v.inuse.domain = (_d))
+
+/* TODO: implement */
+#define mfn_valid(mfn) ({ (void) (mfn); 0; })
+
+#define domain_set_alloc_bitsize(d) ((void)(d))
+#define domain_clamp_alloc_bitsize(d, b) (b)
+
+#define PFN_ORDER(pfn_) ((pfn_)->v.free.order)
+
+struct page_info
+{
+    /* Each frame can be threaded onto a doubly-linked list. */
+    struct page_list_entry list;
+
+    /* Reference count and various PGC_xxx flags and fields. */
+    unsigned long count_info;
+
+    /* Context-dependent fields follow... */
+    union {
+        /* Page is in use: ((count_info & PGC_count_mask) != 0). */
+        struct {
+            /* Type reference count and various PGT_xxx flags and fields. */
+            unsigned long type_info;
+        } inuse;
+        /* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
+        union {
+            struct {
+                /*
+                 * Index of the first *possibly* unscrubbed page in the buddy.
+                 * One more bit than maximum possible order to accommodate
+                 * INVALID_DIRTY_IDX.
+                 */
+#define INVALID_DIRTY_IDX ((1UL << (MAX_ORDER + 1)) - 1)
+                unsigned long first_dirty:MAX_ORDER + 1;
+
+                /* Do TLBs need flushing for safety before next page use? */
+                bool need_tlbflush:1;
+
+#define BUDDY_NOT_SCRUBBING    0
+#define BUDDY_SCRUBBING        1
+#define BUDDY_SCRUB_ABORT      2
+                unsigned long scrub_state:2;
+            };
+
+            unsigned long val;
+        } free;
+
+    } u;
+
+    union {
+        /* Page is in use, but not as a shadow. */
+        struct {
+            /* Owner of this page (zero if page is anonymous). */
+            struct domain *domain;
+        } inuse;
+
+        /* Page is on a free list. */
+        struct {
+            /* Order-size of the free chunk this page is the head of. */
+            unsigned int order;
+        } free;
+
+    } v;
+
+    union {
+        /*
+         * Timestamp from 'TLB clock', used to avoid extra safety flushes.
+         * Only valid for: a) free pages, and b) pages with zero type count
+         */
+        u32 tlbflush_timestamp;
+    };
+    u64 pad;
+};
+
+
+#define FRAMETABLE_VIRT_START  (XEN_VIRT_START + GB(32))
+#define frame_table ((struct page_info *)FRAMETABLE_VIRT_START)
+
+/* PDX of the first page in the frame table. */
+extern unsigned long frametable_base_pdx;
+
+/* Convert between machine frame numbers and page-info structures. */
+#define mfn_to_page(mfn)                                            \
+    (frame_table + (mfn_to_pdx(mfn) - frametable_base_pdx))
+#define page_to_mfn(pg)                                             \
+    pdx_to_mfn((unsigned long)((pg) - frame_table) + frametable_base_pdx)
+
+static inline void *page_to_virt(const struct page_info *pg)
+{
+    return mfn_to_virt(mfn_x(page_to_mfn(pg)));
+}
+
+/*
+ * Common code requires get_page_type and put_page_type.
+ * We don't care about typecounts so we just do the minimum to make it
+ * happy.
+ */
+static inline int get_page_type(struct page_info *page, unsigned long type)
+{
+    return 1;
+}
+
+static inline void put_page_type(struct page_info *page)
+{
+    return;
+}
+
+/* TODO */
+static inline bool get_page_nr(struct page_info *page, const struct domain *domain,
+                        unsigned long nr)
+{
+    BUG_ON("unimplemented");
+}
+static inline void put_page_nr(struct page_info *page, unsigned long nr)
+{
+    BUG_ON("unimplemented");
+}
+
+static inline void put_page_and_type(struct page_info *page)
+{
+    put_page_type(page);
+    put_page(page);
+}
+
+/*
+ * PPC does not have an M2P, but common code expects a handful of
+ * M2P-related defines and functions. Provide dummy versions of these.
+ */
+#define INVALID_M2P_ENTRY        (~0UL)
+#define SHARED_M2P_ENTRY         (~0UL - 1UL)
+#define SHARED_M2P(_e)           ((_e) == SHARED_M2P_ENTRY)
+
+#define set_gpfn_from_mfn(mfn, pfn) BUG_ON("unimplemented")
+#define mfn_to_gfn(d, mfn) ({ BUG_ON("unimplemented"); _gfn(0); })
+
+#define PDX_GROUP_SHIFT XEN_PT_SHIFT_LVL_3
+
+static inline unsigned long domain_get_maximum_gpfn(struct domain *d)
+{
+    BUG_ON("unimplemented");
+    return 0;
+}
+
+static inline long arch_memory_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg)
+{
+    BUG_ON("unimplemented");
+    return 0;
+}
+
+static inline unsigned int arch_get_dma_bitsize(void)
+{
+    return 32; /* TODO */
+}
+
+/*
+ * On PPC, all the RAM is currently direct mapped in Xen.
+ * Hence return always true.
+ */
+static inline bool arch_mfns_in_directmap(unsigned long mfn, unsigned long nr)
+{
+    return true;
+}

 #endif /* _ASM_PPC_MM_H */
diff --git a/xen/arch/ppc/include/asm/monitor.h b/xen/arch/ppc/include/asm/monitor.h
new file mode 100644
index 0000000000..e5b0282bf1
--- /dev/null
+++ b/xen/arch/ppc/include/asm/monitor.h
@@ -0,0 +1,43 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Derived from xen/arch/arm/include/asm/monitor.h */
+#ifndef __ASM_PPC_MONITOR_H__
+#define __ASM_PPC_MONITOR_H__
+
+#include <public/domctl.h>
+#include <xen/errno.h>
+
+static inline
+void arch_monitor_allow_userspace(struct domain *d, bool allow_userspace)
+{
+}
+
+static inline
+int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
+{
+    /* No arch-specific monitor ops on PPC. */
+    return -EOPNOTSUPP;
+}
+
+int arch_monitor_domctl_event(struct domain *d,
+                              struct xen_domctl_monitor_op *mop);
+
+static inline
+int arch_monitor_init_domain(struct domain *d)
+{
+    /* No arch-specific domain initialization on PPC. */
+    return 0;
+}
+
+static inline
+void arch_monitor_cleanup_domain(struct domain *d)
+{
+    /* No arch-specific domain cleanup on PPC. */
+}
+
+static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
+{
+    BUG_ON("unimplemented");
+    return 0;
+}
+
+#endif /* __ASM_PPC_MONITOR_H__ */
diff --git a/xen/arch/ppc/include/asm/nospec.h b/xen/arch/ppc/include/asm/nospec.h
new file mode 100644
index 0000000000..b97322e48d
--- /dev/null
+++ b/xen/arch/ppc/include/asm/nospec.h
@@ -0,0 +1,15 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* From arch/arm/include/asm/nospec.h. */
+#ifndef __ASM_PPC_NOSPEC_H__
+#define __ASM_PPC_NOSPEC_H__
+
+static inline bool evaluate_nospec(bool condition)
+{
+    return condition;
+}
+
+static inline void block_speculation(void)
+{
+}
+
+#endif /* __ASM_PPC_NOSPEC_H__ */
diff --git a/xen/arch/ppc/include/asm/numa.h b/xen/arch/ppc/include/asm/numa.h
new file mode 100644
index 0000000000..d857bba2ba
--- /dev/null
+++ b/xen/arch/ppc/include/asm/numa.h
@@ -0,0 +1,26 @@ 
+#ifndef __ASM_PPC_NUMA_H__
+#define __ASM_PPC_NUMA_H__
+
+#include <xen/types.h>
+#include <xen/mm.h>
+
+typedef uint8_t nodeid_t;
+
+/* Fake one node for now. See also node_online_map. */
+#define cpu_to_node(cpu) 0
+#define node_to_cpumask(node)   (cpu_online_map)
+
+/*
+ * TODO: make first_valid_mfn static when NUMA is supported on Arm, this
+ * is required because the dummy helpers are using it.
+ */
+extern mfn_t first_valid_mfn;
+
+/* XXX: implement NUMA support */
+#define node_spanned_pages(nid) (max_page - mfn_x(first_valid_mfn))
+#define node_start_pfn(nid) (mfn_x(first_valid_mfn))
+#define __node_distance(a, b) (20)
+
+#define arch_want_default_dmazone() (false)
+
+#endif /* __ASM_PPC_NUMA_H__ */
diff --git a/xen/arch/ppc/include/asm/p2m.h b/xen/arch/ppc/include/asm/p2m.h
new file mode 100644
index 0000000000..591427bf42
--- /dev/null
+++ b/xen/arch/ppc/include/asm/p2m.h
@@ -0,0 +1,105 @@ 
+#ifndef __ASM_PPC_P2M_H__
+#define __ASM_PPC_P2M_H__
+
+#include <asm/page-bits.h>
+
+#define paddr_bits PADDR_BITS
+
+/*
+ * List of possible type for each page in the p2m entry.
+ * The number of available bit per page in the pte for this purpose is 4 bits.
+ * So it's possible to only have 16 fields. If we run out of value in the
+ * future, it's possible to use higher value for pseudo-type and don't store
+ * them in the p2m entry.
+ */
+typedef enum {
+    p2m_invalid = 0,    /* Nothing mapped here */
+    p2m_ram_rw,         /* Normal read/write guest RAM */
+    p2m_ram_ro,         /* Read-only; writes are silently dropped */
+    p2m_mmio_direct_dev,/* Read/write mapping of genuine Device MMIO area */
+    p2m_mmio_direct_nc, /* Read/write mapping of genuine MMIO area non-cacheable */
+    p2m_mmio_direct_c,  /* Read/write mapping of genuine MMIO area cacheable */
+    p2m_map_foreign_rw, /* Read/write RAM pages from foreign domain */
+    p2m_map_foreign_ro, /* Read-only RAM pages from foreign domain */
+    p2m_grant_map_rw,   /* Read/write grant mapping */
+    p2m_grant_map_ro,   /* Read-only grant mapping */
+    /* The types below are only used to decide the page attribute in the P2M */
+    p2m_iommu_map_rw,   /* Read/write iommu mapping */
+    p2m_iommu_map_ro,   /* Read-only iommu mapping */
+    p2m_max_real_type,  /* Types after this won't be store in the p2m */
+} p2m_type_t;
+
+#include <xen/p2m-common.h>
+
+static inline int get_page_and_type(struct page_info *page,
+                                    struct domain *domain,
+                                    unsigned long type)
+{
+    BUG_ON("unimplemented");
+    return 1;
+}
+
+/* Look up a GFN and take a reference count on the backing page. */
+typedef unsigned int p2m_query_t;
+#define P2M_ALLOC    (1u<<0)   /* Populate PoD and paged-out entries */
+#define P2M_UNSHARE  (1u<<1)   /* Break CoW sharing */
+
+static inline struct page_info *get_page_from_gfn(
+    struct domain *d, unsigned long gfn, p2m_type_t *t, p2m_query_t q)
+{
+    BUG_ON("unimplemented");
+    return NULL;
+}
+
+static inline void memory_type_changed(struct domain *d)
+{
+    BUG_ON("unimplemented");
+}
+
+
+static inline int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
+                                                        unsigned int order)
+{
+    BUG_ON("unimplemented");
+    return 1;
+}
+
+static inline int guest_physmap_add_entry(struct domain *d,
+                            gfn_t gfn,
+                            mfn_t mfn,
+                            unsigned long page_order,
+                            p2m_type_t t)
+{
+    BUG_ON("unimplemented");
+    return 1;
+}
+
+/* Untyped version for RAM only, for compatibility */
+static inline int __must_check
+guest_physmap_add_page(struct domain *d, gfn_t gfn, mfn_t mfn,
+                       unsigned int page_order)
+{
+    return guest_physmap_add_entry(d, gfn, mfn, page_order, p2m_ram_rw);
+}
+
+static inline mfn_t gfn_to_mfn(struct domain *d, gfn_t gfn)
+{
+    BUG_ON("unimplemented");
+    return _mfn(0);
+}
+
+static inline bool arch_acquire_resource_check(struct domain *d)
+{
+    /*
+     * The reference counting of foreign entries in set_foreign_p2m_entry()
+     * is supported on PPC.
+     */
+    return true;
+}
+
+static inline void p2m_altp2m_check(struct vcpu *v, uint16_t idx)
+{
+    /* Not supported on PPC. */
+}
+
+#endif /* __ASM_PPC_P2M_H__ */
diff --git a/xen/arch/ppc/include/asm/page.h b/xen/arch/ppc/include/asm/page.h
index 3c90e8bf19..7ede71e2fc 100644
--- a/xen/arch/ppc/include/asm/page.h
+++ b/xen/arch/ppc/include/asm/page.h
@@ -1,3 +1,4 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef _ASM_PPC_PAGE_H
 #define _ASM_PPC_PAGE_H

@@ -36,6 +37,9 @@ 
 #define PTE_XEN_RO   (PTE_XEN_BASE | PTE_EAA_READ)
 #define PTE_XEN_RX   (PTE_XEN_BASE | PTE_EAA_READ | PTE_EAA_EXECUTE)

+/* TODO */
+#define PAGE_HYPERVISOR 0
+
 /*
  * Radix Tree layout for 64KB pages:
  *
@@ -177,4 +181,18 @@  struct prtb_entry {

 void tlbie_all(void);

+static inline void invalidate_icache(void)
+{
+    BUG_ON("unimplemented");
+}
+
+#define clear_page(page) memset(page, 0, PAGE_SIZE)
+#define copy_page(dp, sp) memcpy(dp, sp, PAGE_SIZE)
+
+/* TODO: Flush the dcache for an entire page. */
+static inline void flush_page_to_ram(unsigned long mfn, bool sync_icache)
+{
+    BUG_ON("unimplemented");
+}
+
 #endif /* _ASM_PPC_PAGE_H */
diff --git a/xen/arch/ppc/include/asm/paging.h b/xen/arch/ppc/include/asm/paging.h
new file mode 100644
index 0000000000..eccacece29
--- /dev/null
+++ b/xen/arch/ppc/include/asm/paging.h
@@ -0,0 +1,7 @@ 
+#ifndef __ASM_PPC_PAGING_H__
+#define __ASM_PPC_PAGING_H__
+
+#define paging_mode_translate(d)              (1)
+#define paging_mode_external(d)               (1)
+
+#endif /* __ASM_PPC_PAGING_H__ */
diff --git a/xen/arch/ppc/include/asm/pci.h b/xen/arch/ppc/include/asm/pci.h
new file mode 100644
index 0000000000..e76c8e5475
--- /dev/null
+++ b/xen/arch/ppc/include/asm/pci.h
@@ -0,0 +1,7 @@ 
+#ifndef __ASM_PPC_PCI_H__
+#define __ASM_PPC_PCI_H__
+
+struct arch_pci_dev {
+};
+
+#endif /* __ASM_PPC_PCI_H__ */
diff --git a/xen/arch/ppc/include/asm/percpu.h b/xen/arch/ppc/include/asm/percpu.h
new file mode 100644
index 0000000000..e7c40c0f03
--- /dev/null
+++ b/xen/arch/ppc/include/asm/percpu.h
@@ -0,0 +1,24 @@ 
+#ifndef __PPC_PERCPU_H__
+#define __PPC_PERCPU_H__
+
+#ifndef __ASSEMBLY__
+
+extern char __per_cpu_start[], __per_cpu_data_end[];
+extern unsigned long __per_cpu_offset[NR_CPUS];
+void percpu_init_areas(void);
+
+#define smp_processor_id() 0 /* TODO: Fix this */
+
+#define per_cpu(var, cpu)  \
+    (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
+#define this_cpu(var) \
+    (*RELOC_HIDE(&per_cpu__##var, smp_processor_id()))
+
+#define per_cpu_ptr(var, cpu)  \
+    (*RELOC_HIDE(var, __per_cpu_offset[cpu]))
+#define this_cpu_ptr(var) \
+    (*RELOC_HIDE(var, smp_processor_id()))
+
+#endif
+
+#endif /* __PPC_PERCPU_H__ */
diff --git a/xen/arch/ppc/include/asm/processor.h b/xen/arch/ppc/include/asm/processor.h
index 6b70569eb8..0e651d0aa9 100644
--- a/xen/arch/ppc/include/asm/processor.h
+++ b/xen/arch/ppc/include/asm/processor.h
@@ -110,6 +110,10 @@ 
 /* Macro to adjust thread priority for hardware multithreading */
 #define HMT_very_low()  asm volatile ( "or %r31, %r31, %r31" )

+/* TODO: This isn't correct */
+#define cpu_to_core(cpu)   (0)
+#define cpu_to_socket(cpu) (0)
+
 /*
  * User-accessible registers: most of these need to be saved/restored
  * for every nested Xen invocation.
@@ -178,6 +182,12 @@  static inline void noreturn die(void)
         HMT_very_low();
 }

+/*
+ * Implemented on pre-POWER10 by setting HMT to low then to medium using
+ * the special OR forms. See HMT_very_low above.
+ */
+#define cpu_relax() asm volatile ( "or %r1, %r1, %r1; or %r2, %r2, %r2" )
+
 #endif /* __ASSEMBLY__ */

 #endif /* _ASM_PPC_PROCESSOR_H */
diff --git a/xen/arch/ppc/include/asm/random.h b/xen/arch/ppc/include/asm/random.h
new file mode 100644
index 0000000000..2f9e9bbae4
--- /dev/null
+++ b/xen/arch/ppc/include/asm/random.h
@@ -0,0 +1,9 @@ 
+#ifndef __ASM_PPC_RANDOM_H__
+#define __ASM_PPC_RANDOM_H__
+
+static inline unsigned int arch_get_random(void)
+{
+    return 0;
+}
+
+#endif /* __ASM_PPC_RANDOM_H__ */
diff --git a/xen/arch/ppc/include/asm/setup.h b/xen/arch/ppc/include/asm/setup.h
new file mode 100644
index 0000000000..e4f64879b6
--- /dev/null
+++ b/xen/arch/ppc/include/asm/setup.h
@@ -0,0 +1,6 @@ 
+#ifndef __ASM_PPC_SETUP_H__
+#define __ASM_PPC_SETUP_H__
+
+#define max_init_domid (0)
+
+#endif /* __ASM_PPC_SETUP_H__ */
diff --git a/xen/arch/ppc/include/asm/smp.h b/xen/arch/ppc/include/asm/smp.h
new file mode 100644
index 0000000000..eca43f0e6c
--- /dev/null
+++ b/xen/arch/ppc/include/asm/smp.h
@@ -0,0 +1,18 @@ 
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+#include <xen/cpumask.h>
+#include <xen/percpu.h>
+
+DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_mask);
+DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
+
+#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
+
+/*
+ * Do we, for platform reasons, need to actually keep CPUs online when we
+ * would otherwise prefer them to be off?
+ */
+#define park_offline_cpus false
+
+#endif
diff --git a/xen/arch/ppc/include/asm/softirq.h b/xen/arch/ppc/include/asm/softirq.h
new file mode 100644
index 0000000000..a0b28a5e51
--- /dev/null
+++ b/xen/arch/ppc/include/asm/softirq.h
@@ -0,0 +1,8 @@ 
+#ifndef __ASM_PPC_SOFTIRQ_H__
+#define __ASM_PPC_SOFTIRQ_H__
+
+#define NR_ARCH_SOFTIRQS 0
+
+#define arch_skip_send_event_check(cpu) 0
+
+#endif /* __ASM_PPC_SOFTIRQ_H__ */
diff --git a/xen/arch/ppc/include/asm/spinlock.h b/xen/arch/ppc/include/asm/spinlock.h
new file mode 100644
index 0000000000..4bdb4b1e98
--- /dev/null
+++ b/xen/arch/ppc/include/asm/spinlock.h
@@ -0,0 +1,15 @@ 
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#define arch_lock_acquire_barrier() smp_mb()
+#define arch_lock_release_barrier() smp_mb()
+
+#define arch_lock_relax() cpu_relax()
+#define arch_lock_signal()
+#define arch_lock_signal_wmb()      \
+({                                  \
+    smp_wmb();                      \
+    arch_lock_signal();             \
+})
+
+#endif /* __ASM_SPINLOCK_H */
diff --git a/xen/arch/ppc/include/asm/system.h b/xen/arch/ppc/include/asm/system.h
index 94091df644..e13ce27598 100644
--- a/xen/arch/ppc/include/asm/system.h
+++ b/xen/arch/ppc/include/asm/system.h
@@ -1,6 +1,228 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) IBM Corp. 2005
+ * Copyright (C) Raptor Engineering LLC
+ *
+ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
+ *          Shawn Anastasio <sanastasio@raptorengineering.com>
+ */
+
 #ifndef _ASM_SYSTEM_H_
 #define _ASM_SYSTEM_H_

-#define smp_wmb() __asm__ __volatile__ ( "lwsync" : : : "memory" )
+#include <xen/lib.h>
+#include <asm/memory.h>
+#include <asm/time.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+
+#define xchg(ptr,x) 							                               \
+({									                                           \
+	__typeof__(*(ptr)) _x_ = (x);					                           \
+	(__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr)));    \
+})
+
+#define build_xchg(fn, type, ldinsn, stinsn) \
+static inline unsigned long fn(volatile type *m, unsigned long val)            \
+{                                                                              \
+    unsigned long dummy;                                                       \
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER                                    \
+                   "1: " ldinsn " %0,0,%3\n"                                   \
+                   stinsn " %2,0,%3\n"                                         \
+                   "2:  bne- 1b"                                               \
+                   PPC_ATOMIC_EXIT_BARRIER                                     \
+                   : "=&r" (dummy), "=m" (*m)                                  \
+                   : "r" (val), "r" (m)                                        \
+                   : "cc", "memory" );                                         \
+    return dummy;                                                              \
+}
+
+build_xchg(__xchg_u8, uint8_t, "lbarx", "stbcx.")
+build_xchg(__xchg_u16, uint16_t, "lharx", "sthcx.")
+build_xchg(__xchg_u32, uint32_t, "lwarx", "stwcx.")
+build_xchg(__xchg_u64, uint64_t, "ldarx", "stdcx.")
+
+#undef build_xchg
+
+/*
+ * This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid xchg().
+ */
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
+                                   int size)
+{
+    switch (size) {
+    case 1:
+        return __xchg_u8(ptr, x);
+    case 2:
+        return __xchg_u16(ptr, x);
+    case 4:
+        return __xchg_u32(ptr, x);
+    case 8:
+        return __xchg_u64(ptr, x);
+    }
+    __xchg_called_with_bad_pointer();
+    return x;
+}
+
+
+static inline unsigned long __cmpxchg_u32(volatile int *p, int old, int new)
+{
+    unsigned int prev;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: lwarx   %0,0,%2\n"
+                   "cmpw    0,%0,%3\n"
+                   "bne-    2f\n "
+                   "stwcx.  %4,0,%2\n"
+                   "bne-    1b\n"
+                   PPC_ATOMIC_EXIT_BARRIER "\n"
+                   "2:"
+                   : "=&r" (prev), "=m" (*p)
+                   : "r" (p), "r" (old), "r" (new), "m" (*p)
+                   : "cc", "memory" );
+
+    return prev;
+}
+
+static inline unsigned long __cmpxchg_u64(volatile long *p, unsigned long old,
+                                          unsigned long new)
+{
+    unsigned long prev;
+
+    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
+                   "1: ldarx   %0,0,%2\n"
+                   "cmpd    0,%0,%3\n"
+                   "bne-    2f\n"
+                   "stdcx.  %4,0,%2\n"
+                   "bne-    1b"
+                   PPC_ATOMIC_EXIT_BARRIER "\n"
+                   "2:"
+                   : "=&r" (prev), "=m" (*p)
+                   : "r" (p), "r" (old), "r" (new), "m" (*p)
+                   : "cc", "memory" );
+
+    return prev;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static always_inline unsigned long __cmpxchg(
+    volatile void *ptr,
+    unsigned long old,
+    unsigned long new,
+    int size)
+{
+    switch (size) {
+    case 2:
+        BUG_ON("unimplemented"); return 0; /* XXX implement __cmpxchg_u16 ? */
+    case 4:
+        return __cmpxchg_u32(ptr, old, new);
+    case 8:
+        return __cmpxchg_u64(ptr, old, new);
+    }
+    __cmpxchg_called_with_bad_pointer();
+    return old;
+}
+
+#define cmpxchg_user(ptr,o,n) cmpxchg(ptr,o,n)
+
+#define cmpxchg(ptr,o,n)                         \
+  ({                                     \
+     __typeof__(*(ptr)) _o_ = (o);                   \
+     __typeof__(*(ptr)) _n_ = (n);                   \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,       \
+                    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+
+/*
+ * Memory barrier.
+ * The sync instruction guarantees that all memory accesses initiated
+ * by this processor have been performed (with respect to all other
+ * mechanisms that access memory).  The eieio instruction is a barrier
+ * providing an ordering (separately) for (a) cacheable stores and (b)
+ * loads and stores to non-cacheable memory (e.g. I/O devices).
+ *
+ * mb() prevents loads and stores being reordered across this point.
+ * rmb() prevents loads being reordered across this point.
+ * wmb() prevents stores being reordered across this point.
+ * read_barrier_depends() prevents data-dependent loads being reordered
+ *  across this point (nop on PPC).
+ *
+ * We have to use the sync instructions for mb(), since lwsync doesn't
+ * order loads with respect to previous stores.  Lwsync is fine for
+ * rmb(), though.
+ * For wmb(), we use sync since wmb is used in drivers to order
+ * stores to system memory with respect to writes to the device.
+ * However, smp_wmb() can be a lighter-weight eieio barrier on
+ * SMP since it is only used to order updates to system memory.
+ */
+#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
+#define rmb()  __asm__ __volatile__ ("lwsync" : : : "memory")
+#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define read_barrier_depends()  do { } while(0)
+
+#define set_mb(var, value)  do { var = value; smp_mb(); } while (0)
+#define set_wmb(var, value) do { var = value; smp_wmb(); } while (0)
+
+#define smp_mb__before_atomic()    smp_mb()
+#define smp_mb__after_atomic()     smp_mb()
+
+#ifdef CONFIG_SMP
+#define smp_mb()    mb()
+#define smp_rmb()   rmb()
+#define smp_wmb()   __asm__ __volatile__ ("lwsync" : : : "memory")
+#define smp_read_barrier_depends()  read_barrier_depends()
+#else
+#define smp_mb()    __asm__ __volatile__("": : :"memory")
+#define smp_rmb()   __asm__ __volatile__("": : :"memory")
+#define smp_wmb()   __asm__ __volatile__("": : :"memory")
+#define smp_read_barrier_depends()  do { } while(0)
+#endif /* CONFIG_SMP */
+
+#define local_save_flags(flags) ((flags) = mfmsr())
+#define local_irq_restore(flags) do { \
+        __asm__ __volatile__("": : :"memory"); \
+        mtmsrd((flags)); \
+} while(0)
+
+static inline void local_irq_disable(void)
+{
+    unsigned long msr;
+    msr = mfmsr();
+    mtmsrd(msr & ~MSR_EE);
+    asm volatile ( "" : : : "memory" );
+}
+
+static inline void local_irq_enable(void)
+{
+    unsigned long msr;
+    __asm__ __volatile__("" : : : "memory");
+    msr = mfmsr();
+    mtmsrd(msr | MSR_EE);
+}
+
+static inline void __do_save_and_cli(unsigned long *flags)
+{
+    unsigned long msr;
+    msr = mfmsr();
+    *flags = msr;
+    mtmsrd(msr & ~MSR_EE);
+    __asm__ __volatile__("" : : : "memory");
+}
+
+#define local_irq_save(flags) __do_save_and_cli(&flags)
+
+static inline int local_irq_is_enabled(void)
+{
+    return !!(mfmsr() & MSR_EE);
+}
+
+#define arch_fetch_and_add(x, v) __sync_fetch_and_add(x, v)

 #endif /* _ASM_SYSTEM_H */
diff --git a/xen/arch/ppc/include/asm/time.h b/xen/arch/ppc/include/asm/time.h
new file mode 100644
index 0000000000..d47a6f9245
--- /dev/null
+++ b/xen/arch/ppc/include/asm/time.h
@@ -0,0 +1,21 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_TIME_H__
+#define __ASM_PPC_TIME_H__
+
+#include <xen/lib.h>
+#include <asm/processor.h>
+#include <asm/regs.h>
+
+struct vcpu;
+
+/* TODO: implement */
+static inline void force_update_vcpu_system_time(struct vcpu *v) { BUG_ON("unimplemented"); }
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+    return mfspr(SPRN_TBRL);
+}
+
+#endif /* __ASM_PPC_TIME_H__ */
diff --git a/xen/arch/ppc/include/asm/vm_event.h b/xen/arch/ppc/include/asm/vm_event.h
new file mode 100644
index 0000000000..75eba6346d
--- /dev/null
+++ b/xen/arch/ppc/include/asm/vm_event.h
@@ -0,0 +1,49 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_PPC_VM_EVENT_H__
+#define __ASM_PPC_VM_EVENT_H__
+
+#include <xen/sched.h>
+#include <public/vm_event.h>
+
+static inline int vm_event_init_domain(struct domain *d)
+{
+    /* Nothing to do. */
+    return 0;
+}
+
+static inline void vm_event_cleanup_domain(struct domain *d)
+{
+    memset(&d->monitor, 0, sizeof(d->monitor));
+}
+
+static inline void vm_event_toggle_singlestep(struct domain *d, struct vcpu *v,
+                                              vm_event_response_t *rsp)
+{
+    /* Not supported on PPC. */
+}
+
+static inline
+void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
+{
+    /* Not supported on PPC. */
+}
+
+static inline
+void vm_event_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
+{
+    /* Not supported on PPC. */
+}
+
+static inline
+void vm_event_sync_event(struct vcpu *v, bool value)
+{
+    /* Not supported on PPC. */
+}
+
+static inline
+void vm_event_reset_vmtrace(struct vcpu *v)
+{
+    /* Not supported on PPC. */
+}
+
+#endif /* __ASM_PPC_VM_EVENT_H__ */
diff --git a/xen/arch/ppc/include/asm/xenoprof.h b/xen/arch/ppc/include/asm/xenoprof.h
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xen/arch/ppc/mm-radix.c b/xen/arch/ppc/mm-radix.c
index 3feeb90ebc..06129cef9c 100644
--- a/xen/arch/ppc/mm-radix.c
+++ b/xen/arch/ppc/mm-radix.c
@@ -1,13 +1,13 @@ 
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 #include <xen/init.h>
 #include <xen/kernel.h>
+#include <xen/mm.h>
 #include <xen/types.h>
 #include <xen/lib.h>

 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/early_printk.h>
-#include <asm/mm.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/regs.h>
diff --git a/xen/arch/ppc/tlb-radix.c b/xen/arch/ppc/tlb-radix.c
index 3dde102c62..74213113e0 100644
--- a/xen/arch/ppc/tlb-radix.c
+++ b/xen/arch/ppc/tlb-radix.c
@@ -5,9 +5,9 @@ 
  *
  * Copyright 2015-2016, Aneesh Kumar K.V, IBM Corporation.
  */
+#include <xen/bitops.h>
 #include <xen/stringify.h>

-#include <asm/bitops.h>
 #include <asm/msr.h>
 #include <asm/processor.h>

diff --git a/xen/include/public/hvm/save.h b/xen/include/public/hvm/save.h
index 464ebdb0da..2cf4238daa 100644
--- a/xen/include/public/hvm/save.h
+++ b/xen/include/public/hvm/save.h
@@ -89,6 +89,8 @@  DECLARE_HVM_SAVE_TYPE(END, 0, struct hvm_save_end);
 #include "../arch-x86/hvm/save.h"
 #elif defined(__arm__) || defined(__aarch64__)
 #include "../arch-arm/hvm/save.h"
+#elif defined(__powerpc64__)
+#include "../arch-ppc.h"
 #else
 #error "unsupported architecture"
 #endif
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index eb87a81e7b..5a176b6ac3 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -11,6 +11,8 @@ 
 #include "arch-x86/pmu.h"
 #elif defined (__arm__) || defined (__aarch64__)
 #include "arch-arm.h"
+#elif defined (__powerpc64__)
+#include "arch-ppc.h"
 #else
 #error "Unsupported architecture"
 #endif
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 920567e006..b812a0a324 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -16,6 +16,8 @@ 
 #include "arch-x86/xen.h"
 #elif defined(__arm__) || defined (__aarch64__)
 #include "arch-arm.h"
+#elif defined(__powerpc64__)
+#include "arch-ppc.h"
 #else
 #error "Unsupported architecture"
 #endif