]> git.proxmox.com Git - mirror_qemu.git/blob - pc-bios/s390-ccw/netmain.c
pc-bios/s390-ccw: Add core files for the network bootloading program
[mirror_qemu.git] / pc-bios / s390-ccw / netmain.c
1 /*
2 * S390 virtio-ccw network boot loading program
3 *
4 * Copyright 2017 Thomas Huth, Red Hat Inc.
5 *
6 * Based on the S390 virtio-ccw loading program (main.c)
7 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
8 *
9 * This code is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14
15 #include <stdint.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <time.h>
22
23 #include "s390-ccw.h"
24 #include "virtio.h"
25
26 extern char _start[];
27
28 char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
29 IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
30
31 static SubChannelId net_schid = { .one = 1 };
32 static uint64_t dest_timer;
33
34 static uint64_t get_timer_ms(void)
35 {
36 uint64_t clk;
37
38 asm volatile(" stck %0 " : : "Q"(clk) : "memory");
39
40 /* Bit 51 is incremented each microsecond */
41 return (clk >> (63 - 51)) / 1000;
42 }
43
44 void set_timer(int val)
45 {
46 dest_timer = get_timer_ms() + val;
47 }
48
49 int get_timer(void)
50 {
51 return dest_timer - get_timer_ms();
52 }
53
54 int get_sec_ticks(void)
55 {
56 return 1000; /* number of ticks in 1 second */
57 }
58
59 void panic(const char *string)
60 {
61 sclp_print(string);
62 for (;;) {
63 disabled_wait();
64 }
65 }
66
67 static bool find_net_dev(Schib *schib, int dev_no)
68 {
69 int i, r;
70
71 for (i = 0; i < 0x10000; i++) {
72 net_schid.sch_no = i;
73 r = stsch_err(net_schid, schib);
74 if (r == 3 || r == -EIO) {
75 break;
76 }
77 if (!schib->pmcw.dnv) {
78 continue;
79 }
80 if (!virtio_is_supported(net_schid)) {
81 continue;
82 }
83 if (virtio_get_device_type() != VIRTIO_ID_NET) {
84 continue;
85 }
86 if (dev_no < 0 || schib->pmcw.dev == dev_no) {
87 return true;
88 }
89 }
90
91 return false;
92 }
93
94 static void virtio_setup(void)
95 {
96 Schib schib;
97 int ssid;
98 bool found = false;
99 uint16_t dev_no;
100
101 /*
102 * We unconditionally enable mss support. In every sane configuration,
103 * this will succeed; and even if it doesn't, stsch_err() can deal
104 * with the consequences.
105 */
106 enable_mss_facility();
107
108 if (store_iplb(&iplb)) {
109 IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
110 dev_no = iplb.ccw.devno;
111 debug_print_int("device no. ", dev_no);
112 net_schid.ssid = iplb.ccw.ssid & 0x3;
113 debug_print_int("ssid ", net_schid.ssid);
114 found = find_net_dev(&schib, dev_no);
115 } else {
116 for (ssid = 0; ssid < 0x3; ssid++) {
117 net_schid.ssid = ssid;
118 found = find_net_dev(&schib, -1);
119 if (found) {
120 break;
121 }
122 }
123 }
124
125 IPL_assert(found, "No virtio net device found");
126 }
127
128 void main(void)
129 {
130 sclp_setup();
131 sclp_print("Network boot starting...\n");
132
133 virtio_setup();
134
135 panic("Failed to load OS from network\n");
136 }