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