@@ -38,6 +38,8 @@
#define POWER7_EXT_IRQ 0
+#define LPCR_ILE (1 << (63-38))
+
struct kvm;
struct kvm_cpu {
@@ -286,7 +286,7 @@ static int setup_fdt(struct kvm *kvm)
uint32_t int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
char hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
"hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
- "hcall-splpar\0hcall-bulk";
+ "hcall-splpar\0hcall-bulk\0hcall-set-mode";
int i, j;
char cpu_name[30];
u8 staging_fdt[FDT_MAX_SIZE];
@@ -27,7 +27,7 @@ typedef uintptr_t target_phys_addr_t;
#define H_HARDWARE -1 /* Hardware error */
#define H_FUNCTION -2 /* Function not supported */
#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */
-
+#define H_P2 -55
#define H_SET_DABR 0x28
#define H_LOGICAL_CI_LOAD 0x3c
#define H_LOGICAL_CI_STORE 0x40
@@ -41,7 +41,18 @@ typedef uintptr_t target_phys_addr_t;
#define H_EOI 0x64
#define H_IPI 0x6c
#define H_XIRR 0x74
-#define MAX_HCALL_OPCODE H_XIRR
+#define H_SET_MODE 0x31C
+#define MAX_HCALL_OPCODE H_SET_MODE
+
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_CIABR 1
+#define H_SET_MODE_RESOURCE_SET_DAWR 2
+#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
+#define H_SET_MODE_RESOURCE_LE 4
+
+/* Flags for H_SET_MODE_RESOURCE_LE */
+#define H_SET_MODE_ENDIAN_BIG 0
+#define H_SET_MODE_ENDIAN_LITTLE 1
/*
* The hcalls above are standardized in PAPR and implemented by pHyp
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <assert.h>
+#include <sys/eventfd.h>
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX -
@@ -74,6 +75,70 @@ static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, ta
return H_SUCCESS;
}
+struct lpcr_data {
+ struct kvm_cpu *cpu;
+ int mode;
+};
+
+static void get_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
+{
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_LPCR_64,
+ .addr = (__u64)lpcr
+ };
+
+ if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®))
+ die("Couldn't read vcpu reg?!");
+}
+
+static void set_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
+{
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_LPCR_64,
+ .addr = (__u64)lpcr
+ };
+
+ if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®))
+ die("Couldn't write vcpu reg?!");
+}
+
+static void set_endian_task(struct kvm_cpu *vcpu, void *data)
+{
+ target_ulong mflags = (target_ulong)data;
+ target_ulong lpcr;
+
+ get_cpu_lpcr(vcpu, &lpcr);
+
+ if (mflags == H_SET_MODE_ENDIAN_BIG)
+ lpcr &= ~LPCR_ILE;
+ else
+ lpcr |= LPCR_ILE;
+
+ set_cpu_lpcr(vcpu, &lpcr);
+}
+
+static target_ulong h_set_mode(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+ int ret;
+
+ switch (args[1]) {
+ case H_SET_MODE_RESOURCE_LE: {
+ struct kvm_cpu_task task;
+ task.func = set_endian_task;
+ task.data = (void *)args[0];
+ kvm_cpu__run_on_all_cpus(vcpu->kvm, &task);
+ ret = H_SUCCESS;
+ break;
+ }
+ default:
+ ret = H_FUNCTION;
+ break;
+ }
+
+ return ret;
+}
+
+
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
{
spapr_hcall_fn *slot;
@@ -128,6 +193,7 @@ void hypercall_init(void)
spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+ spapr_register_hypercall(H_SET_MODE, h_set_mode);
/* KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);