blob: e403b5f733e4cc54a32f67a1b155063242e68ee4 [file] [log] [blame]
Alexander Graf92f2ca32013-04-22 20:57:58 +02001/*
2 * S390 virtio-ccw loading program
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
7 * your option) any later version. See the COPYING file in the top-level
8 * directory.
9 */
10
Thomas Huth90806fe2017-07-12 14:49:43 +020011#include "libc.h"
Jason J. Hernec95df3d2019-04-04 10:34:25 -040012#include "s390-arch.h"
Alexander Graf92f2ca32013-04-22 20:57:58 +020013#include "s390-ccw.h"
Jason J. Herne120d0412019-04-04 10:34:24 -040014#include "cio.h"
Eugene (jno) Dvurechenski60612d52014-05-19 20:11:07 +020015#include "virtio.h"
Alexander Graf92f2ca32013-04-22 20:57:58 +020016
Alexander Graf92f2ca32013-04-22 20:57:58 +020017char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010018static SubChannelId blk_schid = { .one = 1 };
Collin Wallinga0e11b62018-05-29 00:40:09 -040019static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Collin L. Walling118ee802018-02-23 10:43:11 -050020QemuIplParameters qipl;
Jason J. Hernea5f6e092019-04-04 10:34:22 -040021IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
22static bool have_iplb;
Jason J. Hernec95df3d2019-04-04 10:34:25 -040023LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
Christian Borntraegerf2879a52014-07-01 12:17:41 +020024
Collin L. Walling9eaa6542018-02-23 10:43:13 -050025#define LOADPARM_PROMPT "PROMPT "
Collin Walling074afe62018-04-16 12:56:08 -040026#define LOADPARM_EMPTY " "
Collin L. Walling53b310c2018-02-23 10:43:18 -050027#define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
Collin L. Walling9eaa6542018-02-23 10:43:13 -050028
Christian Borntraegerf2879a52014-07-01 12:17:41 +020029/*
Jason J. Hernea5f6e092019-04-04 10:34:22 -040030 * Principles of Operations (SA22-7832-09) chapter 17 requires that
Christian Borntraegerf2879a52014-07-01 12:17:41 +020031 * a subsystem-identification is at 184-187 and bytes 188-191 are zero
32 * after list-directed-IPL and ccw-IPL.
33 */
34void write_subsystem_identification(void)
35{
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010036 SubChannelId *schid = (SubChannelId *) 184;
Christian Borntraegerf2879a52014-07-01 12:17:41 +020037 uint32_t *zeroes = (uint32_t *) 188;
38
39 *schid = blk_schid;
40 *zeroes = 0;
41}
42
Eugene (jno) Dvurechenskic9262e82015-09-17 12:47:27 +020043void panic(const char *string)
Alexander Graf92f2ca32013-04-22 20:57:58 +020044{
45 sclp_print(string);
Christian Borntraeger7f61cbc2013-04-23 01:23:02 +000046 disabled_wait();
Alexander Graf92f2ca32013-04-22 20:57:58 +020047 while (1) { }
48}
49
Farhan Ali95fa1af2017-01-16 10:45:49 -050050unsigned int get_loadparm_index(void)
51{
Collin Walling074afe62018-04-16 12:56:08 -040052 return atoui(loadparm_str);
Farhan Ali95fa1af2017-01-16 10:45:49 -050053}
54
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010055static bool find_dev(Schib *schib, int dev_no)
Alexander Graf92f2ca32013-04-22 20:57:58 +020056{
Alexander Yarygin0f79b892015-06-25 18:35:58 +030057 int i, r;
Dominik Dingelff151f42013-04-30 07:15:58 +000058
Alexander Graf92f2ca32013-04-22 20:57:58 +020059 for (i = 0; i < 0x10000; i++) {
60 blk_schid.sch_no = i;
Alexander Yarygin0f79b892015-06-25 18:35:58 +030061 r = stsch_err(blk_schid, schib);
62 if ((r == 3) || (r == -EIO)) {
Cornelia Huck22d67ab2013-04-26 02:12:52 +000063 break;
64 }
Alexander Yarygin0f79b892015-06-25 18:35:58 +030065 if (!schib->pmcw.dnv) {
66 continue;
67 }
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +010068 if (!virtio_is_supported(blk_schid)) {
Alexander Yarygin0f79b892015-06-25 18:35:58 +030069 continue;
70 }
Farhan Ali99b72e02016-11-01 17:34:00 -040071 /* Skip net devices since no IPLB is created and therefore no
72 * no network bootloader has been loaded
73 */
74 if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
75 continue;
76 }
Alexander Yarygin0f79b892015-06-25 18:35:58 +030077 if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
78 return true;
79 }
80 }
81
82 return false;
83}
84
Collin L. Walling9eaa6542018-02-23 10:43:13 -050085static void menu_setup(void)
86{
Collin Wallinga0e11b62018-05-29 00:40:09 -040087 if (memcmp(loadparm_str, LOADPARM_PROMPT, LOADPARM_LEN) == 0) {
Collin L. Walling9eaa6542018-02-23 10:43:13 -050088 menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0);
89 return;
90 }
91
92 /* If loadparm was set to any other value, then do not enable menu */
Collin Wallinga0e11b62018-05-29 00:40:09 -040093 if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
Collin L. Walling9eaa6542018-02-23 10:43:13 -050094 return;
95 }
96
97 switch (iplb.pbt) {
98 case S390_IPL_TYPE_CCW:
Collin L. Wallingffb4a1c2018-02-23 10:43:19 -050099 case S390_IPL_TYPE_QEMU_SCSI:
Collin L. Walling53b310c2018-02-23 10:43:18 -0500100 menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
Collin L. Walling9eaa6542018-02-23 10:43:13 -0500101 qipl.boot_menu_timeout);
102 return;
103 }
104}
105
Jason J. Herne87f910c2019-04-04 10:34:21 -0400106/*
107 * Initialize the channel I/O subsystem so we can talk to our ipl/boot device.
108 */
109static void css_setup(void)
110{
111 /*
112 * Unconditionally enable mss support. In every sane configuration this
113 * will succeed; and even if it doesn't, stsch_err() can handle it.
114 */
115 enable_mss_facility();
116}
117
Jason J. Hernea5f6e092019-04-04 10:34:22 -0400118/*
119 * Collect various pieces of information from the hypervisor/hardware that
120 * we'll use to determine exactly how we'll boot.
121 */
122static void boot_setup(void)
123{
124 char lpmsg[] = "LOADPARM=[________]\n";
125
126 sclp_get_loadparm_ascii(loadparm_str);
127 memcpy(lpmsg + 10, loadparm_str, 8);
128 sclp_print(lpmsg);
129
130 have_iplb = store_iplb(&iplb);
131}
132
Alexander Yarygind046c512015-07-31 17:04:51 +0300133static void virtio_setup(void)
Alexander Yarygin0f79b892015-06-25 18:35:58 +0300134{
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +0100135 Schib schib;
Alexander Yarygin0f79b892015-06-25 18:35:58 +0300136 int ssid;
137 bool found = false;
138 uint16_t dev_no;
Farhan Ali99b72e02016-11-01 17:34:00 -0400139 VDev *vdev = virtio_get_device();
Collin L. Walling118ee802018-02-23 10:43:11 -0500140 QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
Alexander Yarygin0f79b892015-06-25 18:35:58 +0300141
Collin L. Walling118ee802018-02-23 10:43:11 -0500142 memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
143
Jason J. Hernea5f6e092019-04-04 10:34:22 -0400144 if (have_iplb) {
Alexander Yarygind046c512015-07-31 17:04:51 +0300145 switch (iplb.pbt) {
146 case S390_IPL_TYPE_CCW:
147 dev_no = iplb.ccw.devno;
148 debug_print_int("device no. ", dev_no);
149 blk_schid.ssid = iplb.ccw.ssid & 0x3;
150 debug_print_int("ssid ", blk_schid.ssid);
151 found = find_dev(&schib, dev_no);
152 break;
Eugene (jno) Dvurechenskib39b7712016-06-01 15:25:51 +0200153 case S390_IPL_TYPE_QEMU_SCSI:
Eugene (jno) Dvurechenskib39b7712016-06-01 15:25:51 +0200154 vdev->scsi_device_selected = true;
155 vdev->selected_scsi_device.channel = iplb.scsi.channel;
156 vdev->selected_scsi_device.target = iplb.scsi.target;
157 vdev->selected_scsi_device.lun = iplb.scsi.lun;
158 blk_schid.ssid = iplb.scsi.ssid & 0x3;
159 found = find_dev(&schib, iplb.scsi.devno);
160 break;
Alexander Yarygind046c512015-07-31 17:04:51 +0300161 default:
162 panic("List-directed IPL not supported yet!\n");
163 }
Collin L. Walling9eaa6542018-02-23 10:43:13 -0500164 menu_setup();
Alexander Yarygin0f79b892015-06-25 18:35:58 +0300165 } else {
166 for (ssid = 0; ssid < 0x3; ssid++) {
167 blk_schid.ssid = ssid;
168 found = find_dev(&schib, -1);
169 if (found) {
170 break;
Alexander Graf92f2ca32013-04-22 20:57:58 +0200171 }
172 }
173 }
174
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100175 IPL_assert(found, "No virtio device found");
Alexander Graf92f2ca32013-04-22 20:57:58 +0200176
Farhan Ali99b72e02016-11-01 17:34:00 -0400177 if (virtio_get_device_type() == VIRTIO_ID_NET) {
178 sclp_print("Network boot device detected\n");
Collin L. Walling118ee802018-02-23 10:43:11 -0500179 vdev->netboot_start_addr = qipl.netboot_start_addr;
Farhan Ali99b72e02016-11-01 17:34:00 -0400180 } else {
Thomas Huth867e0392017-07-12 14:49:45 +0200181 virtio_blk_setup_device(blk_schid);
Eugene (jno) Dvurechenski60612d52014-05-19 20:11:07 +0200182
Farhan Ali99b72e02016-11-01 17:34:00 -0400183 IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
184 }
Alexander Graf92f2ca32013-04-22 20:57:58 +0200185}
186
187int main(void)
188{
189 sclp_setup();
Jason J. Herne87f910c2019-04-04 10:34:21 -0400190 css_setup();
Jason J. Hernea5f6e092019-04-04 10:34:22 -0400191 boot_setup();
Alexander Yarygind046c512015-07-31 17:04:51 +0300192 virtio_setup();
Dominik Dingelff151f42013-04-30 07:15:58 +0000193
Eugene (jno) Dvurechenski60612d52014-05-19 20:11:07 +0200194 zipl_load(); /* no return */
195
Eugene (jno) Dvurechenskic9262e82015-09-17 12:47:27 +0200196 panic("Failed to load OS from hard disk\n");
Eugene (jno) Dvurechenski60612d52014-05-19 20:11:07 +0200197 return 0; /* make compiler happy */
Alexander Graf92f2ca32013-04-22 20:57:58 +0200198}