blob: cc46e7f731e47367a93e1a021f42799057a7c67f [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* PV diagnose 308 (IPL) tests
*
* Copyright (c) 2023 IBM Corp
*
* Authors:
* Janosch Frank <frankja@linux.ibm.com>
*/
#include <libcflat.h>
#include <sie.h>
#include <sclp.h>
#include <snippet.h>
#include <pv_icptdata.h>
#include <asm/facility.h>
#include <asm/uv.h>
static struct vm vm;
static void test_diag_308(int subcode)
{
extern const char SNIPPET_NAME_START(asm, pv_diag_308)[];
extern const char SNIPPET_NAME_END(asm, pv_diag_308)[];
extern const char SNIPPET_HDR_START(asm, pv_diag_308)[];
extern const char SNIPPET_HDR_END(asm, pv_diag_308)[];
int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_308);
int size_gbin = SNIPPET_LEN(asm, pv_diag_308);
uint16_t rc, rrc;
int cc;
report_prefix_pushf("subcode %d", subcode);
snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_308),
SNIPPET_HDR_START(asm, pv_diag_308),
size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
/* First exit is a diag 0x500 */
sie(&vm);
assert(pv_icptdata_check_diag(&vm, 0x500));
/*
* The snippet asked us for the subcode and we answer by
* putting the value in gr2.
* SIE will copy gr2 to the guest
*/
vm.save_area.guest.grs[2] = subcode;
/* Continue after diag 0x500, next icpt should be the 0x308 */
sie(&vm);
assert(pv_icptdata_check_diag(&vm, 0x308));
assert(vm.save_area.guest.grs[2] == subcode);
/*
* We need to perform several UV calls to emulate the subcode
* 0/1. Failing to do that should result in a validity.
*
* - Mark all cpus as stopped
* - Unshare all memory
* - Prepare the reset
* - Reset the cpus
* - Load the reset PSW
*/
sie_expect_validity(&vm);
sie(&vm);
report(uv_validity_check(&vm), "validity, no action");
/* Mark the CPU as stopped so we can unshare and reset */
cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_STP);
report(!cc, "Set cpu stopped");
sie_expect_validity(&vm);
sie(&vm);
report(uv_validity_check(&vm), "validity, stopped");
/* Unshare all memory */
cc = uv_cmd_nodata(vm.sblk->pv_handle_config,
UVC_CMD_SET_UNSHARED_ALL, &rc, &rrc);
report(cc == 0 && rc == 1, "Unshare all");
sie_expect_validity(&vm);
sie(&vm);
report(uv_validity_check(&vm), "validity, stopped, unshared");
/* Prepare the CPU reset */
cc = uv_cmd_nodata(vm.sblk->pv_handle_config,
UVC_CMD_PREPARE_RESET, &rc, &rrc);
report(cc == 0 && rc == 1, "Prepare reset call");
sie_expect_validity(&vm);
sie(&vm);
report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset");
/*
* Do the reset on the initiating cpu
*
* Reset clear for subcode 0
* Reset initial for subcode 1
*/
if (subcode == 0) {
cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu,
UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc);
report(cc == 0 && rc == 1, "Clear reset cpu");
} else {
cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu,
UVC_CMD_CPU_RESET_INITIAL, &rc, &rrc);
report(cc == 0 && rc == 1, "Initial reset cpu");
}
sie_expect_validity(&vm);
sie(&vm);
report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset, cpu reset");
/* Load the PSW from 0x0 */
cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_OPR_LOAD);
report(!cc, "Set cpu load");
/*
* Check if we executed the iaddr of the reset PSW, we should
* see a diagnose 0x9c PV instruction notification.
*/
sie(&vm);
report(pv_icptdata_check_diag(&vm, 0x9c) &&
vm.save_area.guest.grs[0] == 42,
"continue after load");
uv_destroy_guest(&vm);
report_prefix_pop();
}
int main(void)
{
report_prefix_push("uv-sie");
if (!uv_host_requirement_checks())
goto done;
snippet_setup_guest(&vm, true);
test_diag_308(0);
test_diag_308(1);
sie_guest_destroy(&vm);
done:
report_prefix_pop();
return report_summary();
}