Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/xen/enlighten_pvh.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/acpi.h>
3
#include <linux/cpufreq.h>
4
#include <linux/cpuidle.h>
5
#include <linux/export.h>
6
#include <linux/mm.h>
7
8
#include <xen/hvc-console.h>
9
#include <xen/acpi.h>
10
11
#include <asm/bootparam.h>
12
#include <asm/io_apic.h>
13
#include <asm/hypervisor.h>
14
#include <asm/e820/api.h>
15
#include <asm/setup.h>
16
17
#include <xen/xen.h>
18
#include <asm/xen/interface.h>
19
#include <asm/xen/hypercall.h>
20
21
#include <xen/interface/memory.h>
22
23
#include "xen-ops.h"
24
25
/*
26
* PVH variables.
27
*
28
* The variable xen_pvh needs to live in a data segment since it is used
29
* after startup_{32|64} is invoked, which will clear the .bss segment.
30
*/
31
bool __ro_after_init xen_pvh;
32
EXPORT_SYMBOL_GPL(xen_pvh);
33
34
#ifdef CONFIG_XEN_DOM0
35
int xen_pvh_setup_gsi(int gsi, int trigger, int polarity)
36
{
37
int ret;
38
struct physdev_setup_gsi setup_gsi;
39
40
setup_gsi.gsi = gsi;
41
setup_gsi.triggering = (trigger == ACPI_EDGE_SENSITIVE ? 0 : 1);
42
setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
43
44
ret = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
45
if (ret == -EEXIST) {
46
xen_raw_printk("Already setup the GSI :%d\n", gsi);
47
ret = 0;
48
} else if (ret)
49
xen_raw_printk("Fail to setup GSI (%d)!\n", gsi);
50
51
return ret;
52
}
53
EXPORT_SYMBOL_GPL(xen_pvh_setup_gsi);
54
#endif
55
56
/*
57
* Reserve e820 UNUSABLE regions to inflate the memory balloon.
58
*
59
* On PVH dom0 the host memory map is used, RAM regions available to dom0 are
60
* located as the same place as in the native memory map, but since dom0 gets
61
* less memory than the total amount of host RAM the ranges that can't be
62
* populated are converted from RAM -> UNUSABLE. Use such regions (up to the
63
* ratio signaled in EXTRA_MEM_RATIO) in order to inflate the balloon driver at
64
* boot. Doing so prevents the guest (even if just temporary) from using holes
65
* in the memory map in order to map grants or foreign addresses, and
66
* hopefully limits the risk of a clash with a device MMIO region. Ideally the
67
* hypervisor should notify us which memory ranges are suitable for creating
68
* foreign mappings, but that's not yet implemented.
69
*/
70
static void __init pvh_reserve_extra_memory(void)
71
{
72
struct boot_params *bootp = &boot_params;
73
unsigned int i, ram_pages = 0, extra_pages;
74
75
for (i = 0; i < bootp->e820_entries; i++) {
76
struct boot_e820_entry *e = &bootp->e820_table[i];
77
78
if (e->type != E820_TYPE_RAM)
79
continue;
80
ram_pages += PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr);
81
}
82
83
/* Max amount of extra memory. */
84
extra_pages = EXTRA_MEM_RATIO * ram_pages;
85
86
/*
87
* Convert UNUSABLE ranges to RAM and reserve them for foreign mapping
88
* purposes.
89
*/
90
for (i = 0; i < bootp->e820_entries && extra_pages; i++) {
91
struct boot_e820_entry *e = &bootp->e820_table[i];
92
unsigned long pages;
93
94
if (e->type != E820_TYPE_UNUSABLE)
95
continue;
96
97
pages = min(extra_pages,
98
PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr));
99
100
if (pages != (PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr))) {
101
struct boot_e820_entry *next;
102
103
if (bootp->e820_entries ==
104
ARRAY_SIZE(bootp->e820_table))
105
/* No space left to split - skip region. */
106
continue;
107
108
/* Split entry. */
109
next = e + 1;
110
memmove(next, e,
111
(bootp->e820_entries - i) * sizeof(*e));
112
bootp->e820_entries++;
113
next->addr = PAGE_ALIGN(e->addr) + PFN_PHYS(pages);
114
e->size = next->addr - e->addr;
115
next->size -= e->size;
116
}
117
e->type = E820_TYPE_RAM;
118
extra_pages -= pages;
119
120
xen_add_extra_mem(PFN_UP(e->addr), pages);
121
}
122
}
123
124
static void __init pvh_arch_setup(void)
125
{
126
pvh_reserve_extra_memory();
127
128
if (xen_initial_domain()) {
129
xen_add_preferred_consoles();
130
131
/*
132
* Disable usage of CPU idle and frequency drivers: when
133
* running as hardware domain the exposed native ACPI tables
134
* causes idle and/or frequency drivers to attach and
135
* malfunction. It's Xen the entity that controls the idle and
136
* frequency states.
137
*
138
* For unprivileged domains the exposed ACPI tables are
139
* fabricated and don't contain such data.
140
*/
141
disable_cpuidle();
142
disable_cpufreq();
143
WARN_ON(xen_set_default_idle());
144
}
145
}
146
147
void __init xen_pvh_init(struct boot_params *boot_params)
148
{
149
xen_pvh = 1;
150
xen_domain_type = XEN_HVM_DOMAIN;
151
xen_start_flags = pvh_start_info.flags;
152
153
x86_init.oem.arch_setup = pvh_arch_setup;
154
x86_init.oem.banner = xen_banner;
155
156
xen_efi_init(boot_params);
157
158
if (xen_initial_domain()) {
159
struct xen_platform_op op = {
160
.cmd = XENPF_get_dom0_console,
161
};
162
int ret = HYPERVISOR_platform_op(&op);
163
164
if (ret > 0)
165
xen_init_vga(&op.u.dom0_console,
166
min(ret * sizeof(char),
167
sizeof(op.u.dom0_console)),
168
&boot_params->screen_info);
169
}
170
}
171
172
void __init mem_map_via_hcall(struct boot_params *boot_params_p)
173
{
174
struct xen_memory_map memmap;
175
int rc;
176
177
memmap.nr_entries = ARRAY_SIZE(boot_params_p->e820_table);
178
set_xen_guest_handle(memmap.buffer, boot_params_p->e820_table);
179
rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
180
if (rc) {
181
xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
182
BUG();
183
}
184
boot_params_p->e820_entries = memmap.nr_entries;
185
}
186
187