aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2012-11-30 09:32:27 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2012-11-30 09:32:27 +0000
commit5088edf797252b470d1e74f9125fae29fc026911 (patch)
tree8a410432b43e3486e334af8d09ddbe29cd36d99f /extras
parente71632467f29cbb214f50352ee6216da8c1a7cab (diff)
downloadxen-5088edf797252b470d1e74f9125fae29fc026911.tar.gz
xen-5088edf797252b470d1e74f9125fae29fc026911.tar.bz2
xen-5088edf797252b470d1e74f9125fae29fc026911.zip
[minios] Add xenbus shutdown control support
Add a thread watching the xenbus shutdown control path and notifies a wait queue. Add HYPERVISOR_shutdown convenient inline for minios shutdown. Add proper shutdown to the minios test application. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'extras')
-rw-r--r--extras/mini-os/include/kernel.h3
-rw-r--r--extras/mini-os/include/x86/x86_32/hypercall-x86_32.h8
-rw-r--r--extras/mini-os/include/x86/x86_64/hypercall-x86_64.h8
-rw-r--r--extras/mini-os/kernel.c36
-rw-r--r--extras/mini-os/test.c97
5 files changed, 128 insertions, 24 deletions
diff --git a/extras/mini-os/include/kernel.h b/extras/mini-os/include/kernel.h
index b36f172ed8..78692e6c12 100644
--- a/extras/mini-os/include/kernel.h
+++ b/extras/mini-os/include/kernel.h
@@ -1,6 +1,9 @@
#ifndef _KERNEL_H_
#define _KERNEL_H_
+extern unsigned int do_shutdown;
+extern unsigned int shutdown_reason;
+extern struct wait_queue_head shutdown_queue;
extern void do_exit(void) __attribute__((noreturn));
extern void stop_kernel(void);
diff --git a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
index 43028eea0a..ef52ecdd8f 100644
--- a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
+++ b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
@@ -172,6 +172,14 @@ HYPERVISOR_sched_op(
return _hypercall2(int, sched_op, cmd, arg);
}
+static inline int
+HYPERVISOR_shutdown(
+ unsigned int reason)
+{
+ struct sched_shutdown shutdown = { .reason = reason };
+ return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown);
+}
+
static inline long
HYPERVISOR_set_timer_op(
uint64_t timeout)
diff --git a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
index b874f039fe..513d74e09f 100644
--- a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
+++ b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
@@ -176,6 +176,14 @@ HYPERVISOR_sched_op(
return _hypercall2(int, sched_op, cmd, arg);
}
+static inline int
+HYPERVISOR_shutdown(
+ unsigned int reason)
+{
+ struct sched_shutdown shutdown = { .reason = reason };
+ return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown);
+}
+
static inline long
HYPERVISOR_set_timer_op(
uint64_t timeout)
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index a8dfe6d985..378ce1202f 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -48,6 +48,10 @@
uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
+unsigned int do_shutdown = 0;
+unsigned int shutdown_reason;
+DECLARE_WAIT_QUEUE_HEAD(shutdown_queue);
+
void setup_xen_features(void)
{
xen_feature_info_t fi;
@@ -64,6 +68,36 @@ void setup_xen_features(void)
}
}
+static void shutdown_thread(void *p)
+{
+ const char *path = "control/shutdown";
+ const char *token = path;
+ xenbus_event_queue events = NULL;
+ char *shutdown, *err;
+ xenbus_watch_path_token(XBT_NIL, path, token, &events);
+ while ((err = xenbus_read(XBT_NIL, path, &shutdown)) != NULL)
+ {
+ free(err);
+ xenbus_wait_for_watch(&events);
+ }
+ xenbus_unwatch_path_token(XBT_NIL, path, token);
+ xenbus_write(XBT_NIL, path, "");
+ printk("Shutting down (%s)\n", shutdown);
+
+ if (!strcmp(shutdown, "poweroff"))
+ shutdown_reason = SHUTDOWN_poweroff;
+ else if (!strcmp(shutdown, "reboot"))
+ shutdown_reason = SHUTDOWN_reboot;
+ else
+ /* Unknown */
+ shutdown_reason = SHUTDOWN_crash;
+ wmb();
+ do_shutdown = 1;
+ wmb();
+ wake_up(&shutdown_queue);
+}
+
+
/* This should be overridden by the application we are linked against. */
__attribute__((weak)) int app_main(start_info_t *si)
{
@@ -126,6 +160,8 @@ void start_kernel(start_info_t *si)
/* Init XenBus */
init_xenbus();
+ create_thread("shutdown", shutdown_thread, NULL);
+
/* Call (possibly overridden) app_main() */
app_main(&start_info);
diff --git a/extras/mini-os/test.c b/extras/mini-os/test.c
index 7baf1fbe57..95e2d697f8 100644
--- a/extras/mini-os/test.c
+++ b/extras/mini-os/test.c
@@ -46,6 +46,7 @@
#include <xen/version.h>
static struct netfront_dev *net_dev;
+static struct semaphore net_sem = __SEMAPHORE_INITIALIZER(net_sem, 0);
void test_xenbus(void);
@@ -70,12 +71,14 @@ static void periodic_thread(void *p)
static void netfront_thread(void *p)
{
net_dev = init_netfront(NULL, NULL, NULL, NULL);
+ up(&net_sem);
}
static struct blkfront_dev *blk_dev;
static struct blkfront_info blk_info;
static uint64_t blk_size_read;
static uint64_t blk_size_write;
+static struct semaphore blk_sem = __SEMAPHORE_INITIALIZER(blk_sem, 0);;
struct blk_req {
struct blkfront_aiocb aiocb;
@@ -189,8 +192,10 @@ static void blkfront_thread(void *p)
time_t lasttime = 0;
blk_dev = init_blkfront(NULL, &blk_info);
- if (!blk_dev)
+ if (!blk_dev) {
+ up(&blk_sem);
return;
+ }
if (blk_info.info & VDISK_CDROM)
printk("Block device is a CDROM\n");
@@ -210,7 +215,7 @@ static void blkfront_thread(void *p)
blk_read_sector(blk_info.sectors-1);
}
- while (1) {
+ while (!do_shutdown) {
uint64_t sector = rand() % blk_info.sectors;
struct timeval tv;
#ifdef BLKTEST_WRITE
@@ -235,6 +240,7 @@ static void blkfront_thread(void *p)
}
#endif
}
+ up(&blk_sem);
}
#define WIDTH 800
@@ -293,7 +299,6 @@ static void fbfront_thread(void *p)
xfree(mfns);
if (!fb_dev) {
xfree(fb);
- return;
}
up(&fbfront_sem);
}
@@ -330,17 +335,21 @@ static void refresh_cursor(int new_x, int new_y)
}
static struct kbdfront_dev *kbd_dev;
+static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
static void kbdfront_thread(void *p)
{
DEFINE_WAIT(w);
DEFINE_WAIT(w2);
+ DEFINE_WAIT(w3);
int x = WIDTH / 2, y = HEIGHT / 2, z = 0;
kbd_dev = init_kbdfront(NULL, 1);
- if (!kbd_dev)
+ down(&fbfront_sem);
+ if (!kbd_dev) {
+ up(&kbd_sem);
return;
+ }
- down(&fbfront_sem);
refresh_cursor(x, y);
while (1) {
union xenkbd_in_event kbdevent;
@@ -349,6 +358,11 @@ static void kbdfront_thread(void *p)
add_waiter(w, kbdfront_queue);
add_waiter(w2, fbfront_queue);
+ add_waiter(w3, shutdown_queue);
+
+ rmb();
+ if (do_shutdown)
+ break;
while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) {
sleep = 0;
@@ -391,9 +405,11 @@ static void kbdfront_thread(void *p)
fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
}
} else if (kbdevent.key.keycode == KEY_Q) {
- struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
- HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
- do_exit();
+ shutdown_reason = SHUTDOWN_poweroff;
+ wmb();
+ do_shutdown = 1;
+ wmb();
+ wake_up(&shutdown_queue);
}
break;
}
@@ -410,11 +426,16 @@ static void kbdfront_thread(void *p)
}
if (sleep)
schedule();
+ remove_waiter(w3, shutdown_queue);
+ remove_waiter(w2, fbfront_queue);
+ remove_waiter(w, kbdfront_queue);
}
+ up(&kbd_sem);
}
#ifdef CONFIG_PCIFRONT
static struct pcifront_dev *pci_dev;
+static struct semaphore pci_sem = __SEMAPHORE_INITIALIZER(pci_sem, 0);
static void print_pcidev(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun)
{
@@ -432,44 +453,72 @@ static void pcifront_thread(void *p)
{
pcifront_watches(NULL);
pci_dev = init_pcifront(NULL);
- if (!pci_dev)
+ if (!pci_dev) {
+ up(&pci_sem);
return;
+ }
printk("PCI devices:\n");
pcifront_scan(pci_dev, print_pcidev);
+ up(&pci_sem);
}
#endif
-int app_main(start_info_t *si)
-{
- printk("Test main: start_info=%p\n", si);
- create_thread("xenbus_tester", xenbus_tester, si);
- create_thread("periodic_thread", periodic_thread, si);
- create_thread("netfront", netfront_thread, si);
- create_thread("blkfront", blkfront_thread, si);
- create_thread("fbfront", fbfront_thread, si);
- create_thread("kbdfront", kbdfront_thread, si);
-#ifdef CONFIG_PCIFRONT
- create_thread("pcifront", pcifront_thread, si);
-#endif
- return 0;
-}
-
void shutdown_frontends(void)
{
+ down(&net_sem);
if (net_dev)
shutdown_netfront(net_dev);
+ down(&blk_sem);
if (blk_dev)
shutdown_blkfront(blk_dev);
if (fb_dev)
shutdown_fbfront(fb_dev);
+ down(&kbd_sem);
if (kbd_dev)
shutdown_kbdfront(kbd_dev);
#ifdef CONFIG_PCIFRONT
+ down(&pci_sem);
if (pci_dev)
shutdown_pcifront(pci_dev);
#endif
}
+
+static void shutdown_thread(void *p)
+{
+ DEFINE_WAIT(w);
+
+ while (1) {
+ add_waiter(w, shutdown_queue);
+ rmb();
+ if (do_shutdown) {
+ rmb();
+ break;
+ }
+ schedule();
+ remove_waiter(w, shutdown_queue);
+ }
+
+ shutdown_frontends();
+
+ HYPERVISOR_shutdown(shutdown_reason);
+}
+
+int app_main(start_info_t *si)
+{
+ printk("Test main: start_info=%p\n", si);
+ create_thread("xenbus_tester", xenbus_tester, si);
+ create_thread("periodic_thread", periodic_thread, si);
+ create_thread("netfront", netfront_thread, si);
+ create_thread("blkfront", blkfront_thread, si);
+ create_thread("fbfront", fbfront_thread, si);
+ create_thread("kbdfront", kbdfront_thread, si);
+#ifdef CONFIG_PCIFRONT
+ create_thread("pcifront", pcifront_thread, si);
+#endif
+ create_thread("shutdown", shutdown_thread, si);
+ return 0;
+}