All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 4/4] ppc/pegasos2: Implement some RTAS functions with VOF
@ 2021-07-08 21:46 BALATON Zoltan
  2021-07-09  0:40 ` David Gibson
  0 siblings, 1 reply; 2+ messages in thread
From: BALATON Zoltan @ 2021-07-08 21:46 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc; +Cc: Alexey Kardashevskiy, David Gibson

Linux uses RTAS functions to access PCI devices so we need to provide
these with VOF. Implement some of the most important functions to
allow booting Linux with VOF. With this the board is now usable
without a binary ROM image and we can enable it by default as other
boards.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
v2: Use named values for /rtas functions, only sending v2 for this,
    others are unchanged

 default-configs/devices/ppc-softmmu.mak |   2 +-
 hw/ppc/pegasos2.c                       | 137 ++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/default-configs/devices/ppc-softmmu.mak b/default-configs/devices/ppc-softmmu.mak
index c2d41198cd..4535993d8d 100644
--- a/default-configs/devices/ppc-softmmu.mak
+++ b/default-configs/devices/ppc-softmmu.mak
@@ -14,7 +14,7 @@ CONFIG_SAM460EX=y
 CONFIG_MAC_OLDWORLD=y
 CONFIG_MAC_NEWWORLD=y
 
-CONFIG_PEGASOS2=n
+CONFIG_PEGASOS2=y
 
 # For PReP
 CONFIG_PREP=y
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index f1741a4512..5c4e2ae8bf 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -43,6 +43,7 @@
 #define PROM_SIZE     0x80000
 
 #define KVMPPC_HCALL_BASE    0xf000
+#define KVMPPC_H_RTAS        (KVMPPC_HCALL_BASE + 0x0)
 #define KVMPPC_H_VOF_CLIENT  (KVMPPC_HCALL_BASE + 0x5)
 
 #define H_SUCCESS     0
@@ -195,6 +196,30 @@ static void pegasos2_init(MachineState *machine)
     }
 }
 
+static uint32_t pegasos2_pci_config_read(AddressSpace *as, int bus,
+                                         uint32_t addr, uint32_t len)
+{
+    hwaddr pcicfg = (bus ? 0xf1000c78 : 0xf1000cf8);
+    uint32_t val = 0xffffffff;
+
+    stl_le_phys(as, pcicfg, addr | BIT(31));
+    switch (len) {
+    case 4:
+        val = ldl_le_phys(as, pcicfg + 4);
+        break;
+    case 2:
+        val = lduw_le_phys(as, pcicfg + 4);
+        break;
+    case 1:
+        val = ldub_phys(as, pcicfg + 4);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__);
+        break;
+    }
+    return val;
+}
+
 static void pegasos2_pci_config_write(AddressSpace *as, int bus, uint32_t addr,
                                       uint32_t len, uint32_t val)
 {
@@ -304,6 +329,87 @@ static void pegasos2_machine_reset(MachineState *machine)
     pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine);
 }
 
+enum pegasos2_rtas_tokens {
+    RTAS_RESTART_RTAS = 0,
+    RTAS_NVRAM_FETCH = 1,
+    RTAS_NVRAM_STORE = 2,
+    RTAS_GET_TIME_OF_DAY = 3,
+    RTAS_SET_TIME_OF_DAY = 4,
+    RTAS_EVENT_SCAN = 6,
+    RTAS_CHECK_EXCEPTION = 7,
+    RTAS_READ_PCI_CONFIG = 8,
+    RTAS_WRITE_PCI_CONFIG = 9,
+    RTAS_DISPLAY_CHARACTER = 10,
+    RTAS_SET_INDICATOR = 11,
+    RTAS_POWER_OFF = 17,
+    RTAS_SUSPEND = 18,
+    RTAS_HIBERNATE = 19,
+    RTAS_SYSTEM_REBOOT = 20,
+};
+
+static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
+                                  target_ulong args_real)
+{
+    AddressSpace *as = CPU(cpu)->as;
+    uint32_t token = ldl_be_phys(as, args_real);
+    uint32_t nargs = ldl_be_phys(as, args_real + 4);
+    uint32_t nrets = ldl_be_phys(as, args_real + 8);
+    uint32_t args = args_real + 12;
+    uint32_t rets = args_real + 12 + nargs * 4;
+
+    if (nrets < 1) {
+        qemu_log_mask(LOG_GUEST_ERROR, "Too few return values in RTAS call\n");
+        return H_PARAMETER;
+    }
+    switch (token) {
+    case RTAS_READ_PCI_CONFIG:
+    {
+        uint32_t addr, len, val;
+
+        if (nargs != 2 || nrets != 2) {
+            stl_be_phys(as, rets, -1);
+            return H_PARAMETER;
+        }
+        addr = ldl_be_phys(as, args);
+        len = ldl_be_phys(as, args + 4);
+        val = pegasos2_pci_config_read(as, !(addr >> 24),
+                                       addr & 0x0fffffff, len);
+        stl_be_phys(as, rets, 0);
+        stl_be_phys(as, rets + 4, val);
+        return H_SUCCESS;
+    }
+    case RTAS_WRITE_PCI_CONFIG:
+    {
+        uint32_t addr, len, val;
+
+        if (nargs != 3 || nrets != 1) {
+            stl_be_phys(as, rets, -1);
+            return H_PARAMETER;
+        }
+        addr = ldl_be_phys(as, args);
+        len = ldl_be_phys(as, args + 4);
+        val = ldl_be_phys(as, args + 8);
+        pegasos2_pci_config_write(as, !(addr >> 24),
+                                  addr & 0x0fffffff, len, val);
+        stl_be_phys(as, rets, 0);
+        return H_SUCCESS;
+    }
+    case RTAS_DISPLAY_CHARACTER:
+        if (nargs != 1 || nrets != 1) {
+            stl_be_phys(as, rets, -1);
+            return H_PARAMETER;
+        }
+        qemu_log_mask(LOG_UNIMP, "%c", ldl_be_phys(as, args));
+        stl_be_phys(as, rets, 0);
+        return H_SUCCESS;
+    default:
+        qemu_log_mask(LOG_UNIMP, "Unknown RTAS token %u (args=%u, rets=%u)\n",
+                      token, nargs, nrets);
+        stl_be_phys(as, rets, 0);
+        return H_SUCCESS;
+    }
+}
+
 static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
 {
     Pegasos2MachineState *pm = PEGASOS2_MACHINE(vhyp);
@@ -315,6 +421,8 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
     if (msr_pr) {
         qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=1\n");
         env->gpr[3] = H_PRIVILEGE;
+    } else if (env->gpr[3] == KVMPPC_H_RTAS) {
+        env->gpr[3] = pegasos2_rtas(cpu, pm, env->gpr[4]);
     } else if (env->gpr[3] == KVMPPC_H_VOF_CLIENT) {
         int ret = vof_client_call(MACHINE(pm), pm->vof, pm->fdt_blob,
                                   env->gpr[4]);
@@ -687,6 +795,35 @@ static void *build_fdt(MachineState *machine, int *fdt_size)
     qemu_fdt_setprop_string(fdt, "/failsafe", "device_type", "serial");
     qemu_fdt_setprop_string(fdt, "/failsafe", "name", "failsafe");
 
+    qemu_fdt_add_subnode(fdt, "/rtas");
+    qemu_fdt_setprop_cell(fdt, "/rtas", "system-reboot", RTAS_SYSTEM_REBOOT);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "hibernate", RTAS_HIBERNATE);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "suspend", RTAS_SUSPEND);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "power-off", RTAS_POWER_OFF);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "set-indicator", RTAS_SET_INDICATOR);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "display-character",
+                          RTAS_DISPLAY_CHARACTER);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "write-pci-config",
+                          RTAS_WRITE_PCI_CONFIG);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "read-pci-config",
+                          RTAS_READ_PCI_CONFIG);
+    /* Pegasos2 firmware misspells check-exception and guests use that */
+    qemu_fdt_setprop_cell(fdt, "/rtas", "check-execption",
+                          RTAS_CHECK_EXCEPTION);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "event-scan", RTAS_EVENT_SCAN);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "set-time-of-day",
+                          RTAS_SET_TIME_OF_DAY);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "get-time-of-day",
+                          RTAS_GET_TIME_OF_DAY);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-store", RTAS_NVRAM_STORE);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-fetch", RTAS_NVRAM_FETCH);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "restart-rtas", RTAS_RESTART_RTAS);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-error-log-max", 0);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-event-scan-rate", 0);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-display-device", 0);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", 20);
+    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-version", 1);
+
     /* cpus */
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "#cpus", 1);
-- 
2.21.4



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2 4/4] ppc/pegasos2: Implement some RTAS functions with VOF
  2021-07-08 21:46 [PATCH v2 4/4] ppc/pegasos2: Implement some RTAS functions with VOF BALATON Zoltan
@ 2021-07-09  0:40 ` David Gibson
  0 siblings, 0 replies; 2+ messages in thread
