]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - arch/um/drivers/mconsole_kern.c
[PATCH] uml: skas0-hold-own-ldt fixups for x86-64
[mirror_ubuntu-zesty-kernel.git] / arch / um / drivers / mconsole_kern.c
CommitLineData
1da177e4
LT
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
6f517d3f 23#include "linux/console.h"
1da177e4
LT
24#include "asm/irq.h"
25#include "asm/uaccess.h"
26#include "user_util.h"
27#include "kern_util.h"
28#include "kern.h"
29#include "mconsole.h"
30#include "mconsole_kern.h"
31#include "irq_user.h"
32#include "init.h"
33#include "os.h"
34#include "umid.h"
35#include "irq_kern.h"
3eddddcf 36#include "choose-mode.h"
1da177e4 37
d50084a2 38static int do_unlink_socket(struct notifier_block *notifier,
1da177e4
LT
39 unsigned long what, void *data)
40{
41 return(mconsole_unlink_socket());
42}
43
44
45static struct notifier_block reboot_notifier = {
46 .notifier_call = do_unlink_socket,
47 .priority = 0,
48};
49
d50084a2 50/* Safe without explicit locking for now. Tasklets provide their own
1da177e4
LT
51 * locking, and the interrupt handler is safe because it can't interrupt
52 * itself and it can only happen on CPU 0.
53 */
54
9010772c 55static LIST_HEAD(mc_requests);
1da177e4
LT
56
57static void mc_work_proc(void *unused)
58{
59 struct mconsole_entry *req;
60 unsigned long flags;
61
62 while(!list_empty(&mc_requests)){
63 local_save_flags(flags);
d50084a2 64 req = list_entry(mc_requests.next, struct mconsole_entry,
1da177e4
LT
65 list);
66 list_del(&req->list);
67 local_irq_restore(flags);
68 req->request.cmd->handler(&req->request);
69 kfree(req);
70 }
71}
72
9010772c 73static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
1da177e4
LT
74
75static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
76 struct pt_regs *regs)
77{
78 /* long to avoid size mismatch warnings from gcc */
79 long fd;
80 struct mconsole_entry *new;
81 struct mc_request req;
82
83 fd = (long) dev_id;
84 while (mconsole_get_request(fd, &req)){
85 if(req.cmd->context == MCONSOLE_INTR)
86 (*req.cmd->handler)(&req);
87 else {
88 new = kmalloc(sizeof(*new), GFP_ATOMIC);
89 if(new == NULL)
90 mconsole_reply(&req, "Out of memory", 1, 0);
91 else {
92 new->request = req;
93 list_add(&new->list, &mc_requests);
94 }
95 }
96 }
97 if(!list_empty(&mc_requests))
98 schedule_work(&mconsole_work);
99 reactivate_fd(fd, MCONSOLE_IRQ);
100 return(IRQ_HANDLED);
101}
102
103void mconsole_version(struct mc_request *req)
104{
105 char version[256];
106
d50084a2
JD
107 sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
108 system_utsname.nodename, system_utsname.release,
1da177e4
LT
109 system_utsname.version, system_utsname.machine);
110 mconsole_reply(req, version, 0, 0);
111}
112
113void mconsole_log(struct mc_request *req)
114{
115 int len;
116 char *ptr = req->request.data;
117
118 ptr += strlen("log ");
119
120 len = req->len - (ptr - req->request.data);
121 printk("%.*s", len, ptr);
122 mconsole_reply(req, "", 0, 0);
123}
124
125/* This is a more convoluted version of mconsole_proc, which has some stability
126 * problems; however, we need it fixed, because it is expected that UML users
127 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
128 * show the real procfs content, not the ones from hppfs.*/
129#if 0
130void mconsole_proc(struct mc_request *req)
131{
132 struct nameidata nd;
133 struct file_system_type *proc;
134 struct super_block *super;
135 struct file *file;
136 int n, err;
137 char *ptr = req->request.data, *buf;
138
139 ptr += strlen("proc");
140 while(isspace(*ptr)) ptr++;
141
142 proc = get_fs_type("proc");
143 if(proc == NULL){
144 mconsole_reply(req, "procfs not registered", 1, 0);
145 goto out;
146 }
147
148 super = (*proc->get_sb)(proc, 0, NULL, NULL);
149 put_filesystem(proc);
150 if(super == NULL){
151 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
152 goto out;
153 }
154 up_write(&super->s_umount);
155
156 nd.dentry = super->s_root;
157 nd.mnt = NULL;
158 nd.flags = O_RDONLY + 1;
159 nd.last_type = LAST_ROOT;
160
161 /* START: it was experienced that the stability problems are closed
162 * if commenting out these two calls + the below read cycle. To
163 * make UML crash again, it was enough to readd either one.*/
164 err = link_path_walk(ptr, &nd);
165 if(err){
166 mconsole_reply(req, "Failed to look up file", 1, 0);
167 goto out_kill;
168 }
169
170 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
171 if(IS_ERR(file)){
172 mconsole_reply(req, "Failed to open file", 1, 0);
173 goto out_kill;
174 }
175 /*END*/
176
177 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
178 if(buf == NULL){
179 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
180 goto out_fput;
181 }
182
183 if((file->f_op != NULL) && (file->f_op->read != NULL)){
184 do {
185 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
186 &file->f_pos);
187 if(n >= 0){
188 buf[n] = '\0';
189 mconsole_reply(req, buf, 0, (n > 0));
190 }
191 else {
192 mconsole_reply(req, "Read of file failed",
193 1, 0);
194 goto out_free;
195 }
196 } while(n > 0);
197 }
198 else mconsole_reply(req, "", 0, 0);
199
200 out_free:
201 kfree(buf);
202 out_fput:
203 fput(file);
204 out_kill:
205 deactivate_super(super);
206 out: ;
207}
208#endif
209
210void mconsole_proc(struct mc_request *req)
211{
212 char path[64];
213 char *buf;
214 int len;
215 int fd;
216 int first_chunk = 1;
217 char *ptr = req->request.data;
218
219 ptr += strlen("proc");
220 while(isspace(*ptr)) ptr++;
221 snprintf(path, sizeof(path), "/proc/%s", ptr);
222
223 fd = sys_open(path, 0, 0);
224 if (fd < 0) {
225 mconsole_reply(req, "Failed to open file", 1, 0);
226 printk("open %s: %d\n",path,fd);
227 goto out;
228 }
229
230 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
231 if(buf == NULL){
232 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
233 goto out_close;
234 }
235
236 for (;;) {
237 len = sys_read(fd, buf, PAGE_SIZE-1);
238 if (len < 0) {
239 mconsole_reply(req, "Read of file failed", 1, 0);
240 goto out_free;
241 }
242 /*Begin the file content on his own line.*/
243 if (first_chunk) {
244 mconsole_reply(req, "\n", 0, 1);
245 first_chunk = 0;
246 }
247 if (len == PAGE_SIZE-1) {
248 buf[len] = '\0';
249 mconsole_reply(req, buf, 0, 1);
250 } else {
251 buf[len] = '\0';
252 mconsole_reply(req, buf, 0, 0);
253 break;
254 }
255 }
256
257 out_free:
258 kfree(buf);
259 out_close:
260 sys_close(fd);
261 out:
262 /* nothing */;
263}
264
265#define UML_MCONSOLE_HELPTEXT \
266"Commands: \n\
267 version - Get kernel version \n\
268 help - Print this message \n\
269 halt - Halt UML \n\
270 reboot - Reboot UML \n\
271 config <dev>=<config> - Add a new device to UML; \n\
272 same syntax as command line \n\
273 config <dev> - Query the configuration of a device \n\
274 remove <dev> - Remove a device from UML \n\
275 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
db805812 276 cad - invoke the Ctrl-Alt-Del handler \n\
1da177e4
LT
277 stop - pause the UML; it will do nothing until it receives a 'go' \n\
278 go - continue the UML after a 'stop' \n\
279 log <string> - make UML enter <string> into the kernel log\n\
280 proc <file> - returns the contents of the UML's /proc/<file>\n\
3eddddcf 281 stack <pid> - returns the stack of the specified pid\n\
1da177e4
LT
282"
283
284void mconsole_help(struct mc_request *req)
285{
286 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
287}
288
289void mconsole_halt(struct mc_request *req)
290{
291 mconsole_reply(req, "", 0, 0);
292 machine_halt();
293}
294
295void mconsole_reboot(struct mc_request *req)
296{
297 mconsole_reply(req, "", 0, 0);
298 machine_restart(NULL);
299}
300
301extern void ctrl_alt_del(void);
302
303void mconsole_cad(struct mc_request *req)
304{
305 mconsole_reply(req, "", 0, 0);
306 ctrl_alt_del();
307}
308
309void mconsole_go(struct mc_request *req)
310{
311 mconsole_reply(req, "Not stopped", 1, 0);
312}
313
314void mconsole_stop(struct mc_request *req)
315{
316 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
317 os_set_fd_block(req->originating_fd, 1);
318 mconsole_reply(req, "", 0, 0);
319 while(mconsole_get_request(req->originating_fd, req)){
320 if(req->cmd->handler == mconsole_go) break;
321 (*req->cmd->handler)(req);
322 }
323 os_set_fd_block(req->originating_fd, 0);
324 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
325 mconsole_reply(req, "", 0, 0);
326}
327
328/* This list is populated by __initcall routines. */
329
330LIST_HEAD(mconsole_devices);
331
332void mconsole_register_dev(struct mc_device *new)
333{
334 list_add(&new->list, &mconsole_devices);
335}
336
337static struct mc_device *mconsole_find_dev(char *name)
338{
339 struct list_head *ele;
340 struct mc_device *dev;
341
342 list_for_each(ele, &mconsole_devices){
343 dev = list_entry(ele, struct mc_device, list);
344 if(!strncmp(name, dev->name, strlen(dev->name)))
345 return(dev);
346 }
347 return(NULL);
348}
349
350#define CONFIG_BUF_SIZE 64
351
d50084a2 352static void mconsole_get_config(int (*get_config)(char *, char *, int,
1da177e4
LT
353 char **),
354 struct mc_request *req, char *name)
355{
356 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
357 int n, size;
358
359 if(get_config == NULL){
360 mconsole_reply(req, "No get_config routine defined", 1, 0);
361 return;
362 }
363
364 error = NULL;
365 size = sizeof(default_buf)/sizeof(default_buf[0]);
366 buf = default_buf;
367
368 while(1){
369 n = (*get_config)(name, buf, size, &error);
370 if(error != NULL){
371 mconsole_reply(req, error, 1, 0);
372 goto out;
373 }
374
375 if(n <= size){
376 mconsole_reply(req, buf, 0, 0);
377 goto out;
378 }
379
380 if(buf != default_buf)
381 kfree(buf);
382
383 size = n;
384 buf = kmalloc(size, GFP_KERNEL);
385 if(buf == NULL){
386 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
387 return;
388 }
389 }
390 out:
391 if(buf != default_buf)
392 kfree(buf);
1da177e4
LT
393}
394
395void mconsole_config(struct mc_request *req)
396{
397 struct mc_device *dev;
398 char *ptr = req->request.data, *name;
399 int err;
400
401 ptr += strlen("config");
402 while(isspace(*ptr)) ptr++;
403 dev = mconsole_find_dev(ptr);
404 if(dev == NULL){
405 mconsole_reply(req, "Bad configuration option", 1, 0);
406 return;
407 }
408
409 name = &ptr[strlen(dev->name)];
410 ptr = name;
411 while((*ptr != '=') && (*ptr != '\0'))
412 ptr++;
413
414 if(*ptr == '='){
415 err = (*dev->config)(name);
416 mconsole_reply(req, "", err, 0);
417 }
418 else mconsole_get_config(dev->get_config, req, name);
419}
420
421void mconsole_remove(struct mc_request *req)
422{
d50084a2 423 struct mc_device *dev;
29d56cfe 424 char *ptr = req->request.data, *err_msg = "";
3a331a51 425 char error[256];
29d56cfe 426 int err, start, end, n;
1da177e4
LT
427
428 ptr += strlen("remove");
429 while(isspace(*ptr)) ptr++;
430 dev = mconsole_find_dev(ptr);
431 if(dev == NULL){
432 mconsole_reply(req, "Bad remove option", 1, 0);
433 return;
434 }
29d56cfe 435
3a331a51
JD
436 ptr = &ptr[strlen(dev->name)];
437
438 err = 1;
439 n = (*dev->id)(&ptr, &start, &end);
440 if(n < 0){
441 err_msg = "Couldn't parse device number";
442 goto out;
443 }
444 else if((n < start) || (n > end)){
445 sprintf(error, "Invalid device number - must be between "
446 "%d and %d", start, end);
447 err_msg = error;
448 goto out;
449 }
29d56cfe
JD
450
451 err = (*dev->remove)(n);
3a331a51
JD
452 switch(err){
453 case -ENODEV:
454 err_msg = "Device doesn't exist";
455 break;
456 case -EBUSY:
457 err_msg = "Device is currently open";
458 break;
459 default:
460 break;
461 }
462out:
29d56cfe 463 mconsole_reply(req, err_msg, err, 0);
1da177e4
LT
464}
465
6f517d3f
JD
466static DEFINE_SPINLOCK(console_lock);
467static LIST_HEAD(clients);
468static char console_buf[MCONSOLE_MAX_DATA];
469static int console_index = 0;
470
471static void console_write(struct console *console, const char *string,
472 unsigned len)
473{
474 struct list_head *ele;
475 int n;
476
477 if(list_empty(&clients))
478 return;
479
480 while(1){
481 n = min(len, ARRAY_SIZE(console_buf) - console_index);
482 strncpy(&console_buf[console_index], string, n);
483 console_index += n;
484 string += n;
485 len -= n;
486 if(len == 0)
487 return;
488
489 list_for_each(ele, &clients){
490 struct mconsole_entry *entry;
491
492 entry = list_entry(ele, struct mconsole_entry, list);
493 mconsole_reply_len(&entry->request, console_buf,
494 console_index, 0, 1);
495 }
496
497 console_index = 0;
498 }
499}
500
501static struct console mc_console = { .name = "mc",
502 .write = console_write,
a174b30e 503 .flags = CON_ENABLED,
6f517d3f
JD
504 .index = -1 };
505
506static int mc_add_console(void)
507{
508 register_console(&mc_console);
509 return 0;
510}
511
512late_initcall(mc_add_console);
513
514static void with_console(struct mc_request *req, void (*proc)(void *),
515 void *arg)
516{
517 struct mconsole_entry entry;
518 unsigned long flags;
519
520 INIT_LIST_HEAD(&entry.list);
521 entry.request = *req;
522 list_add(&entry.list, &clients);
523 spin_lock_irqsave(&console_lock, flags);
524
525 (*proc)(arg);
526
527 mconsole_reply_len(req, console_buf, console_index, 0, 0);
528 console_index = 0;
529
530 spin_unlock_irqrestore(&console_lock, flags);
531 list_del(&entry.list);
532}
533
4111b025
JD
534#ifdef CONFIG_MAGIC_SYSRQ
535static void sysrq_proc(void *arg)
536{
537 char *op = arg;
538
539 handle_sysrq(*op, &current->thread.regs, NULL);
540}
541
542void mconsole_sysrq(struct mc_request *req)
543{
544 char *ptr = req->request.data;
545
546 ptr += strlen("sysrq");
547 while(isspace(*ptr)) ptr++;
548
549 /* With 'b', the system will shut down without a chance to reply,
550 * so in this case, we reply first.
551 */
552 if(*ptr == 'b')
553 mconsole_reply(req, "", 0, 0);
554
555 with_console(req, sysrq_proc, ptr);
556}
557#else
558void mconsole_sysrq(struct mc_request *req)
559{
560 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
561}
562#endif
563
6f517d3f
JD
564static void stack_proc(void *arg)
565{
566 struct task_struct *from = current, *to = arg;
567
568 to->thread.saved_task = from;
569 switch_to(from, to, from);
570}
571
3eddddcf
JD
572/* Mconsole stack trace
573 * Added by Allan Graves, Jeff Dike
574 * Dumps a stacks registers to the linux console.
575 * Usage stack <pid>.
576 */
577void do_stack(struct mc_request *req)
578{
3a331a51
JD
579 char *ptr = req->request.data;
580 int pid_requested= -1;
6f517d3f 581 struct task_struct *from = NULL;
3eddddcf
JD
582 struct task_struct *to = NULL;
583
3a331a51
JD
584 /* Would be nice:
585 * 1) Send showregs output to mconsole.
3eddddcf
JD
586 * 2) Add a way to stack dump all pids.
587 */
588
3a331a51
JD
589 ptr += strlen("stack");
590 while(isspace(*ptr)) ptr++;
3eddddcf 591
3a331a51
JD
592 /* Should really check for multiple pids or reject bad args here */
593 /* What do the arguments in mconsole_reply mean? */
594 if(sscanf(ptr, "%d", &pid_requested) == 0){
595 mconsole_reply(req, "Please specify a pid", 1, 0);
596 return;
597 }
3eddddcf 598
6f517d3f 599 from = current;
3eddddcf 600
6f517d3f 601 to = find_task_by_pid(pid_requested);
3a331a51
JD
602 if((to == NULL) || (pid_requested == 0)) {
603 mconsole_reply(req, "Couldn't find that pid", 1, 0);
604 return;
605 }
6f517d3f 606 with_console(req, stack_proc, to);
3eddddcf
JD
607}
608
609void mconsole_stack(struct mc_request *req)
610{
611 /* This command doesn't work in TT mode, so let's check and then
612 * get out of here
613 */
614 CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
615 1, 0),
616 do_stack(req));
617}
618
1da177e4
LT
619/* Changed by mconsole_setup, which is __setup, and called before SMP is
620 * active.
621 */
d50084a2 622static char *notify_socket = NULL;
1da177e4 623
9010772c 624static int mconsole_init(void)
1da177e4
LT
625{
626 /* long to avoid size mismatch warnings from gcc */
627 long sock;
628 int err;
629 char file[256];
630
631 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
632 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
633
634 sock = os_create_unix_socket(file, sizeof(file), 1);
635 if (sock < 0){
636 printk("Failed to initialize management console\n");
637 return(1);
638 }
639
640 register_reboot_notifier(&reboot_notifier);
641
642 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
643 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
644 "mconsole", (void *)sock);
645 if (err){
646 printk("Failed to get IRQ for management console\n");
647 return(1);
648 }
649
650 if(notify_socket != NULL){
970d6e3a 651 notify_socket = kstrdup(notify_socket, GFP_KERNEL);
1da177e4
LT
652 if(notify_socket != NULL)
653 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
d50084a2 654 mconsole_socket_name,
1da177e4
LT
655 strlen(mconsole_socket_name) + 1);
656 else printk(KERN_ERR "mconsole_setup failed to strdup "
657 "string\n");
658 }
659
d50084a2 660 printk("mconsole (version %d) initialized on %s\n",
1da177e4
LT
661 MCONSOLE_VERSION, mconsole_socket_name);
662 return(0);
663}
664
665__initcall(mconsole_init);
666
667static int write_proc_mconsole(struct file *file, const char __user *buffer,
668 unsigned long count, void *data)
669{
670 char *buf;
671
672 buf = kmalloc(count + 1, GFP_KERNEL);
d50084a2 673 if(buf == NULL)
1da177e4
LT
674 return(-ENOMEM);
675
676 if(copy_from_user(buf, buffer, count)){
677 count = -EFAULT;
678 goto out;
679 }
680
681 buf[count] = '\0';
682
683 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
684 out:
685 kfree(buf);
686 return(count);
687}
688
689static int create_proc_mconsole(void)
690{
691 struct proc_dir_entry *ent;
692
693 if(notify_socket == NULL) return(0);
694
695 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
696 if(ent == NULL){
30f417c6 697 printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
1da177e4
LT
698 return(0);
699 }
700
701 ent->read_proc = NULL;
702 ent->write_proc = write_proc_mconsole;
703 return(0);
704}
705
706static DEFINE_SPINLOCK(notify_spinlock);
707
708void lock_notify(void)
709{
710 spin_lock(&notify_spinlock);
711}
712
713void unlock_notify(void)
714{
715 spin_unlock(&notify_spinlock);
716}
717
718__initcall(create_proc_mconsole);
719
720#define NOTIFY "=notify:"
721
722static int mconsole_setup(char *str)
723{
724 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
725 str += strlen(NOTIFY);
726 notify_socket = str;
727 }
728 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
729 return(1);
730}
731
732__setup("mconsole", mconsole_setup);
733
734__uml_help(mconsole_setup,
735"mconsole=notify:<socket>\n"
736" Requests that the mconsole driver send a message to the named Unix\n"
737" socket containing the name of the mconsole socket. This also serves\n"
738" to notify outside processes when UML has booted far enough to respond\n"
739" to mconsole requests.\n\n"
740);
741
742static int notify_panic(struct notifier_block *self, unsigned long unused1,
743 void *ptr)
744{
745 char *message = ptr;
746
747 if(notify_socket == NULL) return(0);
748
d50084a2 749 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
1da177e4
LT
750 strlen(message) + 1);
751 return(0);
752}
753
754static struct notifier_block panic_exit_notifier = {
755 .notifier_call = notify_panic,
756 .next = NULL,
757 .priority = 1
758};
759
760static int add_notifier(void)
761{
762 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
763 return(0);
764}
765
766__initcall(add_notifier);
767
768char *mconsole_notify_socket(void)
769{
770 return(notify_socket);
771}
772
773EXPORT_SYMBOL(mconsole_notify_socket);