xref: /openbmc/linux/drivers/firmware/efi/capsule-loader.c (revision 65117f1aa1b2d145fd5ca376bde642794d0aae1b)
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