162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/compat.h>
462306a36Sopenharmony_ci#include <linux/ptrace.h>
562306a36Sopenharmony_ci#include <asm/cio.h>
662306a36Sopenharmony_ci#include <asm/asm-offsets.h>
762306a36Sopenharmony_ci#include "boot.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define CCW0(cmd, addr, cnt, flg) \
1062306a36Sopenharmony_ci	{ .cmd_code = cmd, .cda = addr, .count = cnt, .flags = flg, }
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define PSW_MASK_DISABLED (PSW_MASK_WAIT | PSW_MASK_EA | PSW_MASK_BA)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct ipl_lowcore {
1562306a36Sopenharmony_ci	psw_t32		ipl_psw;			/* 0x0000 */
1662306a36Sopenharmony_ci	struct ccw0	ccwpgm[2];			/* 0x0008 */
1762306a36Sopenharmony_ci	u8		fill[56];			/* 0x0018 */
1862306a36Sopenharmony_ci	struct ccw0	ccwpgmcc[20];			/* 0x0050 */
1962306a36Sopenharmony_ci	u8		pad_0xf0[0x01a0-0x00f0];	/* 0x00f0 */
2062306a36Sopenharmony_ci	psw_t		restart_psw;			/* 0x01a0 */
2162306a36Sopenharmony_ci	psw_t		external_new_psw;		/* 0x01b0 */
2262306a36Sopenharmony_ci	psw_t		svc_new_psw;			/* 0x01c0 */
2362306a36Sopenharmony_ci	psw_t		program_new_psw;		/* 0x01d0 */
2462306a36Sopenharmony_ci	psw_t		mcck_new_psw;			/* 0x01e0 */
2562306a36Sopenharmony_ci	psw_t		io_new_psw;			/* 0x01f0 */
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * Initial lowcore for IPL: the first 24 bytes are loaded by IPL to
3062306a36Sopenharmony_ci * addresses 0-23 (a PSW and two CCWs). Bytes 24-79 are discarded.
3162306a36Sopenharmony_ci * The next 160 bytes are loaded to addresses 0x18-0xb7. They form
3262306a36Sopenharmony_ci * the continuation of the CCW program started by IPL and load the
3362306a36Sopenharmony_ci * range 0x0f0-0x730 from the image to the range 0x0f0-0x730 in
3462306a36Sopenharmony_ci * memory. At the end of the channel program the PSW at location 0 is
3562306a36Sopenharmony_ci * loaded.
3662306a36Sopenharmony_ci * Initial processing starts at 0x200 = iplstart.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * The restart psw points to iplstart which allows to load a kernel
3962306a36Sopenharmony_ci * image into memory and starting it by a psw restart on any cpu. All
4062306a36Sopenharmony_ci * other default psw new locations contain a disabled wait psw where
4162306a36Sopenharmony_ci * the address indicates which psw was loaded.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Note that the 'file' utility can detect s390 kernel images. For
4462306a36Sopenharmony_ci * that to succeed the two initial CCWs, and the 0x40 fill bytes must
4562306a36Sopenharmony_ci * be present.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic struct ipl_lowcore ipl_lowcore __used __section(".ipldata") = {
4862306a36Sopenharmony_ci	.ipl_psw = { .mask = PSW32_MASK_BASE, .addr = PSW32_ADDR_AMODE | IPL_START },
4962306a36Sopenharmony_ci	.ccwpgm = {
5062306a36Sopenharmony_ci		[ 0] = CCW0(CCW_CMD_READ_IPL, 0x018, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
5162306a36Sopenharmony_ci		[ 1] = CCW0(CCW_CMD_READ_IPL, 0x068, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
5262306a36Sopenharmony_ci	},
5362306a36Sopenharmony_ci	.fill = {
5462306a36Sopenharmony_ci		[ 0 ... 55] = 0x40,
5562306a36Sopenharmony_ci	},
5662306a36Sopenharmony_ci	.ccwpgmcc = {
5762306a36Sopenharmony_ci		[ 0] = CCW0(CCW_CMD_READ_IPL, 0x0f0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
5862306a36Sopenharmony_ci		[ 1] = CCW0(CCW_CMD_READ_IPL, 0x140, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
5962306a36Sopenharmony_ci		[ 2] = CCW0(CCW_CMD_READ_IPL, 0x190, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6062306a36Sopenharmony_ci		[ 3] = CCW0(CCW_CMD_READ_IPL, 0x1e0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6162306a36Sopenharmony_ci		[ 4] = CCW0(CCW_CMD_READ_IPL, 0x230, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6262306a36Sopenharmony_ci		[ 5] = CCW0(CCW_CMD_READ_IPL, 0x280, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6362306a36Sopenharmony_ci		[ 6] = CCW0(CCW_CMD_READ_IPL, 0x2d0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6462306a36Sopenharmony_ci		[ 7] = CCW0(CCW_CMD_READ_IPL, 0x320, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6562306a36Sopenharmony_ci		[ 8] = CCW0(CCW_CMD_READ_IPL, 0x370, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6662306a36Sopenharmony_ci		[ 9] = CCW0(CCW_CMD_READ_IPL, 0x3c0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6762306a36Sopenharmony_ci		[10] = CCW0(CCW_CMD_READ_IPL, 0x410, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6862306a36Sopenharmony_ci		[11] = CCW0(CCW_CMD_READ_IPL, 0x460, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
6962306a36Sopenharmony_ci		[12] = CCW0(CCW_CMD_READ_IPL, 0x4b0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7062306a36Sopenharmony_ci		[13] = CCW0(CCW_CMD_READ_IPL, 0x500, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7162306a36Sopenharmony_ci		[14] = CCW0(CCW_CMD_READ_IPL, 0x550, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7262306a36Sopenharmony_ci		[15] = CCW0(CCW_CMD_READ_IPL, 0x5a0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7362306a36Sopenharmony_ci		[16] = CCW0(CCW_CMD_READ_IPL, 0x5f0, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7462306a36Sopenharmony_ci		[17] = CCW0(CCW_CMD_READ_IPL, 0x640, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7562306a36Sopenharmony_ci		[18] = CCW0(CCW_CMD_READ_IPL, 0x690, 0x50, CCW_FLAG_SLI | CCW_FLAG_CC),
7662306a36Sopenharmony_ci		[19] = CCW0(CCW_CMD_READ_IPL, 0x6e0, 0x50, CCW_FLAG_SLI),
7762306a36Sopenharmony_ci	},
7862306a36Sopenharmony_ci	.restart_psw	  = { .mask = 0, .addr = IPL_START, },
7962306a36Sopenharmony_ci	.external_new_psw = { .mask = PSW_MASK_DISABLED, .addr = __LC_EXT_NEW_PSW, },
8062306a36Sopenharmony_ci	.svc_new_psw	  = { .mask = PSW_MASK_DISABLED, .addr = __LC_SVC_NEW_PSW, },
8162306a36Sopenharmony_ci	.program_new_psw  = { .mask = PSW_MASK_DISABLED, .addr = __LC_PGM_NEW_PSW, },
8262306a36Sopenharmony_ci	.mcck_new_psw	  = { .mask = PSW_MASK_DISABLED, .addr = __LC_MCK_NEW_PSW, },
8362306a36Sopenharmony_ci	.io_new_psw	  = { .mask = PSW_MASK_DISABLED, .addr = __LC_IO_NEW_PSW, },
8462306a36Sopenharmony_ci};
85