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
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
;
39 mutex_init(&sys
->virt_devs_lock
, &virt_devs_lc
);
40 INIT_LIST_HEAD(&sys
->virt_devs
);
42 mutex_lock(&sys
->virt_devs_lock
);
45 list_for_each_entry(cur
, &sys
->directory
->devices
, list
) {
46 ret
= alloc_virt_dev(sys
, cur
, 0x10000 + i
);
48 con_printf(sys
->con
, "Failed to allocate vdev %04X, "
49 "SCH = %05X (%s)\n", cur
->vdev
, 0x10000 + 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
;
62 INIT_LIST_HEAD(&sys
->guest_pages
);
65 p
= alloc_pages(0, ZONE_NORMAL
);
69 list_add(&p
->guest
, &sys
->guest_pages
);
73 dat_insert_page(&sys
->as
, (u64
) page_to_addr(p
),
80 static void free_vcpu(struct virt_sys
*sys
)
82 struct virt_cpu
*cpu
= sys
->cpu
;
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]));
102 static int alloc_vcpu(struct virt_sys
*sys
)
104 char tname
[TASK_NAME_LEN
+1];
105 struct virt_cpu
*cpu
;
109 page
= alloc_pages(0, ZONE_NORMAL
);
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;
132 cpu
->sie_cb
.eca
= 0xC1002001U
;
134 * TODO: What about ->scaoh and ->scaol?
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
);
151 static int alloc_console(struct virt_cons
*con
)
156 con
->wlines
= alloc_spool();
157 if (IS_ERR(con
->wlines
)) {
158 ret
= PTR_ERR(con
->wlines
);
162 con
->rlines
= alloc_spool();
163 if (IS_ERR(con
->rlines
)) {
164 ret
= PTR_ERR(con
->rlines
);
168 page
= alloc_pages(0, ZONE_NORMAL
);
174 con
->bigbuf
= page_to_addr(page
);
179 free_spool(con
->rlines
);
181 free_spool(con
->wlines
);
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
,
196 struct virt_sys
*sys
;
197 bool already_online
= false;
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;
208 mutex_unlock(&online_users_lock
);
213 sys
= malloc(sizeof(struct virt_sys
), ZONE_NORMAL
);
217 init_circbuf(&sys
->crws
, struct crw
, NUM_CRWS
);
219 if (alloc_console(&sys
->console
))
222 sys
->con
= &sys
->console
;
223 sys
->con
->dev
= rcon
;
225 sys
->directory
= find_user_by_id(name
);
226 if (IS_ERR(sys
->directory
))
229 alloc_guest_devices(sys
);
231 ret
= alloc_guest_storage(sys
);
234 ret
= alloc_vcpu(sys
);
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
);
248 free_console(&sys
->console
);
254 void list_users(struct virt_cons
*con
, void (*f
)(struct virt_cons
*con
,
255 struct virt_sys
*sys
))
257 struct virt_sys
*sys
;
262 mutex_lock(&online_users_lock
);
263 list_for_each_entry(sys
, &online_users
, online_users
)
265 mutex_unlock(&online_users_lock
);