loader: remove shouting from ORB's variable name
[hvf.git] / cp / guest / init.c
blob9bba61ee2d57cd4fee00adb02500526ad08027b9
1 /*
2 * (C) Copyright 2007-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <directory.h>
9 #include <sched.h>
10 #include <errno.h>
11 #include <page.h>
12 #include <buddy.h>
13 #include <slab.h>
14 #include <dat.h>
15 #include <clock.h>
16 #include <ebcdic.h>
17 #include <cpu.h>
18 #include <vcpu.h>
19 #include <vdevice.h>
20 #include <mutex.h>
21 #include <vsprintf.h>
22 #include <shell.h>
23 #include <guest.h>
25 static LOCK_CLASS(online_users_lc);
26 static LIST_HEAD(online_users);
27 static UNLOCKED_MUTEX(online_users_lock, &online_users_lc);
29 static LOCK_CLASS(guest_interrupt_queue_lc);
31 static LOCK_CLASS(virt_devs_lc);
33 static void alloc_guest_devices(struct virt_sys *sys)
35 struct directory_vdev *cur;
36 int ret;
37 int i;
39 mutex_init(&sys->virt_devs_lock, &virt_devs_lc);
40 INIT_LIST_HEAD(&sys->virt_devs);
42 mutex_lock(&sys->virt_devs_lock);
44 i = 0;
45 list_for_each_entry(cur, &sys->directory->devices, list) {
46 ret = alloc_virt_dev(sys, cur, 0x10000 + i);
47 if (ret)
48 con_printf(sys->con, "Failed to allocate vdev %04X, "
49 "SCH = %05X (%s)\n", cur->vdev, 0x10000 + i,
50 errstrings[-ret]);
51 i++;
54 mutex_unlock(&sys->virt_devs_lock);
57 static int alloc_guest_storage(struct virt_sys *sys)
59 u64 pages = sys->directory->storage_size >> PAGE_SHIFT;
60 struct page *p;
62 INIT_LIST_HEAD(&sys->guest_pages);
64 while (pages) {
65 p = alloc_pages(0, ZONE_NORMAL);
66 if (!p)
67 return -ENOMEM;
69 list_add(&p->guest, &sys->guest_pages);
71 pages--;
73 dat_insert_page(&sys->as, (u64) page_to_addr(p),
74 pages << PAGE_SHIFT);
77 return 0;
80 static void free_vcpu(struct virt_sys *sys)
82 struct virt_cpu *cpu = sys->cpu;
84 if (sys->task) {
85 FIXME("kill the vcpu task");
88 assert(list_empty(&cpu->int_io[0]));
89 assert(list_empty(&cpu->int_io[1]));
90 assert(list_empty(&cpu->int_io[2]));
91 assert(list_empty(&cpu->int_io[3]));
92 assert(list_empty(&cpu->int_io[4]));
93 assert(list_empty(&cpu->int_io[5]));
94 assert(list_empty(&cpu->int_io[6]));
95 assert(list_empty(&cpu->int_io[7]));
97 free_pages(cpu, 0);
99 sys->cpu = NULL;
102 static int alloc_vcpu(struct virt_sys *sys)
104 char tname[TASK_NAME_LEN+1];
105 struct virt_cpu *cpu;
106 struct page *page;
107 int ret;
109 page = alloc_pages(0, ZONE_NORMAL);
110 if (!page)
111 return -ENOMEM;
113 cpu = page_to_addr(page);
115 memset(cpu, 0, PAGE_SIZE);
116 mutex_init(&cpu->int_lock, &guest_interrupt_queue_lc);
117 INIT_LIST_HEAD(&cpu->int_io[0]);
118 INIT_LIST_HEAD(&cpu->int_io[1]);
119 INIT_LIST_HEAD(&cpu->int_io[2]);
120 INIT_LIST_HEAD(&cpu->int_io[3]);
121 INIT_LIST_HEAD(&cpu->int_io[4]);
122 INIT_LIST_HEAD(&cpu->int_io[5]);
123 INIT_LIST_HEAD(&cpu->int_io[6]);
124 INIT_LIST_HEAD(&cpu->int_io[7]);
126 cpu->cpuid = getcpuid() | 0xFF00000000000000ULL;
128 cpu->sie_cb.gmsor = 0;
129 cpu->sie_cb.gmslm = sys->directory->storage_size;
130 cpu->sie_cb.gbea = 1;
131 cpu->sie_cb.ecb = 2;
132 cpu->sie_cb.eca = 0xC1002001U;
134 * TODO: What about ->scaoh and ->scaol?
137 sys->cpu = cpu;
139 snprintf(tname, 32, "%s-vcpu0", sysconf.oper_userid);
140 sys->task = create_task(tname, shell_start, sys);
141 if (IS_ERR(sys->task)) {
142 ret = PTR_ERR(sys->task);
143 sys->task = NULL;
144 free_vcpu(sys);
145 return ret;
148 return 0;
151 static int alloc_console(struct virt_cons *con)
153 struct page *page;
154 int ret;
156 con->wlines = alloc_spool();
157 if (IS_ERR(con->wlines)) {
158 ret = PTR_ERR(con->wlines);
159 goto out;
162 con->rlines = alloc_spool();
163 if (IS_ERR(con->rlines)) {
164 ret = PTR_ERR(con->rlines);
165 goto out_free;
168 page = alloc_pages(0, ZONE_NORMAL);
169 if (!page) {
170 ret = -ENOMEM;
171 goto out_free2;
174 con->bigbuf = page_to_addr(page);
176 return 0;
178 out_free2:
179 free_spool(con->rlines);
180 out_free:
181 free_spool(con->wlines);
182 out:
183 return ret;
186 static void free_console(struct virt_cons *con)
188 free_spool(con->rlines);
189 free_spool(con->wlines);
190 free_pages(con->bigbuf, 0);
193 struct virt_sys *guest_create(char *name, struct device *rcon,
194 bool internal_guest)
196 struct virt_sys *sys;
197 bool already_online = false;
198 int ret;
200 /* first, check that we're not already online */
201 mutex_lock(&online_users_lock);
202 list_for_each_entry(sys, &online_users, online_users) {
203 if (!strcmp(sys->directory->userid, name)) {
204 already_online = true;
205 break;
208 mutex_unlock(&online_users_lock);
210 if (already_online)
211 return NULL;
213 sys = malloc(sizeof(struct virt_sys), ZONE_NORMAL);
214 if (!sys)
215 return NULL;
217 init_circbuf(&sys->crws, struct crw, NUM_CRWS);
219 if (alloc_console(&sys->console))
220 goto free;
222 sys->con = &sys->console;
223 sys->con->dev = rcon;
225 sys->directory = find_user_by_id(name);
226 if (IS_ERR(sys->directory))
227 goto free_cons;
229 alloc_guest_devices(sys);
231 ret = alloc_guest_storage(sys);
232 assert(!ret);
234 ret = alloc_vcpu(sys);
235 assert(!ret);
237 sys->internal = internal_guest;
238 sys->print_ts = true; /* print timestamps */
239 sys->print_name = internal_guest; /* print names */
241 mutex_lock(&online_users_lock);
242 list_add_tail(&sys->online_users, &online_users);
243 mutex_unlock(&online_users_lock);
245 return sys;
247 free_cons:
248 free_console(&sys->console);
249 free:
250 free(sys);
251 return NULL;
254 void list_users(struct virt_cons *con, void (*f)(struct virt_cons *con,
255 struct virt_sys *sys))
257 struct virt_sys *sys;
259 if (!f)
260 return;
262 mutex_lock(&online_users_lock);
263 list_for_each_entry(sys, &online_users, online_users)
264 f(con, sys);
265 mutex_unlock(&online_users_lock);