^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/sched/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/syscalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/utsname.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/socket.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/un.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/mount.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/switch_to.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <irq_kern.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <irq_user.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <kern_util.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include "mconsole.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include "mconsole_kern.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <os.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static struct vfsmount *proc_mnt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int do_unlink_socket(struct notifier_block *notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long what, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return mconsole_unlink_socket();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static struct notifier_block reboot_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .notifier_call = do_unlink_socket,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .priority = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* Safe without explicit locking for now. Tasklets provide their own
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * locking, and the interrupt handler is safe because it can't interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * itself and it can only happen on CPU 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static LIST_HEAD(mc_requests);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void mc_work_proc(struct work_struct *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct mconsole_entry *req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) while (!list_empty(&mc_requests)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) req = list_entry(mc_requests.next, struct mconsole_entry, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) list_del(&req->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) req->request.cmd->handler(&req->request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) kfree(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static DECLARE_WORK(mconsole_work, mc_work_proc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* long to avoid size mismatch warnings from gcc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) long fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct mconsole_entry *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static struct mc_request req; /* that's OK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) fd = (long) dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) while (mconsole_get_request(fd, &req)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (req.cmd->context == MCONSOLE_INTR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) (*req.cmd->handler)(&req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) new = kmalloc(sizeof(*new), GFP_NOWAIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (new == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) mconsole_reply(&req, "Out of memory", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) new->request = req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) new->request.regs = get_irq_regs()->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) list_add(&new->list, &mc_requests);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!list_empty(&mc_requests))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) schedule_work(&mconsole_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) void mconsole_version(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) char version[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) sprintf(version, "%s %s %s %s %s", utsname()->sysname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) utsname()->nodename, utsname()->release, utsname()->version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) utsname()->machine);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) mconsole_reply(req, version, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) void mconsole_log(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) char *ptr = req->request.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ptr += strlen("log ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) len = req->len - (ptr - req->request.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printk(KERN_WARNING "%.*s", len, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) void mconsole_proc(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct vfsmount *mnt = proc_mnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct file *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) int first_chunk = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) char *ptr = req->request.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ptr += strlen("proc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ptr = skip_spaces(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (!mnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) mconsole_reply(req, "Proc not available", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (IS_ERR(file)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) mconsole_reply(req, "Failed to open file", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) mconsole_reply(req, "Failed to allocate buffer", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) goto out_fput;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) len = kernel_read(file, buf, PAGE_SIZE - 1, &pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (len < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) mconsole_reply(req, "Read of file failed", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Begin the file content on his own line. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (first_chunk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) mconsole_reply(req, "\n", 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) first_chunk = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) buf[len] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) mconsole_reply(req, buf, 0, (len > 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) } while (len > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) out_fput:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) fput(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) out: ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) #define UML_MCONSOLE_HELPTEXT \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) "Commands: \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) version - Get kernel version \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) help - Print this message \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) halt - Halt UML \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) reboot - Reboot UML \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) config <dev>=<config> - Add a new device to UML; \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) same syntax as command line \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) config <dev> - Query the configuration of a device \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) remove <dev> - Remove a device from UML \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sysrq <letter> - Performs the SysRq action controlled by the letter \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) cad - invoke the Ctrl-Alt-Del handler \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) stop - pause the UML; it will do nothing until it receives a 'go' \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) go - continue the UML after a 'stop' \n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) log <string> - make UML enter <string> into the kernel log\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) proc <file> - returns the contents of the UML's /proc/<file>\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) stack <pid> - returns the stack of the specified pid\n\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) void mconsole_help(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) void mconsole_halt(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) machine_halt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) void mconsole_reboot(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) machine_restart(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) void mconsole_cad(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) ctrl_alt_del();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) void mconsole_go(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) mconsole_reply(req, "Not stopped", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) void mconsole_stop(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) block_signals();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) os_set_fd_block(req->originating_fd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) mconsole_reply(req, "stopped", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (!mconsole_get_request(req->originating_fd, req))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (req->cmd->handler == mconsole_go)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (req->cmd->handler == mconsole_stop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) mconsole_reply(req, "Already stopped", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (req->cmd->handler == mconsole_sysrq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct pt_regs *old_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) old_regs = set_irq_regs((struct pt_regs *)&req->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) mconsole_sysrq(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) set_irq_regs(old_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) (*req->cmd->handler)(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) os_set_fd_block(req->originating_fd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) unblock_signals();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static DEFINE_SPINLOCK(mc_devices_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static LIST_HEAD(mconsole_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) void mconsole_register_dev(struct mc_device *new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) spin_lock(&mc_devices_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) BUG_ON(!list_empty(&new->list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) list_add(&new->list, &mconsole_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) spin_unlock(&mc_devices_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static struct mc_device *mconsole_find_dev(char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct list_head *ele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct mc_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) list_for_each(ele, &mconsole_devices) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) dev = list_entry(ele, struct mc_device, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (!strncmp(name, dev->name, strlen(dev->name)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) #define UNPLUGGED_PER_PAGE \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) struct unplugged_pages {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) void *pages[UNPLUGGED_PER_PAGE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static DEFINE_MUTEX(plug_mem_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static unsigned long long unplugged_pages_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static LIST_HEAD(unplugged_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static int unplug_index = UNPLUGGED_PER_PAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static int mem_config(char *str, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) unsigned long long diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int err = -EINVAL, i, add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) char *ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (str[0] != '=') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *error_out = "Expected '=' after 'mem'";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (str[0] == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) add = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) else if (str[0] == '+') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) add = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) *error_out = "Expected increment to start with '-' or '+'";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) diff = memparse(str, &ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (*ret != '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *error_out = "Failed to parse memory increment";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) diff /= PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) mutex_lock(&plug_mem_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) for (i = 0; i < diff; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) struct unplugged_pages *unplugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) void *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (add) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (list_empty(&unplugged_pages))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) unplugged = list_entry(unplugged_pages.next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct unplugged_pages, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (unplug_index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) addr = unplugged->pages[--unplug_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) list_del(&unplugged->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) addr = unplugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) unplug_index = UNPLUGGED_PER_PAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) free_page((unsigned long) addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) unplugged_pages_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) page = alloc_page(GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (page == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) unplugged = page_address(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (unplug_index == UNPLUGGED_PER_PAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) list_add(&unplugged->list, &unplugged_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) unplug_index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct list_head *entry = unplugged_pages.next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) addr = unplugged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) unplugged = list_entry(entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) struct unplugged_pages,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) err = os_drop_memory(addr, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) printk(KERN_ERR "Failed to release "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) "memory - errno = %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) *error_out = "Failed to release memory";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) unplugged->pages[unplug_index++] = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) unplugged_pages_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) mutex_unlock(&plug_mem_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) static int mem_get_config(char *name, char *str, int size, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) char buf[sizeof("18446744073709551615")];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) int len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) sprintf(buf, "%ld", uml_physmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) CONFIG_CHUNK(str, size, len, buf, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static int mem_id(char **str, int *start_out, int *end_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) *start_out = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) *end_out = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static int mem_remove(int n, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) *error_out = "Memory doesn't support the remove operation";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static struct mc_device mem_mc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .list = LIST_HEAD_INIT(mem_mc.list),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .name = "mem",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .config = mem_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) .get_config = mem_get_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .id = mem_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .remove = mem_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static int __init mem_mc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (can_drop_memory())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) mconsole_register_dev(&mem_mc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) else printk(KERN_ERR "Can't release memory to the host - memory "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) "hotplug won't be supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) __initcall(mem_mc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) #define CONFIG_BUF_SIZE 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static void mconsole_get_config(int (*get_config)(char *, char *, int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) char **),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) struct mc_request *req, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) char default_buf[CONFIG_BUF_SIZE], *error, *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) int n, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (get_config == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) mconsole_reply(req, "No get_config routine defined", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) error = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) size = ARRAY_SIZE(default_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) buf = default_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) n = (*get_config)(name, buf, size, &error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (error != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) mconsole_reply(req, error, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (n <= size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) mconsole_reply(req, buf, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (buf != default_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) size = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) buf = kmalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) mconsole_reply(req, "Failed to allocate buffer", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (buf != default_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) void mconsole_config(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct mc_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) char *ptr = req->request.data, *name, *error_string = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) ptr += strlen("config");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ptr = skip_spaces(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) dev = mconsole_find_dev(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (dev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) mconsole_reply(req, "Bad configuration option", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) name = &ptr[strlen(dev->name)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) ptr = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) while ((*ptr != '=') && (*ptr != '\0'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) ptr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (*ptr == '=') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) err = (*dev->config)(name, &error_string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) mconsole_reply(req, error_string, err, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) else mconsole_get_config(dev->get_config, req, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) void mconsole_remove(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) struct mc_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) char *ptr = req->request.data, *err_msg = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) char error[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) int err, start, end, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) ptr += strlen("remove");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) ptr = skip_spaces(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) dev = mconsole_find_dev(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (dev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) mconsole_reply(req, "Bad remove option", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ptr = &ptr[strlen(dev->name)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) err = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) n = (*dev->id)(&ptr, &start, &end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (n < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) err_msg = "Couldn't parse device number";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) else if ((n < start) || (n > end)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) sprintf(error, "Invalid device number - must be between "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) "%d and %d", start, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) err_msg = error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) err_msg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) err = (*dev->remove)(n, &err_msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) switch(err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) err_msg = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) case -ENODEV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (err_msg == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) err_msg = "Device doesn't exist";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) case -EBUSY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (err_msg == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) err_msg = "Device is currently open";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) mconsole_reply(req, err_msg, err, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) struct mconsole_output {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct mc_request *req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) static DEFINE_SPINLOCK(client_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) static LIST_HEAD(clients);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) static char console_buf[MCONSOLE_MAX_DATA];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static void console_write(struct console *console, const char *string,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) unsigned int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct list_head *ele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (list_empty(&clients))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) while (len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) n = min((size_t) len, ARRAY_SIZE(console_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) strncpy(console_buf, string, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) string += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) len -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) list_for_each(ele, &clients) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) struct mconsole_output *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) entry = list_entry(ele, struct mconsole_output, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) mconsole_reply_len(entry->req, console_buf, n, 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static struct console mc_console = { .name = "mc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) .write = console_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) .flags = CON_ENABLED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) .index = -1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static int mc_add_console(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) register_console(&mc_console);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) late_initcall(mc_add_console);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) static void with_console(struct mc_request *req, void (*proc)(void *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) struct mconsole_output entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) entry.req = req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) spin_lock_irqsave(&client_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) list_add(&entry.list, &clients);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) spin_unlock_irqrestore(&client_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) (*proc)(arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) mconsole_reply_len(req, "", 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) spin_lock_irqsave(&client_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) list_del(&entry.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) spin_unlock_irqrestore(&client_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) #ifdef CONFIG_MAGIC_SYSRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) #include <linux/sysrq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) static void sysrq_proc(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) char *op = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) handle_sysrq(*op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) void mconsole_sysrq(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) char *ptr = req->request.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) ptr += strlen("sysrq");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) ptr = skip_spaces(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * With 'b', the system will shut down without a chance to reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * so in this case, we reply first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (*ptr == 'b')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) mconsole_reply(req, "", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) with_console(req, sysrq_proc, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) void mconsole_sysrq(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) mconsole_reply(req, "Sysrq not compiled in", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static void stack_proc(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct task_struct *task = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) show_stack(task, NULL, KERN_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) * Mconsole stack trace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * Added by Allan Graves, Jeff Dike
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * Dumps a stacks registers to the linux console.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * Usage stack <pid>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) void mconsole_stack(struct mc_request *req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) char *ptr = req->request.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) int pid_requested= -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct task_struct *to = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * Would be nice:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * 1) Send showregs output to mconsole.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * 2) Add a way to stack dump all pids.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) ptr += strlen("stack");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) ptr = skip_spaces(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * Should really check for multiple pids or reject bad args here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) /* What do the arguments in mconsole_reply mean? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (sscanf(ptr, "%d", &pid_requested) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) mconsole_reply(req, "Please specify a pid", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) to = find_task_by_pid_ns(pid_requested, &init_pid_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if ((to == NULL) || (pid_requested == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) mconsole_reply(req, "Couldn't find that pid", 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) with_console(req, stack_proc, to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) static int __init mount_proc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) struct file_system_type *proc_fs_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) struct vfsmount *mnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) proc_fs_type = get_fs_type("proc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (!proc_fs_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) mnt = kern_mount(proc_fs_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) put_filesystem(proc_fs_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (IS_ERR(mnt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return PTR_ERR(mnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) proc_mnt = mnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) * Changed by mconsole_setup, which is __setup, and called before SMP is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) * active.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static char *notify_socket = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) static int __init mconsole_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) /* long to avoid size mismatch warnings from gcc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) long sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) char file[UNIX_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) mount_proc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (umid_file_name("mconsole", file, sizeof(file)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) snprintf(mconsole_socket_name, sizeof(file), "%s", file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) sock = os_create_unix_socket(file, sizeof(file), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (sock < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) printk(KERN_ERR "Failed to initialize management console\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (os_set_fd_block(sock, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) register_reboot_notifier(&reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) IRQF_SHARED, "mconsole", (void *)sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) printk(KERN_ERR "Failed to get IRQ for management console\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (notify_socket != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) notify_socket = kstrdup(notify_socket, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (notify_socket != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) mconsole_notify(notify_socket, MCONSOLE_SOCKET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) mconsole_socket_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) strlen(mconsole_socket_name) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) else printk(KERN_ERR "mconsole_setup failed to strdup "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) "string\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) printk(KERN_INFO "mconsole (version %d) initialized on %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) MCONSOLE_VERSION, mconsole_socket_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) os_close_file(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) __initcall(mconsole_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) static ssize_t mconsole_proc_write(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) const char __user *buffer, size_t count, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) buf = memdup_user_nul(buffer, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if (IS_ERR(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return PTR_ERR(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static const struct proc_ops mconsole_proc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) .proc_write = mconsole_proc_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) .proc_lseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int create_proc_mconsole(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct proc_dir_entry *ent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (notify_socket == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) ent = proc_create("mconsole", 0200, NULL, &mconsole_proc_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) if (ent == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) printk(KERN_INFO "create_proc_mconsole : proc_create failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) static DEFINE_SPINLOCK(notify_spinlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) void lock_notify(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) spin_lock(¬ify_spinlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) void unlock_notify(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) spin_unlock(¬ify_spinlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) __initcall(create_proc_mconsole);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) #define NOTIFY "notify:"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static int mconsole_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (!strncmp(str, NOTIFY, strlen(NOTIFY))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) str += strlen(NOTIFY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) notify_socket = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) __setup("mconsole=", mconsole_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) __uml_help(mconsole_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) "mconsole=notify:<socket>\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) " Requests that the mconsole driver send a message to the named Unix\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) " socket containing the name of the mconsole socket. This also serves\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) " to notify outside processes when UML has booted far enough to respond\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) " to mconsole requests.\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static int notify_panic(struct notifier_block *self, unsigned long unused1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) char *message = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (notify_socket == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) strlen(message) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) static struct notifier_block panic_exit_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) .notifier_call = notify_panic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) .next = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) .priority = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) static int add_notifier(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) atomic_notifier_chain_register(&panic_notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) &panic_exit_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) __initcall(add_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) char *mconsole_notify_socket(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) return notify_socket;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) EXPORT_SYMBOL(mconsole_notify_socket);