├── Makefile ├── README.md └── amifldrv.c /Makefile: -------------------------------------------------------------------------------- 1 | ifndef KERNEL 2 | KERNEL = /lib/modules/$(shell uname -r)/build 3 | endif 4 | EXTRA_CFLAGS := -Wall -Wstrict-prototypes -O2 -fno-strict-aliasing 5 | obj-m += amifldrv_mod.o 6 | amifldrv_mod-objs := amifldrv.o 7 | default: 8 | make -C $(KERNEL) SUBDIRS=$(PWD) modules 9 | rm -f amifldrv.o_shipped 10 | mv amifldrv.o amifldrv.o_shipped 11 | rm -f amifldrv_mod.o 12 | .PHONY : clean 13 | clean: 14 | rm -f *.*~ 15 | rm -f test 16 | rm -f .*cmd 17 | rm -f *.o 18 | rm -f *mod* 19 | rm -f *.ko 20 | rm -f amifldrv.o_shipped 21 | rm -rf .tmp_versions/ 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # amifldrv source code 2 | 3 | ***This repository is not maintained, and its utility has never been guaranteed. It may not work with newer AMI hardware. Your mileage may vary.*** 4 | 5 | This is the source code for the `amifldrv` kernel module used by the AMI 6 | Aptios flashing tool for linux, `afulnx`. This is associated with the 7 | _64-Bit_ version of the tool, and I _cannot_ guarantee that it will work 8 | with the _32-Bit_ version. 9 | 10 | This source code has been _modified_ so that it will compile and work (I 11 | tested this by flashing with it (!)) on recent versions of Linux. This was 12 | tested with and functioned on Linux 4.1. 13 | 14 | # License issues 15 | 16 | AMI _did not_ specify a license for this code in `readme.txt`, 17 | `readme_afulnx.txt` or any other file, including the source code. 18 | Furthermore, Linux kernel modules can be considered derivitave works of 19 | the Linux kernel, which is licensed under the GNU General Public License. 20 | The GPL _mandates_ that source code be made available. AMI appear to have 21 | gone out of their way to make obtaining the _full_ module source rather 22 | obfuse, as the tool that emits it will delete it immediately after 23 | exiting. 24 | 25 | I do not claim any ownership of this code. 26 | -------------------------------------------------------------------------------- /amifldrv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * American Megatrends ROM Driver 3 | * There wasn't a copyright here, so idk 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define LINUX_PRE_2_6 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) 17 | #define LINUX_POST_2_6 (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 18 | 19 | #if LINUX_PRE_2_6 20 | # include 21 | #else 22 | # define mem_map_reserve(p) set_bit (PG_reserved, &((p)->flags)) 23 | # define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) 24 | #endif 25 | 26 | #define CMD_ALLOC 0x4160 27 | #define CMD_FREE 0x4161 28 | #define CMD_LOCK_KB 0x4162 29 | #define CMD_UNLOCK_KB 0x4163 30 | 31 | /* 32 | * ioctl data packet used to communicate instructions to the driver 33 | */ 34 | typedef struct _struct_AMIFL_alloc_params { 35 | long size; 36 | unsigned long kvirtlen; 37 | void* kmallocptr; 38 | void* kvirtadd; 39 | void* kphysadd; 40 | } AMIFL_alloc_params; 41 | 42 | static int *kmalloc_area = NULL; 43 | static int *kmalloc_ptr = NULL; 44 | static unsigned long kmalloc_len = 0L; 45 | static int kcount = 0; 46 | static int major; 47 | static AMIFL_alloc_params kmalloc_drv[128]; 48 | 49 | /* 50 | * Section: Character Device Implementation 51 | * ============================================================================ 52 | */ 53 | 54 | #if LINUX_POST_2_6 55 | static int chardev_open_count = 0; 56 | #endif 57 | 58 | /** 59 | * Character Device open action 60 | */ 61 | int 62 | AMI_chrdrv_open(struct inode* inode, struct file* file) 63 | { 64 | #if LINUX_PRE_2_6 65 | MOD_INC_USE_COUNT; 66 | #else 67 | if (chardev_open_count > 0) 68 | { 69 | return -EBUSY; 70 | } 71 | 72 | ++chardev_open_count; 73 | try_module_get(THIS_MODULE); 74 | #endif 75 | 76 | return(0); 77 | } 78 | 79 | int 80 | AMI_chrdrv_release(struct inode* inode, struct file* file) 81 | { 82 | #if LINUX_PRE_2_6 83 | MOD_DEC_USE_COUNT; 84 | #else 85 | --chardev_open_count; 86 | module_put(THIS_MODULE); 87 | #endif 88 | 89 | return(0); 90 | } 91 | 92 | #if defined(HAVE_UNLOCKED_IOCTL) 93 | long 94 | AMI_chrdrv_ioctl(struct file* _unused_file, unsigned int cmd, unsigned long arg) 95 | #else 96 | int 97 | AMI_chrdrv_ioctl(struct inode* _unused_inode, unsigned int cmd, unsigned long arg) 98 | #endif 99 | { 100 | switch(cmd) 101 | { 102 | case CMD_ALLOC: 103 | { 104 | unsigned long virt_addr; 105 | AMIFL_alloc_params arg_kernel_space; 106 | 107 | if (kcount >= 128) 108 | { 109 | return -EINVAL; 110 | } 111 | 112 | kmalloc_ptr = NULL; 113 | 114 | if (!arg || kmalloc_ptr) 115 | { 116 | return -EINVAL; 117 | } 118 | 119 | copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFL_alloc_params)); 120 | 121 | if (arg_kernel_space.size > 128 * 1024) 122 | { 123 | return -EINVAL; 124 | } 125 | 126 | kmalloc_len = ((arg_kernel_space.size + PAGE_SIZE - 1) & PAGE_MASK); 127 | kmalloc_ptr = kmalloc((kmalloc_len + 2 * PAGE_SIZE), GFP_DMA | GFP_KERNEL); 128 | kmalloc_area = (int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE - 1) & PAGE_MASK); 129 | 130 | for (virt_addr = (unsigned long) kmalloc_area; 131 | virt_addr < (unsigned long) kmalloc_area + kmalloc_len; 132 | virt_addr += PAGE_SIZE) 133 | { 134 | mem_map_reserve(virt_to_page(virt_addr)); 135 | } 136 | 137 | { 138 | int i; 139 | for (i = 0; i < (kmalloc_len / sizeof(int)); ++i) { 140 | kmalloc_area[i] = 0xAFD00000 + i; 141 | } 142 | } 143 | 144 | kmalloc_drv[kcount].size = arg_kernel_space.size; 145 | kmalloc_drv[kcount].kmallocptr = kmalloc_ptr; 146 | kmalloc_drv[kcount].kvirtlen = kmalloc_len; 147 | kmalloc_drv[kcount].kvirtadd = kmalloc_area; 148 | kmalloc_drv[kcount].kphysadd = (void *)((unsigned long)virt_to_phys(kmalloc_area)); 149 | ++kcount; 150 | 151 | arg_kernel_space.kvirtadd = kmalloc_area; 152 | arg_kernel_space.kphysadd = (void *)((unsigned long)virt_to_phys(kmalloc_area)); 153 | 154 | copy_to_user((void*) arg, (void*) &arg_kernel_space, sizeof(AMIFL_alloc_params)); 155 | 156 | return 0; 157 | } 158 | case CMD_FREE: 159 | { 160 | unsigned long virt_addr; 161 | AMIFL_alloc_params arg_kernel_space; 162 | int isearch = 0; 163 | 164 | copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFL_alloc_params)); 165 | 166 | if (kcount > 0) { 167 | for (isearch=0; isearch= kcount) return 0; 171 | kmalloc_ptr = kmalloc_drv[isearch].kmallocptr; 172 | kmalloc_area = kmalloc_drv[isearch].kvirtadd; 173 | kmalloc_len = kmalloc_drv[isearch].kvirtlen; 174 | } else 175 | return 0; 176 | if (kmalloc_ptr) { 177 | for(virt_addr = (unsigned long) kmalloc_area; 178 | virt_addr < (unsigned long) kmalloc_area + kmalloc_len; 179 | virt_addr += PAGE_SIZE) 180 | { 181 | mem_map_unreserve(virt_to_page(virt_addr)); 182 | } 183 | 184 | if (kmalloc_ptr) { 185 | kfree(kmalloc_ptr); 186 | } 187 | 188 | kmalloc_len = 0L; 189 | kmalloc_ptr = NULL; 190 | kmalloc_area = NULL; 191 | kcount--; 192 | 193 | if (isearch != kcount) { 194 | kmalloc_drv[isearch].size = kmalloc_drv[kcount].size; 195 | kmalloc_drv[isearch].kmallocptr = kmalloc_drv[kcount].kmallocptr; 196 | kmalloc_drv[isearch].kvirtlen = kmalloc_drv[kcount].kvirtlen; 197 | kmalloc_drv[isearch].kvirtadd = kmalloc_drv[kcount].kvirtadd; 198 | kmalloc_drv[isearch].kphysadd = kmalloc_drv[kcount].kphysadd; 199 | } 200 | 201 | kmalloc_drv[kcount].size = 0; 202 | kmalloc_drv[kcount].kmallocptr = NULL; 203 | kmalloc_drv[kcount].kvirtlen = 0; 204 | kmalloc_drv[kcount].kvirtadd = NULL; 205 | kmalloc_drv[kcount].kphysadd = NULL; 206 | } 207 | return 0; 208 | } 209 | case CMD_LOCK_KB: 210 | disable_irq(1); 211 | return 0; 212 | case CMD_UNLOCK_KB: 213 | enable_irq(1); 214 | return 0; 215 | } 216 | return -ENOTTY; 217 | } 218 | 219 | int 220 | AMI_chrdrv_mmap(struct file* file, struct vm_area_struct* vma) 221 | { 222 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 223 | unsigned long size = vma->vm_end - vma->vm_start; 224 | 225 | if (offset & ~PAGE_MASK) { 226 | return -ENXIO; 227 | } 228 | if (!kmalloc_ptr) { 229 | return(-ENXIO); 230 | } 231 | if (size > kmalloc_len) { 232 | return(-ENXIO); 233 | } 234 | if ((offset+size) > kmalloc_len) { 235 | return -ENXIO; 236 | } 237 | if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { 238 | return(-EINVAL); 239 | } 240 | 241 | vma->vm_flags |= VM_LOCKED; 242 | 243 | { 244 | unsigned long pfn = virt_to_phys((void*)((unsigned long) kmalloc_area)); 245 | 246 | #if LINUX_POST_2_6 247 | int remap_result = 248 | remap_pfn_range(vma, 249 | vma->vm_start, 250 | pfn >> PAGE_SHIFT, 251 | size, 252 | PAGE_SHARED); 253 | #else 254 | int remap_result = 255 | remap_page_range(vma, 256 | vma->vm_start, 257 | pfn, 258 | size, 259 | PAGE_SHARED); 260 | #endif 261 | 262 | if (remap_result) 263 | { 264 | return -ENXIO; 265 | } 266 | } 267 | 268 | return(0); 269 | } 270 | 271 | #if defined(HAVE_UNLOCKED_IOCTL) 272 | # define $IOCTL_FIELD unlocked_ioctl 273 | #else 274 | # define $IOCTL_FIELD ioctl 275 | #endif 276 | 277 | struct file_operations AMI_chrdrv_fops = { 278 | owner: THIS_MODULE, 279 | open: AMI_chrdrv_open, 280 | release: AMI_chrdrv_release, 281 | mmap: AMI_chrdrv_mmap, 282 | $IOCTL_FIELD: AMI_chrdrv_ioctl, 283 | }; 284 | 285 | /* 286 | * Section: Linux Kernel Module Setup 287 | * ============================================================================ 288 | */ 289 | 290 | #if LINUX_POST_2_6 291 | 292 | MODULE_AUTHOR ("American Megatrends Inc."); 293 | MODULE_DESCRIPTION ("AMI Flash Update utility driver"); 294 | MODULE_LICENSE ("Proprietary"); 295 | 296 | #endif 297 | 298 | static int /* module_init */ 299 | amifldrv_init_module(void) 300 | { 301 | major = register_chrdev(0, "amifldrv", &AMI_chrdrv_fops); 302 | 303 | if (major < 0) 304 | { 305 | return -EIO; 306 | } 307 | 308 | memset(kmalloc_drv, 0, sizeof(AMIFL_alloc_params) * 128); 309 | 310 | return(0); 311 | } 312 | 313 | static void /* module_exit */ 314 | amifldrv_cleanup_module(void) 315 | { 316 | unsigned long virt_addr; 317 | if (kcount > 0) 318 | { 319 | { 320 | int iloop; 321 | for (iloop = 0; iloop < kcount; ++iloop) 322 | { 323 | kmalloc_ptr = kmalloc_drv[iloop].kmallocptr; 324 | kmalloc_area = kmalloc_drv[iloop].kvirtadd; 325 | kmalloc_len = kmalloc_drv[iloop].kvirtlen; 326 | if (kmalloc_ptr) 327 | { 328 | for(virt_addr = (unsigned long)kmalloc_area; 329 | virt_addr < (unsigned long)kmalloc_area + kmalloc_len; 330 | virt_addr += PAGE_SIZE) 331 | { 332 | mem_map_unreserve(virt_to_page(virt_addr)); 333 | } 334 | 335 | if (kmalloc_ptr) 336 | { 337 | kfree(kmalloc_ptr); 338 | } 339 | } 340 | } 341 | } 342 | kcount = 0; 343 | } 344 | 345 | unregister_chrdev(major, "amifldrv"); 346 | 347 | return; 348 | } 349 | 350 | module_init(amifldrv_init_module); 351 | module_exit(amifldrv_cleanup_module); 352 | 353 | --------------------------------------------------------------------------------