uboot/drivers/xen/hypervisor.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT License
   2/*
   3 * hypervisor.c
   4 *
   5 * Communication to/from hypervisor.
   6 *
   7 * Copyright (c) 2002-2003, K A Fraser
   8 * Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge
   9 * Copyright (c) 2020, EPAM Systems Inc.
  10 */
  11#include <common.h>
  12#include <cpu_func.h>
  13#include <log.h>
  14#include <memalign.h>
  15
  16#include <asm/io.h>
  17#include <asm/armv8/mmu.h>
  18#include <asm/xen/system.h>
  19
  20#include <linux/bug.h>
  21
  22#include <xen/hvm.h>
  23#include <xen/events.h>
  24#include <xen/gnttab.h>
  25#include <xen/xenbus.h>
  26#include <xen/interface/memory.h>
  27
  28#define active_evtchns(cpu, sh, idx)    \
  29        ((sh)->evtchn_pending[idx] &    \
  30         ~(sh)->evtchn_mask[idx])
  31
  32int in_callback;
  33
  34/*
  35 * Shared page for communicating with the hypervisor.
  36 * Events flags go here, for example.
  37 */
  38struct shared_info *HYPERVISOR_shared_info;
  39
  40static const char *param_name(int op)
  41{
  42#define PARAM(x)[HVM_PARAM_##x] = #x
  43        static const char *const names[] = {
  44                PARAM(CALLBACK_IRQ),
  45                PARAM(STORE_PFN),
  46                PARAM(STORE_EVTCHN),
  47                PARAM(PAE_ENABLED),
  48                PARAM(IOREQ_PFN),
  49                PARAM(VPT_ALIGN),
  50                PARAM(CONSOLE_PFN),
  51                PARAM(CONSOLE_EVTCHN),
  52        };
  53#undef PARAM
  54
  55        if (op >= ARRAY_SIZE(names))
  56                return "unknown";
  57
  58        if (!names[op])
  59                return "reserved";
  60
  61        return names[op];
  62}
  63
  64/**
  65 * hvm_get_parameter_maintain_dcache - function to obtain a HVM
  66 * parameter value.
  67 * @idx: HVM parameter index
  68 * @value: Value to fill in
  69 *
  70 * According to Xen on ARM ABI (xen/include/public/arch-arm.h):
  71 * all memory which is shared with other entities in the system
  72 * (including the hypervisor and other guests) must reside in memory
  73 * which is mapped as Normal Inner Write-Back Outer Write-Back
  74 * Inner-Shareable.
  75 *
  76 * Thus, page attributes must be equally set for all the entities
  77 * working with that page.
  78 *
  79 * Before MMU setup the data cache is turned off, so it means that
  80 * manual data cache maintenance is required, because of the
  81 * difference of page attributes.
  82 */
  83int hvm_get_parameter_maintain_dcache(int idx, uint64_t *value)
  84{
  85        struct xen_hvm_param xhv;
  86        int ret;
  87
  88        invalidate_dcache_range((unsigned long)&xhv,
  89                                (unsigned long)&xhv + sizeof(xhv));
  90        xhv.domid = DOMID_SELF;
  91        xhv.index = idx;
  92        invalidate_dcache_range((unsigned long)&xhv,
  93                                (unsigned long)&xhv + sizeof(xhv));
  94
  95        ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
  96        if (ret < 0) {
  97                pr_err("Cannot get hvm parameter %s (%d): %d!\n",
  98                           param_name(idx), idx, ret);
  99                BUG();
 100        }
 101        invalidate_dcache_range((unsigned long)&xhv,
 102                                (unsigned long)&xhv + sizeof(xhv));
 103
 104        *value = xhv.value;
 105
 106        return ret;
 107}
 108
 109int hvm_get_parameter(int idx, uint64_t *value)
 110{
 111        struct xen_hvm_param xhv;
 112        int ret;
 113
 114        xhv.domid = DOMID_SELF;
 115        xhv.index = idx;
 116        ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
 117        if (ret < 0) {
 118                pr_err("Cannot get hvm parameter %s (%d): %d!\n",
 119                           param_name(idx), idx, ret);
 120                BUG();
 121        }
 122
 123        *value = xhv.value;
 124
 125        return ret;
 126}
 127
 128struct shared_info *map_shared_info(void *p)
 129{
 130        struct xen_add_to_physmap xatp;
 131
 132        HYPERVISOR_shared_info = (struct shared_info *)memalign(PAGE_SIZE,
 133                                                                PAGE_SIZE);
 134        if (!HYPERVISOR_shared_info)
 135                BUG();
 136
 137        xatp.domid = DOMID_SELF;
 138        xatp.idx = 0;
 139        xatp.space = XENMAPSPACE_shared_info;
 140        xatp.gpfn = virt_to_pfn(HYPERVISOR_shared_info);
 141        if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
 142                BUG();
 143
 144        return HYPERVISOR_shared_info;
 145}
 146
 147void do_hypervisor_callback(struct pt_regs *regs)
 148{
 149        unsigned long l1, l2, l1i, l2i;
 150        unsigned int port;
 151        int cpu = 0;
 152        struct shared_info *s = HYPERVISOR_shared_info;
 153        struct vcpu_info *vcpu_info = &s->vcpu_info[cpu];
 154
 155        in_callback = 1;
 156
 157        vcpu_info->evtchn_upcall_pending = 0;
 158        l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
 159
 160        while (l1 != 0) {
 161                l1i = __ffs(l1);
 162                l1 &= ~(1UL << l1i);
 163
 164                while ((l2 = active_evtchns(cpu, s, l1i)) != 0) {
 165                        l2i = __ffs(l2);
 166                        l2 &= ~(1UL << l2i);
 167
 168                        port = (l1i * (sizeof(unsigned long) * 8)) + l2i;
 169                        do_event(port, regs);
 170                }
 171        }
 172
 173        in_callback = 0;
 174}
 175
 176void force_evtchn_callback(void)
 177{
 178#ifdef XEN_HAVE_PV_UPCALL_MASK
 179        int save;
 180#endif
 181        struct vcpu_info *vcpu;
 182
 183        vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
 184#ifdef XEN_HAVE_PV_UPCALL_MASK
 185        save = vcpu->evtchn_upcall_mask;
 186#endif
 187
 188        while (vcpu->evtchn_upcall_pending) {
 189#ifdef XEN_HAVE_PV_UPCALL_MASK
 190                vcpu->evtchn_upcall_mask = 1;
 191#endif
 192                do_hypervisor_callback(NULL);
 193#ifdef XEN_HAVE_PV_UPCALL_MASK
 194                vcpu->evtchn_upcall_mask = save;
 195#endif
 196        };
 197}
 198
 199void mask_evtchn(uint32_t port)
 200{
 201        struct shared_info *s = HYPERVISOR_shared_info;
 202
 203        synch_set_bit(port, &s->evtchn_mask[0]);
 204}
 205
 206void unmask_evtchn(uint32_t port)
 207{
 208        struct shared_info *s = HYPERVISOR_shared_info;
 209        struct vcpu_info *vcpu_info = &s->vcpu_info[smp_processor_id()];
 210
 211        synch_clear_bit(port, &s->evtchn_mask[0]);
 212
 213        /*
 214         * Just like a real IO-APIC we 'lose the interrupt edge' if the
 215         * channel is masked.
 216         */
 217        if (synch_test_bit(port, &s->evtchn_pending[0]) &&
 218            !synch_test_and_set_bit(port / (sizeof(unsigned long) * 8),
 219                                    &vcpu_info->evtchn_pending_sel)) {
 220                vcpu_info->evtchn_upcall_pending = 1;
 221#ifdef XEN_HAVE_PV_UPCALL_MASK
 222                if (!vcpu_info->evtchn_upcall_mask)
 223#endif
 224                        force_evtchn_callback();
 225        }
 226}
 227
 228void clear_evtchn(uint32_t port)
 229{
 230        struct shared_info *s = HYPERVISOR_shared_info;
 231
 232        synch_clear_bit(port, &s->evtchn_pending[0]);
 233}
 234
 235int xen_init(void)
 236{
 237        debug("%s\n", __func__);
 238
 239        map_shared_info(NULL);
 240        init_events();
 241        init_xenbus();
 242        init_gnttab();
 243
 244        return 0;
 245}
 246
 247void xen_fini(void)
 248{
 249        debug("%s\n", __func__);
 250
 251        fini_gnttab();
 252        fini_xenbus();
 253        fini_events();
 254}
 255