Skip to content

Commit 5f7d861

Browse files
vaibhav92npiggin
authored andcommitted
spapr: nested: Add support for reporting Hostwide state counter
Add support for reporting Hostwide state counters for nested KVM pseries guests running with 'cap-nested-papr' on Qemu-TCG acting as L0-hypervisor. The Hostwide state counters are statistics about state that L0-hypervisor maintains for the L2-guests and represent the state of all L2-guests, not just a specific one. These stats counters are exposed to L1-Hypervisor by the L0-Hypervisor via a new bit-flag named 'getHostWideState' for the H_GUEST_GET_STATE hcall which is documented at [1]. Once this flag is set the hcall should populate the Guest-State-Elements in the requested GSB with the stat counter values. Currently following five counters are supported: * l0_guest_heap_size_inuse * l0_guest_heap_size_max * l0_guest_pagetable_size_inuse * l0_guest_pagetable_size_max * l0_guest_pagetable_reclaimed At the moment '0' is being reported for all these counters as these counters doesn't align with how L0-Qemu manages Guest memory. The patch implements support for these counters by adding new members to the 'struct SpaprMachineStateNested'. These new members are then plugged into the existing 'guest_state_element_types[]' with the help of a new macro 'GSBE_NESTED_MACHINE_DW' together with a new helper 'get_machine_ptr()'. guest_state_request_check() is updated to ensure correctness of the requested GSB and finally h_guest_getset_state() is updated to handle the newly introduced flag 'GUEST_STATE_REQUEST_HOST_WIDE'. This patch is tested with the proposed linux-kernel implementation to expose these stat-counter as perf-events at [2]. [1] https://lore.kernel.org/all/[email protected] [2] https://lore.kernel.org/all/[email protected] Signed-off-by: Vaibhav Jain <[email protected]> Reviewed-by: Harsh Prateek Bora <[email protected]> Message-ID: <[email protected]> Signed-off-by: Nicholas Piggin <[email protected]>
1 parent 5f361ea commit 5f7d861

File tree

2 files changed

+147
-39
lines changed

2 files changed

+147
-39
lines changed

hw/ppc/spapr_nested.c

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,9 @@ static
6565
SpaprMachineStateNestedGuest *spapr_get_nested_guest(SpaprMachineState *spapr,
6666
target_ulong guestid)
6767
{
68-
SpaprMachineStateNestedGuest *guest;
69-
70-
guest = g_hash_table_lookup(spapr->nested.guests, GINT_TO_POINTER(guestid));
71-
return guest;
68+
return spapr->nested.guests ?
69+
g_hash_table_lookup(spapr->nested.guests,
70+
GINT_TO_POINTER(guestid)) : NULL;
7271
}
7372

