mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/arm: report clock_frequency via sysctl physinfo, not createdomain
The xen_arch_domainconfig.clock_frequency value is populated in domain_vtimer_init() during XEN_DOMCTL_createdomain from the global timer_dt_clock_frequency, which comes from the host's DT timer node and has nothing to do with the domain being created. Like now removed GIC_NATIVE resolution, this is a host-wide system property being smuggled out through a domain-creation IN struct. Expose it instead as a new arm_clock_frequency_hz field in XEN_SYSCTL_physinfo, populated via arch_do_physinfo(), and mirroring how the GIC capability bits were already moved there. Rather than making the field dependant on DT boot, make Xen always report the timer frequency, either via the DT "clock-frequency" node, or directly via CNTFRQ_EL0. preinit_xen_time() already computes cpu_khz for every boot path. The renamed timer_clock_frequency_hz now captures whichever of the two produced that value, in full Hz precision, instead of only recording the DT case. So, ACPI guests get a real value too, allowing to drop the special case. The DT "clock-frequency" property exists because firmware might leave CNTFRQ_EL0 wrong, and since CNTFRQ_EL0 cannot be trapped the only fix is to replicate the correct value into the guest DT. To keep that signal, a new XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ capability bit records whether arm_clock_frequency_hz came from the DT property. Then libxl only emits a "clock-frequency" property into the guest timer node when that bit is set. A guest whose CNTFRQ_EL0 is already correct keeps an unmodified timer node, exactly as before. Although the CNTFRQ_EL0 register is 64 bits wide, and some current timer implementations run at 1GHz, a 32bit value is sufficient to store the timer value, because it only mirrors the DT 'clock-frequency' property, which the bindings define as a single 32-bit cell. In struct xen_sysctl_physinfo the new field just reuses the former pad word, so sysctl consumers are unaffected. struct xen_arch_domainconfig however loses clock_frequency from its middle, which shrinks the struct and shifts every field after it, so bump XEN_DOMCTL_INTERFACE_VERSION. The xen_arch_domainconfig parameter passed to domain_vtimer_init() is no longer needed, so drop that parameter entirely. libxl now fetches the frequency via libxl_get_physinfo() in libxl__arch_domain_save_config() instead of reading it back out of the createdomain reply. The OCaml xen_arch_domainconfig mirror drops the field too. Signed-off-by: Julian Vetter <julian.vetter@vates.tech> Reviewed-by: Michal Orzel <michal.orzel@amd.com> Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
This commit is contained in:
1 parent
6c6bec2c80
commit
baaa185201
18 files changed
+81
-38
No files matched your search
@@ -3702,6 +3702,7 @@ x.CapVpmu = bool(xc.cap_vpmu)
|
|||||||
x.CapGnttabV1 = bool(xc.cap_gnttab_v1)
|
x.CapGnttabV1 = bool(xc.cap_gnttab_v1)
|
||||||
x.CapGnttabV2 = bool(xc.cap_gnttab_v2)
|
x.CapGnttabV2 = bool(xc.cap_gnttab_v2)
|
||||||
x.ArchCapabilities = uint32(xc.arch_capabilities)
|
x.ArchCapabilities = uint32(xc.arch_capabilities)
|
||||||
|
x.ArmClockFrequencyHz = uint32(xc.arm_clock_frequency_hz)
|
||||||
|
|
||||||
return nil}
|
return nil}
|
||||||
|
|
||||||
@@ -3737,6 +3738,7 @@ xc.cap_vpmu = C.bool(x.CapVpmu)
|
|||||||
xc.cap_gnttab_v1 = C.bool(x.CapGnttabV1)
|
xc.cap_gnttab_v1 = C.bool(x.CapGnttabV1)
|
||||||
xc.cap_gnttab_v2 = C.bool(x.CapGnttabV2)
|
xc.cap_gnttab_v2 = C.bool(x.CapGnttabV2)
|
||||||
xc.arch_capabilities = C.uint32_t(x.ArchCapabilities)
|
xc.arch_capabilities = C.uint32_t(x.ArchCapabilities)
|
||||||
|
xc.arm_clock_frequency_hz = C.uint32_t(x.ArmClockFrequencyHz)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1150,6 +1150,7 @@ CapVpmu bool
|
|||||||
CapGnttabV1 bool
|
CapGnttabV1 bool
|
||||||
CapGnttabV2 bool
|
CapGnttabV2 bool
|
||||||
ArchCapabilities uint32
|
ArchCapabilities uint32
|
||||||
|
ArmClockFrequencyHz uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connectorinfo struct {
|
type Connectorinfo struct {
|
||||||
|
|||||||
@@ -46,4 +46,14 @@ bool arch_capabilities_arm_gic_v3(unsigned int arch_capabilities)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool arch_capabilities_arm_timer_dt_freq(unsigned int arch_capabilities)
|
||||||
|
{
|
||||||
|
#if defined(__arm__) || defined(__aarch64__)
|
||||||
|
return MASK_EXTR(arch_capabilities, XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ARM_ARCH_CAPABILITIES_H */
|
#endif /* ARM_ARCH_CAPABILITIES_H */
|
||||||
@@ -410,6 +410,7 @@ int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
|
|||||||
physinfo->cap_gnttab_v2 =
|
physinfo->cap_gnttab_v2 =
|
||||||
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2);
|
!!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2);
|
||||||
physinfo->arch_capabilities = xcphysinfo.arch_capabilities;
|
physinfo->arch_capabilities = xcphysinfo.arch_capabilities;
|
||||||
|
physinfo->arm_clock_frequency_hz = xcphysinfo.arm_clock_frequency_hz;
|
||||||
|
|
||||||
GC_FREE;
|
GC_FREE;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -252,6 +252,16 @@ int libxl__arch_domain_save_config(libxl__gc *gc,
|
|||||||
libxl__domain_build_state *state,
|
libxl__domain_build_state *state,
|
||||||
const struct xen_domctl_createdomain *config)
|
const struct xen_domctl_createdomain *config)
|
||||||
{
|
{
|
||||||
|
libxl_physinfo info;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
libxl_physinfo_init(&info);
|
||||||
|
rc = libxl_get_physinfo(CTX, &info);
|
||||||
|
if (rc) {
|
||||||
|
LOG(ERROR, "failed to get physinfo");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
switch (config->arch.gic_version) {
|
switch (config->arch.gic_version) {
|
||||||
case XEN_DOMCTL_CONFIG_GIC_V2:
|
case XEN_DOMCTL_CONFIG_GIC_V2:
|
||||||
d_config->b_info.arch_arm.gic_version = LIBXL_GIC_VERSION_V2;
|
d_config->b_info.arch_arm.gic_version = LIBXL_GIC_VERSION_V2;
|
||||||
@@ -261,12 +271,25 @@ int libxl__arch_domain_save_config(libxl__gc *gc,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(ERROR, "Unexpected gic version %u", config->arch.gic_version);
|
LOG(ERROR, "Unexpected gic version %u", config->arch.gic_version);
|
||||||
return ERROR_FAIL;
|
rc = ERROR_FAIL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->clock_frequency = config->arch.clock_frequency;
|
/*
|
||||||
|
* Pass the timer frequency on to the guest DT only when Xen took it from
|
||||||
|
* the host DT (XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ). Otherwise the guest
|
||||||
|
* gets the right value from CNTFRQ_EL0.
|
||||||
|
*/
|
||||||
|
if (arch_capabilities_arm_timer_dt_freq(info.arch_capabilities))
|
||||||
|
state->clock_frequency = info.arm_clock_frequency_hz;
|
||||||
|
else
|
||||||
|
state->clock_frequency = 0;
|
||||||
|
|
||||||
return 0;
|
rc = 0;
|
||||||
|
out:
|
||||||
|
libxl_physinfo_dispose(&info);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libxl__arch_domain_create(libxl__gc *gc,
|
int libxl__arch_domain_create(libxl__gc *gc,
|
||||||
|
|||||||
@@ -1202,6 +1202,7 @@ libxl_physinfo = Struct("physinfo", [
|
|||||||
("cap_gnttab_v1", bool),
|
("cap_gnttab_v1", bool),
|
||||||
("cap_gnttab_v2", bool),
|
("cap_gnttab_v2", bool),
|
||||||
("arch_capabilities", uint32),
|
("arch_capabilities", uint32),
|
||||||
|
("arm_clock_frequency_hz", uint32),
|
||||||
], dir=DIR_OUT)
|
], dir=DIR_OUT)
|
||||||
|
|
||||||
libxl_connectorinfo = Struct("connectorinfo", [
|
libxl_connectorinfo = Struct("connectorinfo", [
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ type xen_arm_arch_domainconfig =
|
|||||||
{
|
{
|
||||||
gic_version: int;
|
gic_version: int;
|
||||||
nr_spis: int;
|
nr_spis: int;
|
||||||
clock_frequency: int32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type x86_arch_emulation_flags =
|
type x86_arch_emulation_flags =
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ type vcpuinfo = {
|
|||||||
type xen_arm_arch_domainconfig = {
|
type xen_arm_arch_domainconfig = {
|
||||||
gic_version: int;
|
gic_version: int;
|
||||||
nr_spis: int;
|
nr_spis: int;
|
||||||
clock_frequency: int32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type x86_arch_emulation_flags =
|
type x86_arch_emulation_flags =
|
||||||
|
|||||||
@@ -449,13 +449,10 @@ static value alloc_domaininfo(xc_domaininfo_t * info)
|
|||||||
tag = 0; /* tag ARM */
|
tag = 0; /* tag ARM */
|
||||||
|
|
||||||
/* xen_arm_arch_domainconfig */
|
/* xen_arm_arch_domainconfig */
|
||||||
arch_config = caml_alloc_tuple(3);
|
arch_config = caml_alloc_tuple(2);
|
||||||
Field(arch_config, 0) = Val_int(info->arch_config.gic_version);
|
Field(arch_config, 0) = Val_int(info->arch_config.gic_version);
|
||||||
Field(arch_config, 1) = Val_int(info->arch_config.nr_spis);
|
Field(arch_config, 1) = Val_int(info->arch_config.nr_spis);
|
||||||
|
|
||||||
tmp = caml_copy_int32(info->arch_config.clock_frequency);
|
|
||||||
Field(arch_config, 2) = tmp;
|
|
||||||
|
|
||||||
#elif defined(__i386__) || defined(__x86_64__)
|
#elif defined(__i386__) || defined(__x86_64__)
|
||||||
|
|
||||||
tag = 1; /* tag x86 */
|
tag = 1; /* tag x86 */
|
||||||
|
|||||||
@@ -714,7 +714,7 @@ int arch_domain_create(struct domain *d,
|
|||||||
if ( (rc = domain_vgic_init(d, config->arch.nr_spis)) != 0 )
|
if ( (rc = domain_vgic_init(d, config->arch.nr_spis)) != 0 )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ( (rc = domain_vtimer_init(d, &config->arch)) != 0 )
|
if ( (rc = domain_vtimer_init(d)) != 0 )
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ( (rc = tee_domain_init(d, config->arch.tee_type)) != 0 )
|
if ( (rc = tee_domain_init(d, config->arch.tee_type)) != 0 )
|
||||||
|
|||||||
@@ -87,10 +87,11 @@ enum timer_ppi
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Value of "clock-frequency" in the DT timer node if present.
|
* The timer frequency, in Hz, that Xen ended up using, and whether it came
|
||||||
* 0 means the property doesn't exist.
|
* from the DT "clock-frequency" property rather than CNTFRQ_EL0.
|
||||||
*/
|
*/
|
||||||
extern uint32_t timer_dt_clock_frequency;
|
extern uint32_t timer_clock_frequency_hz;
|
||||||
|
extern bool timer_clock_frequency_from_dt;
|
||||||
|
|
||||||
/* Get one of the timer IRQ number */
|
/* Get one of the timer IRQ number */
|
||||||
unsigned int timer_get_irq(enum timer_ppi ppi);
|
unsigned int timer_get_irq(enum timer_ppi ppi);
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
#ifndef __ARCH_ARM_VTIMER_H__
|
#ifndef __ARCH_ARM_VTIMER_H__
|
||||||
#define __ARCH_ARM_VTIMER_H__
|
#define __ARCH_ARM_VTIMER_H__
|
||||||
|
|
||||||
extern int domain_vtimer_init(struct domain *d,
|
extern int domain_vtimer_init(struct domain *d);
|
||||||
struct xen_arch_domainconfig *config);
|
|
||||||
extern int vcpu_vtimer_init(struct vcpu *v);
|
extern int vcpu_vtimer_init(struct vcpu *v);
|
||||||
extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
|
extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
|
||||||
extern void virt_timer_save(struct vcpu *v);
|
extern void virt_timer_save(struct vcpu *v);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <asm/arm64/sve.h>
|
#include <asm/arm64/sve.h>
|
||||||
#include <asm/gic.h>
|
#include <asm/gic.h>
|
||||||
|
#include <asm/time.h>
|
||||||
#include <asm/vgic.h>
|
#include <asm/vgic.h>
|
||||||
|
|
||||||
#include <public/sysctl.h>
|
#include <public/sysctl.h>
|
||||||
@@ -26,6 +27,10 @@ void arch_do_physinfo(struct xen_sysctl_physinfo *pi)
|
|||||||
pi->arch_capabilities |= MASK_INSR(sve_encode_vl(get_sys_vl_len()),
|
pi->arch_capabilities |= MASK_INSR(sve_encode_vl(get_sys_vl_len()),
|
||||||
XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK);
|
XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK);
|
||||||
|
|
||||||
|
pi->arm_clock_frequency_hz = timer_clock_frequency_hz;
|
||||||
|
if ( timer_clock_frequency_from_dt )
|
||||||
|
pi->arch_capabilities |= XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ;
|
||||||
|
|
||||||
switch ( gic_hw_version() )
|
switch ( gic_hw_version() )
|
||||||
{
|
{
|
||||||
case GIC_V2:
|
case GIC_V2:
|
||||||
|
|||||||
+6
-3
@@ -35,7 +35,8 @@ uint64_t __read_mostly boot_count;
|
|||||||
* register-mapped time source in the SoC. */
|
* register-mapped time source in the SoC. */
|
||||||
unsigned long __read_mostly cpu_khz; /* CPU clock frequency in kHz. */
|
unsigned long __read_mostly cpu_khz; /* CPU clock frequency in kHz. */
|
||||||
|
|
||||||
uint32_t __read_mostly timer_dt_clock_frequency;
|
uint32_t __read_mostly timer_clock_frequency_hz;
|
||||||
|
bool __read_mostly timer_clock_frequency_from_dt;
|
||||||
|
|
||||||
static unsigned int timer_irq[MAX_TIMER_PPI];
|
static unsigned int timer_irq[MAX_TIMER_PPI];
|
||||||
|
|
||||||
@@ -130,7 +131,8 @@ static void __init preinit_dt_xen_time(void)
|
|||||||
{
|
{
|
||||||
cpu_khz = DIV_ROUND(rate, 1000);
|
cpu_khz = DIV_ROUND(rate, 1000);
|
||||||
validate_timer_frequency();
|
validate_timer_frequency();
|
||||||
timer_dt_clock_frequency = rate;
|
timer_clock_frequency_hz = rate;
|
||||||
|
timer_clock_frequency_from_dt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +148,8 @@ void __init preinit_xen_time(void)
|
|||||||
|
|
||||||
if ( !cpu_khz )
|
if ( !cpu_khz )
|
||||||
{
|
{
|
||||||
cpu_khz = DIV_ROUND(READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK, 1000);
|
timer_clock_frequency_hz = READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK;
|
||||||
|
cpu_khz = DIV_ROUND(timer_clock_frequency_hz, 1000);
|
||||||
validate_timer_frequency();
|
validate_timer_frequency();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static void virt_timer_expired(void *data)
|
|||||||
perfc_incr(vtimer_virt_inject);
|
perfc_incr(vtimer_virt_inject);
|
||||||
}
|
}
|
||||||
|
|
||||||
int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config)
|
int domain_vtimer_init(struct domain *d)
|
||||||
{
|
{
|
||||||
d->arch.virt_timer_base.offset = get_cycles();
|
d->arch.virt_timer_base.offset = get_cycles();
|
||||||
d->arch.virt_timer_base.nanoseconds =
|
d->arch.virt_timer_base.nanoseconds =
|
||||||
@@ -60,8 +60,6 @@ int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config)
|
|||||||
d->time_offset.seconds = d->arch.virt_timer_base.nanoseconds;
|
d->time_offset.seconds = d->arch.virt_timer_base.nanoseconds;
|
||||||
do_div(d->time_offset.seconds, 1000000000);
|
do_div(d->time_offset.seconds, 1000000000);
|
||||||
|
|
||||||
config->clock_frequency = timer_dt_clock_frequency;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per the ACPI specification, providing a secure EL1 timer
|
* Per the ACPI specification, providing a secure EL1 timer
|
||||||
* interrupt is optional and will be ignored by non-secure OS.
|
* interrupt is optional and will be ignored by non-secure OS.
|
||||||
|
|||||||
@@ -343,20 +343,6 @@ struct xen_arch_domainconfig {
|
|||||||
uint16_t tee_type;
|
uint16_t tee_type;
|
||||||
/* IN */
|
/* IN */
|
||||||
uint32_t nr_spis;
|
uint32_t nr_spis;
|
||||||
/*
|
|
||||||
* OUT
|
|
||||||
* Based on the property clock-frequency in the DT timer node.
|
|
||||||
* The property may be present when the bootloader/firmware doesn't
|
|
||||||
* set correctly CNTFRQ which hold the timer frequency.
|
|
||||||
*
|
|
||||||
* As it's not possible to trap this register, we have to replicate
|
|
||||||
* the value in the guest DT.
|
|
||||||
*
|
|
||||||
* = 0 => property not present
|
|
||||||
* > 0 => Value of the property
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
uint32_t clock_frequency;
|
|
||||||
/* IN */
|
/* IN */
|
||||||
uint8_t arm_sci_type;
|
uint8_t arm_sci_type;
|
||||||
/* IN */
|
/* IN */
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
* fields) don't require a change of the version.
|
* fields) don't require a change of the version.
|
||||||
* Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION!
|
* Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION!
|
||||||
*
|
*
|
||||||
* Last version bump: Xen 4.22
|
* Last version bump: Xen 4.23
|
||||||
*/
|
*/
|
||||||
#define XEN_DOMCTL_INTERFACE_VERSION 0x00000018
|
#define XEN_DOMCTL_INTERFACE_VERSION 0x00000019
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NB. xen_domctl.domain is an IN/OUT parameter for this operation.
|
* NB. xen_domctl.domain is an IN/OUT parameter for this operation.
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ struct xen_sysctl_tbuf_op {
|
|||||||
#define XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK (0x1FU)
|
#define XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK (0x1FU)
|
||||||
#define XEN_SYSCTL_PHYSCAP_ARM_GIC_V2 (1U << 5)
|
#define XEN_SYSCTL_PHYSCAP_ARM_GIC_V2 (1U << 5)
|
||||||
#define XEN_SYSCTL_PHYSCAP_ARM_GIC_V3 (1U << 6)
|
#define XEN_SYSCTL_PHYSCAP_ARM_GIC_V3 (1U << 6)
|
||||||
|
/* See arm_clock_frequency_hz in struct xen_sysctl_physinfo. */
|
||||||
|
#define XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ (1U << 7)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct xen_sysctl_physinfo {
|
struct xen_sysctl_physinfo {
|
||||||
@@ -120,7 +122,23 @@ struct xen_sysctl_physinfo {
|
|||||||
uint32_t cpu_khz;
|
uint32_t cpu_khz;
|
||||||
uint32_t capabilities;/* XEN_SYSCTL_PHYSCAP_??? */
|
uint32_t capabilities;/* XEN_SYSCTL_PHYSCAP_??? */
|
||||||
uint32_t arch_capabilities;/* XEN_SYSCTL_PHYSCAP_{X86,ARM,...}_??? */
|
uint32_t arch_capabilities;/* XEN_SYSCTL_PHYSCAP_{X86,ARM,...}_??? */
|
||||||
uint32_t pad;
|
|
||||||
|
/*
|
||||||
|
* ARM only. The timer frequency, in Hz, that Xen is using, taken either
|
||||||
|
* from the host DT timer node's "clock-frequency" property or from a
|
||||||
|
* direct CNTFRQ_EL0 read.
|
||||||
|
*
|
||||||
|
* XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ is set in the former case. The host
|
||||||
|
* DT overrides CNTFRQ_EL0 (the usual way a wrong bootloader/firmware value
|
||||||
|
* is corrected), so the toolstack must carry the same override into the
|
||||||
|
* guest's timer node, since CNTFRQ_EL0 cannot be trapped and fixed up per
|
||||||
|
* guest.
|
||||||
|
*
|
||||||
|
* = 0 => Non-ARM. On ARM the frequency is validated at boot and is
|
||||||
|
* always non-zero.
|
||||||
|
* > 0 => The frequency, in Hz.
|
||||||
|
*/
|
||||||
|
uint32_t arm_clock_frequency_hz;
|
||||||
uint64_aligned_t total_pages;
|
uint64_aligned_t total_pages;
|
||||||
uint64_aligned_t free_pages;
|
uint64_aligned_t free_pages;
|
||||||
uint64_aligned_t scrub_pages;
|
uint64_aligned_t scrub_pages;
|
||||||
|
|||||||