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 proc_ops srm_env_proc_ops = { 123 .proc_open = srm_env_proc_open, 124 .proc_read = seq_read, 125 .proc_lseek = seq_lseek, 126 .proc_release = single_release, 127 .proc_write = srm_env_proc_write, 128 }; 129 130 static int __init 131 srm_env_init(void) 132 { 133 srm_env_t *entry; 134 unsigned long var_num; 135 136 /* 137 * Check system 138 */ 139 if (!alpha_using_srm) { 140 printk(KERN_INFO "%s: This Alpha system doesn't " 141 "know about SRM (or you've booted " 142 "SRM->MILO->Linux, which gets " 143 "misdetected)...\n", __func__); 144 return -ENODEV; 145 } 146 147 /* 148 * Create base directory 149 */ 150 base_dir = proc_mkdir(BASE_DIR, NULL); 151 if (!base_dir) { 152 printk(KERN_ERR "Couldn't create base dir /proc/%s\n", 153 BASE_DIR); 154 return -ENOMEM; 155 } 156 157 /* 158 * Create per-name subdirectory 159 */ 160 named_dir = proc_mkdir(NAMED_DIR, base_dir); 161 if (!named_dir) { 162 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 163 BASE_DIR, NAMED_DIR); 164 goto cleanup; 165 } 166 167 /* 168 * Create per-number subdirectory 169 */ 170 numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); 171 if (!numbered_dir) { 172 printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", 173 BASE_DIR, NUMBERED_DIR); 174 goto cleanup; 175 176 } 177 178 /* 179 * Create all named nodes 180 */ 181 entry = srm_named_entries; 182 while (entry->name && entry->id) { 183 if (!proc_create_data(entry->name, 0644, named_dir, 184 &srm_env_proc_ops, (void *)entry->id)) 185 goto cleanup; 186 entry++; 187 } 188 189 /* 190 * Create all numbered nodes 191 */ 192 for (var_num = 0; var_num <= 255; var_num++) { 193 char name[4]; 194 sprintf(name, "%ld", var_num); 195 if (!proc_create_data(name, 0644, numbered_dir, 196 &srm_env_proc_ops, (void *)var_num)) 197 goto cleanup; 198 } 199 200 printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, 201 VERSION); 202 203 return 0; 204 205 cleanup: 206 remove_proc_subtree(BASE_DIR, NULL); 207 return -ENOMEM; 208 } 209 210 static void __exit 211 srm_env_exit(void) 212 { 213 remove_proc_subtree(BASE_DIR, NULL); 214 printk(KERN_INFO "%s: unloaded successfully\n", NAME); 215 } 216 217 module_init(srm_env_init); 218 module_exit(srm_env_exit); 219