7473
bool spapr_get_pate_nested_papr(SpaprMachineState *spapr, PowerPCCPU *cpu,
@@ -594,26 +593,37 @@ static bool spapr_nested_vcpu_check(SpaprMachineStateNestedGuest *guest,
594593
return false;
595594
}
596595

597-
static void *get_vcpu_state_ptr(SpaprMachineStateNestedGuest *guest,
598-
target_ulong vcpuid)
596+
static void *get_vcpu_state_ptr(SpaprMachineState *spapr,
597+
SpaprMachineStateNestedGuest *guest,
598+
target_ulong vcpuid)
599599
{
600600
assert(spapr_nested_vcpu_check(guest, vcpuid, false));
601601
return &guest->vcpus[vcpuid].state;
602602
}
603603

604-
static void *get_vcpu_ptr(SpaprMachineStateNestedGuest *guest,
605-
target_ulong vcpuid)
604+
static void *get_vcpu_ptr(SpaprMachineState *spapr,
605+
SpaprMachineStateNestedGuest *guest,
606+
target_ulong vcpuid)
606607
{
607608
assert(spapr_nested_vcpu_check(guest, vcpuid, false));
608609
return &guest->vcpus[vcpuid];
609610
}
610611

611-
static void *get_guest_ptr(SpaprMachineStateNestedGuest *guest,
612+
static void *get_guest_ptr(SpaprMachineState *spapr,
613+
SpaprMachineStateNestedGuest *guest,
612614
target_ulong vcpuid)
613615
{
614616
return guest; /* for GSBE_NESTED */
615617
}
616618

619+
static void *get_machine_ptr(SpaprMachineState *spapr,
620+
SpaprMachineStateNestedGuest *guest,
621+
target_ulong vcpuid)
622+
{
623+
/* ignore guest and vcpuid for this */
624+
return &spapr->nested;
625+
}
626+
617627
/*
618628
* set=1 means the L1 is trying to set some state
619629
* set=0 means the L1 is trying to get some state
@@ -1013,7 +1023,15 @@ struct guest_state_element_type guest_state_element_types[] = {
10131023
GSBE_NESTED_VCPU(GSB_VCPU_OUT_BUFFER, 0x10, runbufout, copy_state_runbuf),
10141024
GSBE_NESTED_VCPU(GSB_VCPU_OUT_BUF_MIN_SZ, 0x8, runbufout, out_buf_min_size),
10151025
GSBE_NESTED_VCPU(GSB_VCPU_HDEC_EXPIRY_TB, 0x8, hdecr_expiry_tb,
1016-
copy_state_hdecr)
1026+
copy_state_hdecr),
1027+
GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_HEAP_INUSE, l0_guest_heap_inuse),
1028+
GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_HEAP_MAX, l0_guest_heap_max),
1029+
GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_SIZE_INUSE,
1030+
l0_guest_pgtable_size_inuse),
1031+
GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_SIZE_MAX,
1032+
l0_guest_pgtable_size_max),
1033+
GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_RECLAIMED,
1034+
l0_guest_pgtable_reclaimed),
10171035
};
10181036

10191037
void spapr_nested_gsb_init(void)
@@ -1031,8 +1049,13 @@ void spapr_nested_gsb_init(void)
10311049
else if (type->id >= GSB_VCPU_IN_BUFFER)
10321050
/* 0x0c00 - 0xf000 Thread + RW */
10331051
type->flags = 0;
1052+
else if (type->id >= GSB_L0_GUEST_HEAP_INUSE)
1053+
1054+
/*0x0800 - 0x0804 Hostwide Counters + RO */
1055+
type->flags = GUEST_STATE_ELEMENT_TYPE_FLAG_HOST_WIDE |
1056+
GUEST_STATE_ELEMENT_TYPE_FLAG_READ_ONLY;
10341057
else if (type->id >= GSB_VCPU_LPVR)
1035-
/* 0x0003 - 0x0bff Guest + RW */
1058+
/* 0x0003 - 0x07ff Guest + RW */
10361059
type->flags = GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE;
10371060
else if (type->id >= GSB_HV_VCPU_STATE_SIZE)
10381061
/* 0x0001 - 0x0002 Guest + RO */
@@ -1139,18 +1162,26 @@ static bool guest_state_request_check(struct guest_state_request *gsr)
11391162
return false;
11401163
}
11411164

1142-
if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE) {
1165+
if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_HOST_WIDE) {
1166+
/* Hostwide elements cant be clubbed with other types */
1167+
if (!(gsr->flags & GUEST_STATE_REQUEST_HOST_WIDE)) {
1168+
qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a host wide "
1169+
"Element ID:%04x.\n", id);
1170+
return false;
1171+
}
1172+
} else if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE) {
11431173
/* guest wide element type */
11441174
if (!(gsr->flags & GUEST_STATE_REQUEST_GUEST_WIDE)) {
1145-
qemu_log_mask(LOG_GUEST_ERROR, "trying to set a guest wide "
1175+
qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a guest wide "
11461176
"Element ID:%04x.\n", id);
11471177
return false;
11481178
}
11491179
} else {
11501180
/* thread wide element type */
1151-
if (gsr->flags & GUEST_STATE_REQUEST_GUEST_WIDE) {
1152-
qemu_log_mask(LOG_GUEST_ERROR, "trying to set a thread wide "
1153-
"Element ID:%04x.\n", id);
1181+
if (gsr->flags & (GUEST_STATE_REQUEST_GUEST_WIDE |
1182+
GUEST_STATE_REQUEST_HOST_WIDE)) {
1183+
qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a thread wide"
1184+
" Element ID:%04x.\n", id);
11541185
return false;
11551186
}
11561187
}
@@ -1419,7 +1450,8 @@ static target_ulong h_guest_create_vcpu(PowerPCCPU *cpu,
14191450
return H_SUCCESS;
14201451
}
14211452