From: David Gibson @ 2021-07-09  0:40 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Alexey Kardashevskiy, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 8599 bytes --]

On Thu, Jul 08, 2021 at 11:46:14PM +0200, BALATON Zoltan wrote:
> Linux uses RTAS functions to access PCI devices so we need to provide
> these with VOF. Implement some of the most important functions to
> allow booting Linux with VOF. With this the board is now usable
> without a binary ROM image and we can enable it by default as other
> boards.
> 
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> ---
> v2: Use named values for /rtas functions, only sending v2 for this,
>     others are unchanged

Merged, replacing v1, thanks.

> 
>  default-configs/devices/ppc-softmmu.mak |   2 +-
>  hw/ppc/pegasos2.c                       | 137 ++++++++++++++++++++++++
>  2 files changed, 138 insertions(+), 1 deletion(-)
> 
> diff --git a/default-configs/devices/ppc-softmmu.mak b/default-configs/devices/ppc-softmmu.mak
> index c2d41198cd..4535993d8d 100644
> --- a/default-configs/devices/ppc-softmmu.mak
> +++ b/default-configs/devices/ppc-softmmu.mak
> @@ -14,7 +14,7 @@ CONFIG_SAM460EX=y
>  CONFIG_MAC_OLDWORLD=y
>  CONFIG_MAC_NEWWORLD=y
>  
> -CONFIG_PEGASOS2=n
> +CONFIG_PEGASOS2=y
>  
>  # For PReP
>  CONFIG_PREP=y
> diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
> index f1741a4512..5c4e2ae8bf 100644
> --- a/hw/ppc/pegasos2.c
> +++ b/hw/ppc/pegasos2.c
> @@ -43,6 +43,7 @@
>  #define PROM_SIZE     0x80000
>  
>  #define KVMPPC_HCALL_BASE    0xf000
> +#define KVMPPC_H_RTAS        (KVMPPC_HCALL_BASE + 0x0)
>  #define KVMPPC_H_VOF_CLIENT  (KVMPPC_HCALL_BASE + 0x5)
>  
>  #define H_SUCCESS     0
> @@ -195,6 +196,30 @@ static void pegasos2_init(MachineState *machine)
>      }
>  }
>  
> +static uint32_t pegasos2_pci_config_read(AddressSpace *as, int bus,
> +                                         uint32_t addr, uint32_t len)
> +{
> +    hwaddr pcicfg = (bus ? 0xf1000c78 : 0xf1000cf8);
> +    uint32_t val = 0xffffffff;
> +
> +    stl_le_phys(as, pcicfg, addr | BIT(31));
> +    switch (len) {
> +    case 4:
> +        val = ldl_le_phys(as, pcicfg + 4);
> +        break;
> +    case 2:
> +        val = lduw_le_phys(as, pcicfg + 4);
> +        break;
> +    case 1:
> +        val = ldub_phys(as, pcicfg + 4);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__);
> +        break;
> +    }
> +    return val;
> +}
> +
>  static void pegasos2_pci_config_write(AddressSpace *as, int bus, uint32_t addr,
>                                        uint32_t len, uint32_t val)
>  {
> @@ -304,6 +329,87 @@ static void pegasos2_machine_reset(MachineState *machine)
>      pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine);
>  }
>  
> +enum pegasos2_rtas_tokens {
> +    RTAS_RESTART_RTAS = 0,
> +    RTAS_NVRAM_FETCH = 1,
> +    RTAS_NVRAM_STORE = 2,
> +    RTAS_GET_TIME_OF_DAY = 3,
> +    RTAS_SET_TIME_OF_DAY = 4,
> +    RTAS_EVENT_SCAN = 6,
> +    RTAS_CHECK_EXCEPTION = 7,
> +    RTAS_READ_PCI_CONFIG = 8,
> +    RTAS_WRITE_PCI_CONFIG = 9,
> +    RTAS_DISPLAY_CHARACTER = 10,
> +    RTAS_SET_INDICATOR = 11,
> +    RTAS_POWER_OFF = 17,
> +    RTAS_SUSPEND = 18,
> +    RTAS_HIBERNATE = 19,
> +    RTAS_SYSTEM_REBOOT = 20,
> +};
> +
> +static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
> +                                  target_ulong args_real)
> +{
> +    AddressSpace *as = CPU(cpu)->as;
> +    uint32_t token = ldl_be_phys(as, args_real);
> +    uint32_t nargs = ldl_be_phys(as, args_real + 4);
> +    uint32_t nrets = ldl_be_phys(as, args_real + 8);
> +    uint32_t args = args_real + 12;
> +    uint32_t rets = args_real + 12 + nargs * 4;
> +
> +    if (nrets < 1) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "Too few return values in RTAS call\n");
> +        return H_PARAMETER;
> +    }
> +    switch (token) {
> +    case RTAS_READ_PCI_CONFIG:
> +    {
> +        uint32_t addr, len, val;
> +
> +        if (nargs != 2 || nrets != 2) {
> +            stl_be_phys(as, rets, -1);
> +            return H_PARAMETER;
> +        }
> +        addr = ldl_be_phys(as, args);
> +        len = ldl_be_phys(as, args + 4);
> +        val = pegasos2_pci_config_read(as, !(addr >> 24),
> +                                       addr & 0x0fffffff, len);
> +        stl_be_phys(as, rets, 0);
> +        stl_be_phys(as, rets + 4, val);
> +        return H_SUCCESS;
> +    }
> +    case RTAS_WRITE_PCI_CONFIG:
> +    {
> +        uint32_t addr, len, val;
> +
> +        if (nargs != 3 || nrets != 1) {
> +            stl_be_phys(as, rets, -1);
> +            return H_PARAMETER;
> +        }
> +        addr = ldl_be_phys(as, args);
> +        len = ldl_be_phys(as, args + 4);
> +        val = ldl_be_phys(as, args + 8);
> +        pegasos2_pci_config_write(as, !(addr >> 24),
> +                                  addr & 0x0fffffff, len, val);
> +        stl_be_phys(as, rets, 0);
> +        return H_SUCCESS;
> +    }
> +    case RTAS_DISPLAY_CHARACTER:
> +        if (nargs != 1 || nrets != 1) {
> +            stl_be_phys(as, rets, -1);
> +            return H_PARAMETER;
> +        }
> +        qemu_log_mask(LOG_UNIMP, "%c", ldl_be_phys(as, args));
> +        stl_be_phys(as, rets, 0);
> +        return H_SUCCESS;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "Unknown RTAS token %u (args=%u, rets=%u)\n",
> +                      token, nargs, nrets);
> +        stl_be_phys(as, rets, 0);
> +        return H_SUCCESS;
> +    }
> +}
> +
>  static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
>  {
>      Pegasos2MachineState *pm = PEGASOS2_MACHINE(vhyp);
> @@ -315,6 +421,8 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
>      if (msr_pr) {
>          qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=1\n");
>          env->gpr[3] = H_PRIVILEGE;
> +    } else if (env->gpr[3] == KVMPPC_H_RTAS) {
> +        env->gpr[3] = pegasos2_rtas(cpu, pm, env->gpr[4]);
>      } else if (env->gpr[3] == KVMPPC_H_VOF_CLIENT) {
>          int ret = vof_client_call(MACHINE(pm), pm->vof, pm->fdt_blob,
>                                    env->gpr[4]);
> @@ -687,6 +795,35 @@ static void *build_fdt(MachineState *machine, int *fdt_size)
>      qemu_fdt_setprop_string(fdt, "/failsafe", "device_type", "serial");
>      qemu_fdt_setprop_string(fdt, "/failsafe", "name", "failsafe");
>  
> +    qemu_fdt_add_subnode(fdt, "/rtas");
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "system-reboot", RTAS_SYSTEM_REBOOT);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "hibernate", RTAS_HIBERNATE);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "suspend", RTAS_SUSPEND);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "power-off", RTAS_POWER_OFF);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "set-indicator", RTAS_SET_INDICATOR);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "display-character",
> +                          RTAS_DISPLAY_CHARACTER);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "write-pci-config",
> +                          RTAS_WRITE_PCI_CONFIG);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "read-pci-config",
> +                          RTAS_READ_PCI_CONFIG);
> +    /* Pegasos2 firmware misspells check-exception and guests use that */
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "check-execption",
> +                          RTAS_CHECK_EXCEPTION);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "event-scan", RTAS_EVENT_SCAN);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "set-time-of-day",
> +                          RTAS_SET_TIME_OF_DAY);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "get-time-of-day",
> +                          RTAS_GET_TIME_OF_DAY);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-store", RTAS_NVRAM_STORE);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-fetch", RTAS_NVRAM_FETCH);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "restart-rtas", RTAS_RESTART_RTAS);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-error-log-max", 0);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-event-scan-rate", 0);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-display-device", 0);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", 20);
> +    qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-version", 1);
> +
>      /* cpus */
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#cpus", 1);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-07-09  0:45 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-08 21:46 [PATCH v2 4/4] ppc/pegasos2: Implement some RTAS functions with VOF BALATON Zoltan
2021-07-09  0:40 ` David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.