1*65117f1aSKweh, Hock Leong /* 2*65117f1aSKweh, Hock Leong * EFI capsule loader driver. 3*65117f1aSKweh, Hock Leong * 4*65117f1aSKweh, Hock Leong * Copyright 2015 Intel Corporation 5*65117f1aSKweh, Hock Leong * 6*65117f1aSKweh, Hock Leong * This file is part of the Linux kernel, and is made available under 7*65117f1aSKweh, Hock Leong * the terms of the GNU General Public License version 2. 8*65117f1aSKweh, Hock Leong */ 9*65117f1aSKweh, Hock Leong 10*65117f1aSKweh, Hock Leong #define pr_fmt(fmt) "efi: " fmt 11*65117f1aSKweh, Hock Leong 12*65117f1aSKweh, Hock Leong #include <linux/kernel.h> 13*65117f1aSKweh, Hock Leong #include <linux/module.h> 14*65117f1aSKweh, Hock Leong #include <linux/miscdevice.h> 15*65117f1aSKweh, Hock Leong #include <linux/highmem.h> 16*65117f1aSKweh, Hock Leong #include <linux/slab.h> 17*65117f1aSKweh, Hock Leong #include <linux/mutex.h> 18*65117f1aSKweh, Hock Leong #include <linux/efi.h> 19*65117f1aSKweh, Hock Leong 20*65117f1aSKweh, Hock Leong #define NO_FURTHER_WRITE_ACTION -1 21*65117f1aSKweh, Hock Leong 22*65117f1aSKweh, Hock Leong struct capsule_info { 23*65117f1aSKweh, Hock Leong bool header_obtained; 24*65117f1aSKweh, Hock Leong int reset_type; 25*65117f1aSKweh, Hock Leong long index; 26*65117f1aSKweh, Hock Leong size_t count; 27*65117f1aSKweh, Hock Leong size_t total_size; 28*65117f1aSKweh, Hock Leong struct page **pages; 29*65117f1aSKweh, Hock Leong size_t page_bytes_remain; 30*65117f1aSKweh, Hock Leong }; 31*65117f1aSKweh, Hock Leong 32*65117f1aSKweh, Hock Leong /** 33*65117f1aSKweh, Hock Leong * efi_free_all_buff_pages - free all previous allocated buffer pages 34*65117f1aSKweh, Hock Leong * @cap_info: pointer to current instance of capsule_info structure 35*65117f1aSKweh, Hock Leong * 36*65117f1aSKweh, Hock Leong * In addition to freeing buffer pages, it flags NO_FURTHER_WRITE_ACTION 37*65117f1aSKweh, Hock Leong * to cease processing data in subsequent write(2) calls until close(2) 38*65117f1aSKweh, Hock Leong * is called. 39*65117f1aSKweh, Hock Leong **/ 40*65117f1aSKweh, Hock Leong static void efi_free_all_buff_pages(struct capsule_info *cap_info) 41*65117f1aSKweh, Hock Leong { 42*65117f1aSKweh, Hock Leong while (cap_info->index > 0) 43*65117f1aSKweh, Hock Leong __free_page(cap_info->pages[--cap_info->index]); 44*65117f1aSKweh, Hock Leong 45*65117f1aSKweh, Hock Leong cap_info->index = NO_FURTHER_WRITE_ACTION; 46*65117f1aSKweh, Hock Leong } 47*65117f1aSKweh, Hock Leong 48*65117f1aSKweh, Hock Leong /** 49*65117f1aSKweh, Hock Leong * efi_capsule_setup_info - obtain the efi capsule header in the binary and 50*65117f1aSKweh, Hock Leong * setup capsule_info structure 51*65117f1aSKweh, Hock Leong * @cap_info: pointer to current instance of capsule_info structure 52*65117f1aSKweh, Hock Leong * @kbuff: a mapped first page buffer pointer 53*65117f1aSKweh, Hock Leong * @hdr_bytes: the total received number of bytes for efi header 54*65117f1aSKweh, Hock Leong **/ 55*65117f1aSKweh, Hock Leong static ssize_t efi_capsule_setup_info(struct capsule_info *cap_info, 56*65117f1aSKweh, Hock Leong void *kbuff, size_t hdr_bytes) 57*65117f1aSKweh, Hock Leong { 58*65117f1aSKweh, Hock Leong efi_capsule_header_t *cap_hdr; 59*65117f1aSKweh, Hock Leong size_t pages_needed; 60*65117f1aSKweh, Hock Leong int ret; 61*65117f1aSKweh, Hock Leong void *temp_page; 62*65117f1aSKweh, Hock Leong 63*65117f1aSKweh, Hock Leong /* Only process data block that is larger than efi header size */ 64*65117f1aSKweh, Hock Leong if (hdr_bytes < sizeof(efi_capsule_header_t)) 65*65117f1aSKweh, Hock Leong return 0; 66*65117f1aSKweh, Hock Leong 67*65117f1aSKweh, Hock Leong /* Reset back to the correct offset of header */ 68*65117f1aSKweh, Hock Leong cap_hdr = kbuff - cap_info->count; 69*65117f1aSKweh, Hock Leong pages_needed = ALIGN(cap_hdr->imagesize, PAGE_SIZE) >> PAGE_SHIFT; 70*65117f1aSKweh, Hock Leong 71*65117f1aSKweh, Hock Leong if (pages_needed == 0) { 72*65117f1aSKweh, Hock Leong pr_err("%s: pages count invalid\n", __func__); 73*65117f1aSKweh, Hock Leong return -EINVAL; 74*65117f1aSKweh, Hock Leong } 75*65117f1aSKweh, Hock Leong 76*65117f1aSKweh, Hock Leong /* Check if the capsule binary supported */ 77*65117f1aSKweh, Hock Leong ret = efi_capsule_supported(cap_hdr->guid, cap_hdr->flags, 78*65117f1aSKweh, Hock Leong cap_hdr->imagesize, 79*65117f1aSKweh, Hock Leong &cap_info->reset_type); 80*65117f1aSKweh, Hock Leong if (ret) { 81*65117f1aSKweh, Hock Leong pr_err("%s: efi_capsule_supported() failed\n", 82*65117f1aSKweh, Hock Leong __func__); 83*65117f1aSKweh, Hock Leong return ret; 84*65117f1aSKweh, Hock Leong } 85*65117f1aSKweh, Hock Leong 86*65117f1aSKweh, Hock Leong cap_info->total_size = cap_hdr->imagesize; 87*65117f1aSKweh, Hock Leong temp_page = krealloc(cap_info->pages, 88*65117f1aSKweh, Hock Leong pages_needed * sizeof(void *), 89*65117f1aSKweh, Hock Leong GFP_KERNEL | __GFP_ZERO); 90*65117f1aSKweh, Hock Leong if (!temp_page) { 91*65117f1aSKweh, Hock Leong pr_debug("%s: krealloc() failed\n", __func__); 92*65117f1aSKweh, Hock Leong return -ENOMEM; 93*65117f1aSKweh, Hock Leong } 94*65117f1aSKweh, Hock Leong 95*65117f1aSKweh, Hock Leong cap_info->pages = temp_page; 96*65117f1aSKweh, Hock Leong cap_info->header_obtained = true; 97*65117f1aSKweh, Hock Leong 98*65117f1aSKweh, Hock Leong return 0; 99*65117f1aSKweh, Hock Leong } 100*65117f1aSKweh, Hock Leong 101*65117f1aSKweh, Hock Leong /** 102*65117f1aSKweh, Hock Leong * efi_capsule_submit_update - invoke the efi_capsule_update API once binary 103*65117f1aSKweh, Hock Leong * upload done 104*65117f1aSKweh, Hock Leong * @cap_info: pointer to current instance of capsule_info structure 105*65117f1aSKweh, Hock Leong **/ 106*65117f1aSKweh, Hock Leong static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) 107*65117f1aSKweh, Hock Leong { 108*65117f1aSKweh, Hock Leong int ret; 109*65117f1aSKweh, Hock Leong void *cap_hdr_temp; 110*65117f1aSKweh, Hock Leong 111*65117f1aSKweh, Hock Leong cap_hdr_temp = kmap(cap_info->pages[0]); 112*65117f1aSKweh, Hock Leong if (!cap_hdr_temp) { 113*65117f1aSKweh, Hock Leong pr_debug("%s: kmap() failed\n", __func__); 114*65117f1aSKweh, Hock Leong return -EFAULT; 115*65117f1aSKweh, Hock Leong } 116*65117f1aSKweh, Hock Leong 117*65117f1aSKweh, Hock Leong ret = efi_capsule_update(cap_hdr_temp, cap_info->pages); 118*65117f1aSKweh, Hock Leong kunmap(cap_info->pages[0]); 119*65117f1aSKweh, Hock Leong if (ret) { 120*65117f1aSKweh, Hock Leong pr_err("%s: efi_capsule_update() failed\n", __func__); 121*65117f1aSKweh, Hock Leong return ret; 122*65117f1aSKweh, Hock Leong } 123*65117f1aSKweh, Hock Leong 124*65117f1aSKweh, Hock Leong /* Indicate capsule binary uploading is done */ 125*65117f1aSKweh, Hock Leong cap_info->index = NO_FURTHER_WRITE_ACTION; 126*65117f1aSKweh, Hock Leong pr_info("%s: Successfully upload capsule file with reboot type '%s'\n", 127*65117f1aSKweh, Hock Leong __func__, !cap_info->reset_type ? "RESET_COLD" : 128*65117f1aSKweh, Hock Leong cap_info->reset_type == 1 ? "RESET_WARM" : 129*65117f1aSKweh, Hock Leong "RESET_SHUTDOWN"); 130*65117f1aSKweh, Hock Leong return 0; 131*65117f1aSKweh, Hock Leong } 132*65117f1aSKweh, Hock Leong 133*65117f1aSKweh, Hock Leong /** 134*65117f1aSKweh, Hock Leong * efi_capsule_write - store the capsule binary and pass it to 135*65117f1aSKweh, Hock Leong * efi_capsule_update() API 136*65117f1aSKweh, Hock Leong * @file: file pointer 137*65117f1aSKweh, Hock Leong * @buff: buffer pointer 138*65117f1aSKweh, Hock Leong * @count: number of bytes in @buff 139*65117f1aSKweh, Hock Leong * @offp: not used 140*65117f1aSKweh, Hock Leong * 141*65117f1aSKweh, Hock Leong * Expectation: 142*65117f1aSKweh, Hock Leong * - A user space tool should start at the beginning of capsule binary and 143*65117f1aSKweh, Hock Leong * pass data in sequentially. 144*65117f1aSKweh, Hock Leong * - Users should close and re-open this file note in order to upload more 145*65117f1aSKweh, Hock Leong * capsules. 146*65117f1aSKweh, Hock Leong * - After an error returned, user should close the file and restart the 147*65117f1aSKweh, Hock Leong * operation for the next try otherwise -EIO will be returned until the 148*65117f1aSKweh, Hock Leong * file is closed. 149*65117f1aSKweh, Hock Leong * - An EFI capsule header must be located at the beginning of capsule 150*65117f1aSKweh, Hock Leong * binary file and passed in as first block data of write operation. 151*65117f1aSKweh, Hock Leong **/ 152*65117f1aSKweh, Hock Leong static ssize_t efi_capsule_write(struct file *file, const char __user *buff, 153*65117f1aSKweh, Hock Leong size_t count, loff_t *offp) 154*65117f1aSKweh, Hock Leong { 155*65117f1aSKweh, Hock Leong int ret = 0; 156*65117f1aSKweh, Hock Leong struct capsule_info *cap_info = file->private_data; 157*65117f1aSKweh, Hock Leong struct page *page; 158*65117f1aSKweh, Hock Leong void *kbuff = NULL; 159*65117f1aSKweh, Hock Leong size_t write_byte; 160*65117f1aSKweh, Hock Leong 161*65117f1aSKweh, Hock Leong if (count == 0) 162*65117f1aSKweh, Hock Leong return 0; 163*65117f1aSKweh, Hock Leong 164*65117f1aSKweh, Hock Leong /* Return error while NO_FURTHER_WRITE_ACTION is flagged */ 165*65117f1aSKweh, Hock Leong if (cap_info->index < 0) 166*65117f1aSKweh, Hock Leong return -EIO; 167*65117f1aSKweh, Hock Leong 168*65117f1aSKweh, Hock Leong /* Only alloc a new page when previous page is full */ 169*65117f1aSKweh, Hock Leong if (!cap_info->page_bytes_remain) { 170*65117f1aSKweh, Hock Leong page = alloc_page(GFP_KERNEL); 171*65117f1aSKweh, Hock Leong if (!page) { 172*65117f1aSKweh, Hock Leong pr_debug("%s: alloc_page() failed\n", __func__); 173*65117f1aSKweh, Hock Leong ret = -ENOMEM; 174*65117f1aSKweh, Hock Leong goto failed; 175*65117f1aSKweh, Hock Leong } 176*65117f1aSKweh, Hock Leong 177*65117f1aSKweh, Hock Leong cap_info->pages[cap_info->index++] = page; 178*65117f1aSKweh, Hock Leong cap_info->page_bytes_remain = PAGE_SIZE; 179*65117f1aSKweh, Hock Leong } 180*65117f1aSKweh, Hock Leong 181*65117f1aSKweh, Hock Leong page = cap_info->pages[cap_info->index - 1]; 182*65117f1aSKweh, Hock Leong 183*65117f1aSKweh, Hock Leong kbuff = kmap(page); 184*65117f1aSKweh, Hock Leong if (!kbuff) { 185*65117f1aSKweh, Hock Leong pr_debug("%s: kmap() failed\n", __func__); 186*65117f1aSKweh, Hock Leong ret = -EFAULT; 187*65117f1aSKweh, Hock Leong goto failed; 188*65117f1aSKweh, Hock Leong } 189*65117f1aSKweh, Hock Leong kbuff += PAGE_SIZE - cap_info->page_bytes_remain; 190*65117f1aSKweh, Hock Leong 191*65117f1aSKweh, Hock Leong /* Copy capsule binary data from user space to kernel space buffer */ 192*65117f1aSKweh, Hock Leong write_byte = min_t(size_t, count, cap_info->page_bytes_remain); 193*65117f1aSKweh, Hock Leong if (copy_from_user(kbuff, buff, write_byte)) { 194*65117f1aSKweh, Hock Leong pr_debug("%s: copy_from_user() failed\n", __func__); 195*65117f1aSKweh, Hock Leong ret = -EFAULT; 196*65117f1aSKweh, Hock Leong goto fail_unmap; 197*65117f1aSKweh, Hock Leong } 198*65117f1aSKweh, Hock Leong cap_info->page_bytes_remain -= write_byte; 199*65117f1aSKweh, Hock Leong 200*65117f1aSKweh, Hock Leong /* Setup capsule binary info structure */ 201*65117f1aSKweh, Hock Leong if (!cap_info->header_obtained) { 202*65117f1aSKweh, Hock Leong ret = efi_capsule_setup_info(cap_info, kbuff, 203*65117f1aSKweh, Hock Leong cap_info->count + write_byte); 204*65117f1aSKweh, Hock Leong if (ret) 205*65117f1aSKweh, Hock Leong goto fail_unmap; 206*65117f1aSKweh, Hock Leong } 207*65117f1aSKweh, Hock Leong 208*65117f1aSKweh, Hock Leong cap_info->count += write_byte; 209*65117f1aSKweh, Hock Leong kunmap(page); 210*65117f1aSKweh, Hock Leong 211*65117f1aSKweh, Hock Leong /* Submit the full binary to efi_capsule_update() API */ 212*65117f1aSKweh, Hock Leong if (cap_info->header_obtained && 213*65117f1aSKweh, Hock Leong cap_info->count >= cap_info->total_size) { 214*65117f1aSKweh, Hock Leong if (cap_info->count > cap_info->total_size) { 215*65117f1aSKweh, Hock Leong pr_err("%s: upload size exceeded header defined size\n", 216*65117f1aSKweh, Hock Leong __func__); 217*65117f1aSKweh, Hock Leong ret = -EINVAL; 218*65117f1aSKweh, Hock Leong goto failed; 219*65117f1aSKweh, Hock Leong } 220*65117f1aSKweh, Hock Leong 221*65117f1aSKweh, Hock Leong ret = efi_capsule_submit_update(cap_info); 222*65117f1aSKweh, Hock Leong if (ret) 223*65117f1aSKweh, Hock Leong goto failed; 224*65117f1aSKweh, Hock Leong } 225*65117f1aSKweh, Hock Leong 226*65117f1aSKweh, Hock Leong return write_byte; 227*65117f1aSKweh, Hock Leong 228*65117f1aSKweh, Hock Leong fail_unmap: 229*65117f1aSKweh, Hock Leong kunmap(page); 230*65117f1aSKweh, Hock Leong failed: 231*65117f1aSKweh, Hock Leong efi_free_all_buff_pages(cap_info); 232*65117f1aSKweh, Hock Leong return ret; 233*65117f1aSKweh, Hock Leong } 234*65117f1aSKweh, Hock Leong 235*65117f1aSKweh, Hock Leong /** 236*65117f1aSKweh, Hock Leong * efi_capsule_flush - called by file close or file flush 237*65117f1aSKweh, Hock Leong * @file: file pointer 238*65117f1aSKweh, Hock Leong * @id: not used 239*65117f1aSKweh, Hock Leong * 240*65117f1aSKweh, Hock Leong * If a capsule is being partially uploaded then calling this function 241*65117f1aSKweh, Hock Leong * will be treated as upload termination and will free those completed 242*65117f1aSKweh, Hock Leong * buffer pages and -ECANCELED will be returned. 243*65117f1aSKweh, Hock Leong **/ 244*65117f1aSKweh, Hock Leong static int efi_capsule_flush(struct file *file, fl_owner_t id) 245*65117f1aSKweh, Hock Leong { 246*65117f1aSKweh, Hock Leong int ret = 0; 247*65117f1aSKweh, Hock Leong struct capsule_info *cap_info = file->private_data; 248*65117f1aSKweh, Hock Leong 249*65117f1aSKweh, Hock Leong if (cap_info->index > 0) { 250*65117f1aSKweh, Hock Leong pr_err("%s: capsule upload not complete\n", __func__); 251*65117f1aSKweh, Hock Leong efi_free_all_buff_pages(cap_info); 252*65117f1aSKweh, Hock Leong ret = -ECANCELED; 253*65117f1aSKweh, Hock Leong } 254*65117f1aSKweh, Hock Leong 255*65117f1aSKweh, Hock Leong return ret; 256*65117f1aSKweh, Hock Leong } 257*65117f1aSKweh, Hock Leong 258*65117f1aSKweh, Hock Leong /** 259*65117f1aSKweh, Hock Leong * efi_capsule_release - called by file close 260*65117f1aSKweh, Hock Leong * @inode: not used 261*65117f1aSKweh, Hock Leong * @file: file pointer 262*65117f1aSKweh, Hock Leong * 263*65117f1aSKweh, Hock Leong * We will not free successfully submitted pages since efi update 264*65117f1aSKweh, Hock Leong * requires data to be maintained across system reboot. 265*65117f1aSKweh, Hock Leong **/ 266*65117f1aSKweh, Hock Leong static int efi_capsule_release(struct inode *inode, struct file *file) 267*65117f1aSKweh, Hock Leong { 268*65117f1aSKweh, Hock Leong struct capsule_info *cap_info = file->private_data; 269*65117f1aSKweh, Hock Leong 270*65117f1aSKweh, Hock Leong kfree(cap_info->pages); 271*65117f1aSKweh, Hock Leong kfree(file->private_data); 272*65117f1aSKweh, Hock Leong file->private_data = NULL; 273*65117f1aSKweh, Hock Leong return 0; 274*65117f1aSKweh, Hock Leong } 275*65117f1aSKweh, Hock Leong 276*65117f1aSKweh, Hock Leong /** 277*65117f1aSKweh, Hock Leong * efi_capsule_open - called by file open 278*65117f1aSKweh, Hock Leong * @inode: not used 279*65117f1aSKweh, Hock Leong * @file: file pointer 280*65117f1aSKweh, Hock Leong * 281*65117f1aSKweh, Hock Leong * Will allocate each capsule_info memory for each file open call. 282*65117f1aSKweh, Hock Leong * This provided the capability to support multiple file open feature 283*65117f1aSKweh, Hock Leong * where user is not needed to wait for others to finish in order to 284*65117f1aSKweh, Hock Leong * upload their capsule binary. 285*65117f1aSKweh, Hock Leong **/ 286*65117f1aSKweh, Hock Leong static int efi_capsule_open(struct inode *inode, struct file *file) 287*65117f1aSKweh, Hock Leong { 288*65117f1aSKweh, Hock Leong struct capsule_info *cap_info; 289*65117f1aSKweh, Hock Leong 290*65117f1aSKweh, Hock Leong cap_info = kzalloc(sizeof(*cap_info), GFP_KERNEL); 291*65117f1aSKweh, Hock Leong if (!cap_info) 292*65117f1aSKweh, Hock Leong return -ENOMEM; 293*65117f1aSKweh, Hock Leong 294*65117f1aSKweh, Hock Leong cap_info->pages = kzalloc(sizeof(void *), GFP_KERNEL); 295*65117f1aSKweh, Hock Leong if (!cap_info->pages) { 296*65117f1aSKweh, Hock Leong kfree(cap_info); 297*65117f1aSKweh, Hock Leong return -ENOMEM; 298*65117f1aSKweh, Hock Leong } 299*65117f1aSKweh, Hock Leong 300*65117f1aSKweh, Hock Leong file->private_data = cap_info; 301*65117f1aSKweh, Hock Leong 302*65117f1aSKweh, Hock Leong return 0; 303*65117f1aSKweh, Hock Leong } 304*65117f1aSKweh, Hock Leong 305*65117f1aSKweh, Hock Leong static const struct file_operations efi_capsule_fops = { 306*65117f1aSKweh, Hock Leong .owner = THIS_MODULE, 307*65117f1aSKweh, Hock Leong .open = efi_capsule_open, 308*65117f1aSKweh, Hock Leong .write = efi_capsule_write, 309*65117f1aSKweh, Hock Leong .flush = efi_capsule_flush, 310*65117f1aSKweh, Hock Leong .release = efi_capsule_release, 311*65117f1aSKweh, Hock Leong .llseek = no_llseek, 312*65117f1aSKweh, Hock Leong }; 313*65117f1aSKweh, Hock Leong 314*65117f1aSKweh, Hock Leong static struct miscdevice efi_capsule_misc = { 315*65117f1aSKweh, Hock Leong .minor = MISC_DYNAMIC_MINOR, 316*65117f1aSKweh, Hock Leong .name = "efi_capsule_loader", 317*65117f1aSKweh, Hock Leong .fops = &efi_capsule_fops, 318*65117f1aSKweh, Hock Leong }; 319*65117f1aSKweh, Hock Leong 320*65117f1aSKweh, Hock Leong static int __init efi_capsule_loader_init(void) 321*65117f1aSKweh, Hock Leong { 322*65117f1aSKweh, Hock Leong int ret; 323*65117f1aSKweh, Hock Leong 324*65117f1aSKweh, Hock Leong if (!efi_enabled(EFI_RUNTIME_SERVICES)) 325*65117f1aSKweh, Hock Leong return -ENODEV; 326*65117f1aSKweh, Hock Leong 327*65117f1aSKweh, Hock Leong ret = misc_register(&efi_capsule_misc); 328*65117f1aSKweh, Hock Leong if (ret) 329*65117f1aSKweh, Hock Leong pr_err("%s: Failed to register misc char file note\n", 330*65117f1aSKweh, Hock Leong __func__); 331*65117f1aSKweh, Hock Leong 332*65117f1aSKweh, Hock Leong return ret; 333*65117f1aSKweh, Hock Leong } 334*65117f1aSKweh, Hock Leong module_init(efi_capsule_loader_init); 335*65117f1aSKweh, Hock Leong 336*65117f1aSKweh, Hock Leong static void __exit efi_capsule_loader_exit(void) 337*65117f1aSKweh, Hock Leong { 338*65117f1aSKweh, Hock Leong misc_deregister(&efi_capsule_misc); 339*65117f1aSKweh, Hock Leong } 340*65117f1aSKweh, Hock Leong module_exit(efi_capsule_loader_exit); 341*65117f1aSKweh, Hock Leong 342*65117f1aSKweh, Hock Leong MODULE_DESCRIPTION("EFI capsule firmware binary loader"); 343*65117f1aSKweh, Hock Leong MODULE_LICENSE("GPL v2"); 344