1422-
static target_ulong getset_state(SpaprMachineStateNestedGuest *guest,
1453+
static target_ulong getset_state(SpaprMachineState *spapr,
1454+
SpaprMachineStateNestedGuest *guest,
14231455
uint64_t vcpuid,
14241456
struct guest_state_request *gsr)
14251457
{
@@ -1452,7 +1484,7 @@ static target_ulong getset_state(SpaprMachineStateNestedGuest *guest,
14521484

14531485
/* Get pointer to guest data to get/set */
14541486
if (type->location && type->copy) {
1455-
ptr = type->location(guest, vcpuid);
1487+
ptr = type->location(spapr, guest, vcpuid);
14561488
assert(ptr);
14571489
if (!~(type->mask) && is_gsr_invalid(gsr, element, type)) {
14581490
return H_INVALID_ELEMENT_VALUE;
@@ -1469,6 +1501,7 @@ static target_ulong getset_state(SpaprMachineStateNestedGuest *guest,
14691501
}
14701502

14711503
static target_ulong map_and_getset_state(PowerPCCPU *cpu,
1504+
SpaprMachineState *spapr,
14721505
SpaprMachineStateNestedGuest *guest,
14731506
uint64_t vcpuid,
14741507
struct guest_state_request *gsr)
@@ -1492,7 +1525,7 @@ static target_ulong map_and_getset_state(PowerPCCPU *cpu,
14921525
goto out1;
14931526
}
14941527

1495-
rc = getset_state(guest, vcpuid, gsr);
1528+
rc = getset_state(spapr, guest, vcpuid, gsr);
14961529

14971530
out1:
14981531
address_space_unmap(CPU(cpu)->as, gsr->gsb, len, is_write, len);
@@ -1510,27 +1543,46 @@ static target_ulong h_guest_getset_state(PowerPCCPU *cpu,
15101543
target_ulong buf = args[3];
15111544
target_ulong buflen = args[4];
15121545
struct guest_state_request gsr;
1513-
SpaprMachineStateNestedGuest *guest;
1546+
SpaprMachineStateNestedGuest *guest = NULL;
15141547

1515-
guest = spapr_get_nested_guest(spapr, lpid);
1516-
if (!guest) {
1517-
return H_P2;
1518-
}
15191548
gsr.buf = buf;
15201549
assert(buflen <= GSB_MAX_BUF_SIZE);
15211550
gsr.len = buflen;
15221551
gsr.flags = 0;
1523-
if (flags & H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE) {
1552+
1553+
/* Works for both get/set state */
1554+
if ((flags & H_GUEST_GET_STATE_FLAGS_GUEST_WIDE) ||
1555+
(flags & H_GUEST_SET_STATE_FLAGS_GUEST_WIDE)) {
15241556
gsr.flags |= GUEST_STATE_REQUEST_GUEST_WIDE;
15251557
}
1526-
if (flags & ~H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE) {
1527-
return H_PARAMETER; /* flag not supported yet */
1528-
}
15291558

15301559
if (set) {
1560+
if (flags & ~H_GUEST_SET_STATE_FLAGS_MASK) {
1561+
return H_PARAMETER;
1562+
}
15311563
gsr.flags |= GUEST_STATE_REQUEST_SET;
1564+
} else {
1565+
/*
1566+
* No reserved fields to be set in flags nor both
1567+
* GUEST/HOST wide bits
1568+
*/
1569+
if ((flags & ~H_GUEST_GET_STATE_FLAGS_MASK) ||
1570+
(flags == H_GUEST_GET_STATE_FLAGS_MASK)) {
1571+
return H_PARAMETER;
1572+
}
1573+
1574+
if (flags & H_GUEST_GET_STATE_FLAGS_HOST_WIDE) {
1575+
gsr.flags |= GUEST_STATE_REQUEST_HOST_WIDE;
1576+
}
1577+
}
1578+
1579+
if (!(gsr.flags & GUEST_STATE_REQUEST_HOST_WIDE)) {
1580+
guest = spapr_get_nested_guest(spapr, lpid);
1581+
if (!guest) {
1582+
return H_P2;
1583+
}
15321584
}
1533-
return map_and_getset_state(cpu, guest, vcpuid, &gsr);
1585+
return map_and_getset_state(cpu, spapr, guest, vcpuid, &gsr);
15341586
}
15351587

15361588
static target_ulong h_guest_set_state(PowerPCCPU *cpu,
@@ -1641,7 +1693,8 @@ static int get_exit_ids(uint64_t srr0, uint16_t ids[16])
16411693
return nr;
16421694
}
16431695

1644-
static void exit_process_output_buffer(PowerPCCPU *cpu,
1696+
static void exit_process_output_buffer(SpaprMachineState *spapr,
1697+
PowerPCCPU *cpu,
16451698
SpaprMachineStateNestedGuest *guest,
16461699
target_ulong vcpuid,
16471700
target_ulong *r3)
@@ -1679,7 +1732,7 @@ static void exit_process_output_buffer(PowerPCCPU *cpu,
16791732
gsr.gsb = gsb;
16801733
gsr.len = VCPU_OUT_BUF_MIN_SZ;
16811734
gsr.flags = 0; /* get + never guest wide */
1682-
getset_state(guest, vcpuid, &gsr);
1735+
getset_state(spapr, guest, vcpuid, &gsr);
16831736

16841737
address_space_unmap(CPU(cpu)->as, gsb, len, true, len);
16851738
return;
@@ -1705,7 +1758,7 @@ void spapr_exit_nested_papr(SpaprMachineState *spapr, PowerPCCPU *cpu, int excp)
17051758

17061759
exit_nested_store_l2(cpu, excp, vcpu);
17071760
/* do the output buffer for run_vcpu*/
1708-
exit_process_output_buffer(cpu, guest, vcpuid, &r3_return);
1761+
exit_process_output_buffer(spapr, cpu, guest, vcpuid, &r3_return);
17091762

17101763
assert(env->spr[SPR_LPIDR] != 0);
17111764
nested_load_state(cpu, spapr_cpu->nested_host_state);
@@ -1820,7 +1873,7 @@ static target_ulong h_guest_run_vcpu(PowerPCCPU *cpu,
18201873
gsr.buf = vcpu->runbufin.addr;
18211874
gsr.len = vcpu->runbufin.size;
18221875
gsr.flags = GUEST_STATE_REQUEST_SET; /* Thread wide + writing */
1823-
rc = map_and_getset_state(cpu, guest, vcpuid, &gsr);
1876+
rc = map_and_getset_state(cpu, spapr, guest, vcpuid, &gsr);
18241877
if (rc == H_SUCCESS) {
18251878
nested_papr_run_vcpu(cpu, lpid, vcpu);
18261879
} else {

include/hw/ppc/spapr_nested.h

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111
#define GSB_TB_OFFSET 0x0004 /* Timebase Offset */
1212
#define GSB_PART_SCOPED_PAGETBL 0x0005 /* Partition Scoped Page Table */
1313
#define GSB_PROCESS_TBL 0x0006 /* Process Table */
14-
/* RESERVED 0x0007 - 0x0BFF */
14+
/* RESERVED 0x0007 - 0x07FF */
15+
#define GSB_L0_GUEST_HEAP_INUSE 0x0800 /* Guest Management Heap Size */
16+
#define GSB_L0_GUEST_HEAP_MAX 0x0801 /* Guest Management Heap Max Size */
17+
#define GSB_L0_GUEST_PGTABLE_SIZE_INUSE 0x0802 /* Guest Pagetable Size */
18+
#define GSB_L0_GUEST_PGTABLE_SIZE_MAX 0x0803 /* Guest Pagetable Max Size */
19+
#define GSB_L0_GUEST_PGTABLE_RECLAIMED 0x0804 /* Pagetable Reclaim in bytes */
20+
/* RESERVED 0x0805 - 0xBFF */
1521
#define GSB_VCPU_IN_BUFFER 0x0C00 /* Run VCPU Input Buffer */
1622
#define GSB_VCPU_OUT_BUFFER 0x0C01 /* Run VCPU Out Buffer */
1723
#define GSB_VCPU_VPA 0x0C02 /* HRA to Guest VCPU VPA */
@@ -196,6 +202,38 @@ typedef struct SpaprMachineStateNested {
196202
#define NESTED_API_PAPR 2
197203
bool capabilities_set;
198204
uint32_t pvr_base;
205+
206+
/**
207+
* l0_guest_heap_inuse: The currently used bytes in the Hypervisor's Guest
208+
* Management Space associated with the Host Partition.
209+
**/
210+
uint64_t l0_guest_heap_inuse;
211+
212+
/**
213+
* host_heap_max: The maximum bytes available in the Hypervisor's Guest
214+
* Management Space associated with the Host Partition.
215+
**/
216+
uint64_t l0_guest_heap_max;
217+
218+
/**
219+
* host_pagetable: The currently used bytes in the Hypervisor's Guest
220+
* Page Table Management Space associated with the Host Partition.
221+
**/
222+
uint64_t l0_guest_pgtable_size_inuse;
223+
224+
/**
225+
* host_pagetable_max: The maximum bytes available in the Hypervisor's Guest
226+
* Page Table Management Space associated with the Host Partition.
227+
**/
228+
uint64_t l0_guest_pgtable_size_max;
229+
230+
/**
231+
* host_pagetable_reclaim: The amount of space in bytes that has been
232+
* reclaimed due to overcommit in the Hypervisor's Guest Page Table
233+
* Management Space associated with the Host Partition.
234+
**/
235+
uint64_t l0_guest_pgtable_reclaimed;
236+
199237
GHashTable *guests;
200238
} SpaprMachineStateNested;
201239

@@ -229,9 +267,15 @@ typedef struct SpaprMachineStateNestedGuest {
229267
#define HVMASK_HDEXCR 0x00000000FFFFFFFF
230268
#define HVMASK_TB_OFFSET 0x000000FFFFFFFFFF
231269
#define GSB_MAX_BUF_SIZE (1024 * 1024)
232-
#define H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE 0x8000000000000000
233-
#define GUEST_STATE_REQUEST_GUEST_WIDE 0x1
234-
#define GUEST_STATE_REQUEST_SET 0x2
270+
#define H_GUEST_GET_STATE_FLAGS_MASK 0xC000000000000000ULL
271+
#define H_GUEST_SET_STATE_FLAGS_MASK 0x8000000000000000ULL
272+
#define H_GUEST_SET_STATE_FLAGS_GUEST_WIDE 0x8000000000000000ULL
273+
#define H_GUEST_GET_STATE_FLAGS_GUEST_WIDE 0x8000000000000000ULL
274+
#define H_GUEST_GET_STATE_FLAGS_HOST_WIDE 0x4000000000000000ULL
275+
276+
#define GUEST_STATE_REQUEST_GUEST_WIDE 0x1
277+
#define GUEST_STATE_REQUEST_HOST_WIDE 0x2
278+
#define GUEST_STATE_REQUEST_SET 0x4
235279

236280
/*
237281
* As per ISA v3.1B, following bits are reserved:
@@ -251,6 +295,15 @@ typedef struct SpaprMachineStateNestedGuest {
251295
.copy = (c) \
252296
}
253297

298+
#define GSBE_NESTED_MACHINE_DW(i, f) { \
299+
.id = (i), \
300+
.size = 8, \
301+
.location = get_machine_ptr, \
302+
.offset = offsetof(struct SpaprMachineStateNested, f), \
303+
.copy = copy_state_8to8, \
304+
.mask = HVMASK_DEFAULT \
305+
}
306+
254307
#define GSBE_NESTED(i, sz, f, c) { \
255308
.id = (i), \
256309
.size = (sz), \
@@ -509,9 +562,11 @@ struct guest_state_element_type {
509562
uint16_t id;
510563
int size;
511564
#define GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE 0x1
512-
#define GUEST_STATE_ELEMENT_TYPE_FLAG_READ_ONLY 0x2
565+
#define GUEST_STATE_ELEMENT_TYPE_FLAG_HOST_WIDE 0x2
566+
#define GUEST_STATE_ELEMENT_TYPE_FLAG_READ_ONLY 0x4
513567
uint16_t flags;
514-
void *(*location)(SpaprMachineStateNestedGuest *, target_ulong);
568+
void *(*location)(struct SpaprMachineState *, SpaprMachineStateNestedGuest *,
569+
target_ulong);
515570
size_t offset;
516571
void (*copy)(void *, void *, bool);
517572
uint64_t mask;

0 commit comments

Comments
 (0)