^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * srm_env.c - Access to SRM environment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * variables through linux' procfs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This driver is a modified version of Erik Mouw's example proc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * interface, so: thank you, Erik! He can be reached via email at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * included a patch like this as well. Thanks for idea!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/machvec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define BASE_DIR "srm_environment" /* Subdir in /proc/ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define NAMED_DIR "named_variables" /* Subdir for known variables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define VERSION "0.0.6" /* Module version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define NAME "srm_env" /* Module name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) typedef struct _srm_env {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) } srm_env_t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static struct proc_dir_entry *base_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static struct proc_dir_entry *named_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static struct proc_dir_entry *numbered_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static srm_env_t srm_named_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { "auto_action", ENV_AUTO_ACTION },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { "boot_dev", ENV_BOOT_DEV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) { "bootdef_dev", ENV_BOOTDEF_DEV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) { "booted_dev", ENV_BOOTED_DEV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) { "boot_file", ENV_BOOT_FILE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { "booted_file", ENV_BOOTED_FILE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) { "boot_osflags", ENV_BOOT_OSFLAGS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { "booted_osflags", ENV_BOOTED_OSFLAGS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) { "boot_reset", ENV_BOOT_RESET },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) { "dump_dev", ENV_DUMP_DEV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) { "enable_audit", ENV_ENABLE_AUDIT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) { "license", ENV_LICENSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) { "char_set", ENV_CHAR_SET },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) { "language", ENV_LANGUAGE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) { "tty_dev", ENV_TTY_DEV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) { NULL, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static int srm_env_proc_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned long ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned long id = (unsigned long)m->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) char *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) page = (char *)__get_free_page(GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (!page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = callback_getenv(id, page, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if ((ret >> 61) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) seq_write(m, page, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) free_page((unsigned long)page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int srm_env_proc_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return single_open(file, srm_env_proc_show, PDE_DATA(inode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static ssize_t srm_env_proc_write(struct file *file, const char __user *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) size_t count, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned long id = (unsigned long)PDE_DATA(file_inode(file));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) char *buf = (char *) __get_free_page(GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) unsigned long ret1, ret2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) res = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (count >= PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) res = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (copy_from_user(buf, buffer, count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) buf[count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ret1 = callback_setenv(id, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if ((ret1 >> 61) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ret2 = callback_save_env();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) while((ret2 >> 61) == 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) res = (int) ret1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) free_page((unsigned long)buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static const struct proc_ops srm_env_proc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .proc_open = srm_env_proc_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .proc_read = seq_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .proc_lseek = seq_lseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .proc_release = single_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .proc_write = srm_env_proc_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) srm_env_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) srm_env_t *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned long var_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * Check system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (!alpha_using_srm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) printk(KERN_INFO "%s: This Alpha system doesn't "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) "know about SRM (or you've booted "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) "SRM->MILO->Linux, which gets "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) "misdetected)...\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * Create base directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) base_dir = proc_mkdir(BASE_DIR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (!base_dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) BASE_DIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * Create per-name subdirectory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) named_dir = proc_mkdir(NAMED_DIR, base_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (!named_dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) BASE_DIR, NAMED_DIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Create per-number subdirectory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!numbered_dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) BASE_DIR, NUMBERED_DIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) goto cleanup;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Create all named nodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) entry = srm_named_entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) while (entry->name && entry->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (!proc_create_data(entry->name, 0644, named_dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) &srm_env_proc_ops, (void *)entry->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) entry++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * Create all numbered nodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) for (var_num = 0; var_num <= 255; var_num++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) char name[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) sprintf(name, "%ld", var_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!proc_create_data(name, 0644, numbered_dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) &srm_env_proc_ops, (void *)var_num))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) remove_proc_subtree(BASE_DIR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static void __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) srm_env_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) remove_proc_subtree(BASE_DIR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) printk(KERN_INFO "%s: unloaded successfully\n", NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) module_init(srm_env_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) module_exit(srm_env_exit);