1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2008 - 2009
3*4882a593Smuzhiyun * Windriver, <www.windriver.com>
4*4882a593Smuzhiyun * Tom Rix <Tom.Rix@windriver.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Copyright 2014 Linaro, Ltd.
9*4882a593Smuzhiyun * Rob Herring <robh@kernel.org>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun #include <config.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <console.h>
16*4882a593Smuzhiyun #include <android_bootloader.h>
17*4882a593Smuzhiyun #include <errno.h>
18*4882a593Smuzhiyun #include <fastboot.h>
19*4882a593Smuzhiyun #include <malloc.h>
20*4882a593Smuzhiyun #include <linux/usb/ch9.h>
21*4882a593Smuzhiyun #include <linux/usb/gadget.h>
22*4882a593Smuzhiyun #include <linux/usb/composite.h>
23*4882a593Smuzhiyun #include <linux/compiler.h>
24*4882a593Smuzhiyun #include <u-boot/sha256.h>
25*4882a593Smuzhiyun #include <version.h>
26*4882a593Smuzhiyun #include <g_dnl.h>
27*4882a593Smuzhiyun #include <fs.h>
28*4882a593Smuzhiyun #include <android_avb/avb_ops_user.h>
29*4882a593Smuzhiyun #include <android_avb/rk_avb_ops_user.h>
30*4882a593Smuzhiyun #include <dm/uclass.h>
31*4882a593Smuzhiyun #include <power/fuel_gauge.h>
32*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
33*4882a593Smuzhiyun #include <fb_mmc.h>
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
36*4882a593Smuzhiyun #include <fb_nand.h>
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
39*4882a593Smuzhiyun #include <optee_include/OpteeClientInterface.h>
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun #include <boot_rkimg.h>
42*4882a593Smuzhiyun #include <optee_include/tee_client_api.h>
43*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
44*4882a593Smuzhiyun #include <keymaster.h>
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
47*4882a593Smuzhiyun #include <android_ab.h>
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define FASTBOOT_VERSION "0.4"
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_CLASS 0xff
53*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_SUB_CLASS 0x42
54*4882a593Smuzhiyun #define FASTBOOT_INTERFACE_PROTOCOL 0x03
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
57*4882a593Smuzhiyun #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
58*4882a593Smuzhiyun #define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define EP_BUFFER_SIZE 4096
61*4882a593Smuzhiyun #define SLEEP_COUNT 20000
62*4882a593Smuzhiyun #define MAX_PART_NUM_STR_SIZE 4
63*4882a593Smuzhiyun #define PARTITION_TYPE_STRINGS "partition-type"
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
67*4882a593Smuzhiyun * (64 or 512 or 1024), else we break on certain controllers like DWC3
68*4882a593Smuzhiyun * that expect bulk OUT requests to be divisible by maxpacket size.
69*4882a593Smuzhiyun */
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun struct f_fastboot {
72*4882a593Smuzhiyun struct usb_function usb_function;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* IN/OUT EP's and corresponding requests */
75*4882a593Smuzhiyun struct usb_ep *in_ep, *out_ep;
76*4882a593Smuzhiyun struct usb_request *in_req, *out_req;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun
func_to_fastboot(struct usb_function * f)79*4882a593Smuzhiyun static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun return container_of(f, struct f_fastboot, usb_function);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static struct f_fastboot *fastboot_func;
85*4882a593Smuzhiyun static unsigned int download_size;
86*4882a593Smuzhiyun static unsigned int download_bytes;
87*4882a593Smuzhiyun static unsigned int upload_size;
88*4882a593Smuzhiyun static unsigned int upload_bytes;
89*4882a593Smuzhiyun static bool start_upload;
90*4882a593Smuzhiyun static unsigned intthread_wakeup_needed;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static struct usb_endpoint_descriptor fs_ep_in = {
93*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
94*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
95*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
96*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
97*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(64),
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static struct usb_endpoint_descriptor fs_ep_out = {
101*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
102*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
103*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
104*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
105*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(64),
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static struct usb_endpoint_descriptor hs_ep_in = {
109*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
110*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
111*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
112*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
113*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(512),
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static struct usb_endpoint_descriptor hs_ep_out = {
117*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
118*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
119*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
120*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
121*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(512),
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun static struct usb_endpoint_descriptor ss_ep_in = {
125*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
126*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
127*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
128*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
129*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(1024),
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = {
133*4882a593Smuzhiyun .bLength = sizeof(ss_ep_in_comp_desc),
134*4882a593Smuzhiyun .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
135*4882a593Smuzhiyun /* .bMaxBurst = DYNAMIC, */
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static struct usb_endpoint_descriptor ss_ep_out = {
139*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
140*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
141*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
142*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
143*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(1024),
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {
147*4882a593Smuzhiyun .bLength = sizeof(ss_ep_out_comp_desc),
148*4882a593Smuzhiyun .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
149*4882a593Smuzhiyun /* .bMaxBurst = DYNAMIC, */
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static struct usb_interface_descriptor interface_desc = {
153*4882a593Smuzhiyun .bLength = USB_DT_INTERFACE_SIZE,
154*4882a593Smuzhiyun .bDescriptorType = USB_DT_INTERFACE,
155*4882a593Smuzhiyun .bInterfaceNumber = 0x00,
156*4882a593Smuzhiyun .bAlternateSetting = 0x00,
157*4882a593Smuzhiyun .bNumEndpoints = 0x02,
158*4882a593Smuzhiyun .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
159*4882a593Smuzhiyun .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
160*4882a593Smuzhiyun .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun static struct usb_descriptor_header *fb_fs_function[] = {
164*4882a593Smuzhiyun (struct usb_descriptor_header *)&interface_desc,
165*4882a593Smuzhiyun (struct usb_descriptor_header *)&fs_ep_in,
166*4882a593Smuzhiyun (struct usb_descriptor_header *)&fs_ep_out,
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun static struct usb_descriptor_header *fb_hs_function[] = {
170*4882a593Smuzhiyun (struct usb_descriptor_header *)&interface_desc,
171*4882a593Smuzhiyun (struct usb_descriptor_header *)&hs_ep_in,
172*4882a593Smuzhiyun (struct usb_descriptor_header *)&hs_ep_out,
173*4882a593Smuzhiyun NULL,
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun static struct usb_descriptor_header *fb_ss_function[] = {
177*4882a593Smuzhiyun (struct usb_descriptor_header *)&interface_desc,
178*4882a593Smuzhiyun (struct usb_descriptor_header *)&ss_ep_in,
179*4882a593Smuzhiyun (struct usb_descriptor_header *)&ss_ep_in_comp_desc,
180*4882a593Smuzhiyun (struct usb_descriptor_header *)&ss_ep_out,
181*4882a593Smuzhiyun (struct usb_descriptor_header *)&ss_ep_out_comp_desc,
182*4882a593Smuzhiyun NULL,
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun static struct usb_endpoint_descriptor *
fb_ep_desc(struct usb_gadget * g,struct usb_endpoint_descriptor * fs,struct usb_endpoint_descriptor * hs,struct usb_endpoint_descriptor * ss,struct usb_ss_ep_comp_descriptor * comp_desc,struct usb_ep * ep)186*4882a593Smuzhiyun fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
187*4882a593Smuzhiyun struct usb_endpoint_descriptor *hs,
188*4882a593Smuzhiyun struct usb_endpoint_descriptor *ss,
189*4882a593Smuzhiyun struct usb_ss_ep_comp_descriptor *comp_desc,
190*4882a593Smuzhiyun struct usb_ep *ep)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct usb_endpoint_descriptor *speed_desc = NULL;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* select desired speed */
195*4882a593Smuzhiyun switch (g->speed) {
196*4882a593Smuzhiyun case USB_SPEED_SUPER:
197*4882a593Smuzhiyun if (gadget_is_superspeed(g)) {
198*4882a593Smuzhiyun speed_desc = ss;
199*4882a593Smuzhiyun ep->comp_desc = comp_desc;
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun /* else: Fall trough */
203*4882a593Smuzhiyun case USB_SPEED_HIGH:
204*4882a593Smuzhiyun if (gadget_is_dualspeed(g)) {
205*4882a593Smuzhiyun speed_desc = hs;
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun /* else: fall through */
209*4882a593Smuzhiyun default:
210*4882a593Smuzhiyun speed_desc = fs;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun return speed_desc;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun * static strings, in UTF-8
218*4882a593Smuzhiyun */
219*4882a593Smuzhiyun static const char fastboot_name[] = "Android Fastboot";
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun static struct usb_string fastboot_string_defs[] = {
222*4882a593Smuzhiyun [0].s = fastboot_name,
223*4882a593Smuzhiyun { } /* end of list */
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_fastboot = {
227*4882a593Smuzhiyun .language = 0x0409, /* en-us */
228*4882a593Smuzhiyun .strings = fastboot_string_defs,
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun static struct usb_gadget_strings *fastboot_strings[] = {
232*4882a593Smuzhiyun &stringtab_fastboot,
233*4882a593Smuzhiyun NULL,
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
237*4882a593Smuzhiyun static int strcmp_l1(const char *s1, const char *s2);
wakeup_thread(void)238*4882a593Smuzhiyun static void wakeup_thread(void)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun intthread_wakeup_needed = false;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
busy_indicator(void)243*4882a593Smuzhiyun static void busy_indicator(void)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun static int state;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun switch (state) {
248*4882a593Smuzhiyun case 0:
249*4882a593Smuzhiyun puts("\r|"); break;
250*4882a593Smuzhiyun case 1:
251*4882a593Smuzhiyun puts("\r/"); break;
252*4882a593Smuzhiyun case 2:
253*4882a593Smuzhiyun puts("\r-"); break;
254*4882a593Smuzhiyun case 3:
255*4882a593Smuzhiyun puts("\r\\"); break;
256*4882a593Smuzhiyun case 4:
257*4882a593Smuzhiyun puts("\r|"); break;
258*4882a593Smuzhiyun case 5:
259*4882a593Smuzhiyun puts("\r/"); break;
260*4882a593Smuzhiyun case 6:
261*4882a593Smuzhiyun puts("\r-"); break;
262*4882a593Smuzhiyun case 7:
263*4882a593Smuzhiyun puts("\r\\"); break;
264*4882a593Smuzhiyun default:
265*4882a593Smuzhiyun state = 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun if (state++ == 8)
268*4882a593Smuzhiyun state = 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
fb_get_fstype(const char * ifname,const int part_num,const char ** fs_type)271*4882a593Smuzhiyun static int fb_get_fstype(const char *ifname, const int part_num,
272*4882a593Smuzhiyun const char **fs_type)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun char part_num_str[MAX_PART_NUM_STR_SIZE] = {0};
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun snprintf(part_num_str, ARRAY_SIZE(part_num_str), ":%x", part_num);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (fs_set_blk_dev(ifname, part_num_str, FS_TYPE_ANY))
279*4882a593Smuzhiyun return -1;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (fs_get_fstype(fs_type))
282*4882a593Smuzhiyun return -1;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
sleep_thread(void)287*4882a593Smuzhiyun static int sleep_thread(void)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int rc = 0;
290*4882a593Smuzhiyun int i = 0, k = 0;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /* Wait until a signal arrives or we are woken up */
293*4882a593Smuzhiyun for (;;) {
294*4882a593Smuzhiyun if (!intthread_wakeup_needed)
295*4882a593Smuzhiyun break;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun if (++i == SLEEP_COUNT) {
298*4882a593Smuzhiyun busy_indicator();
299*4882a593Smuzhiyun i = 0;
300*4882a593Smuzhiyun k++;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (k == 10) {
304*4882a593Smuzhiyun /* Handle CTRL+C */
305*4882a593Smuzhiyun if (ctrlc())
306*4882a593Smuzhiyun return -EPIPE;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* Check cable connection */
309*4882a593Smuzhiyun if (!g_dnl_board_usb_cable_connected())
310*4882a593Smuzhiyun return -EIO;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun k = 0;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun usb_gadget_handle_interrupts(0);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun intthread_wakeup_needed = true;
318*4882a593Smuzhiyun return rc;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
fastboot_complete(struct usb_ep * ep,struct usb_request * req)321*4882a593Smuzhiyun static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun int status = req->status;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun wakeup_thread();
326*4882a593Smuzhiyun if (!status)
327*4882a593Smuzhiyun return;
328*4882a593Smuzhiyun printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
fastboot_bind(struct usb_configuration * c,struct usb_function * f)331*4882a593Smuzhiyun static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun int id;
334*4882a593Smuzhiyun struct usb_gadget *gadget = c->cdev->gadget;
335*4882a593Smuzhiyun struct f_fastboot *f_fb = func_to_fastboot(f);
336*4882a593Smuzhiyun const char *s;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* DYNAMIC interface numbers assignments */
339*4882a593Smuzhiyun id = usb_interface_id(c, f);
340*4882a593Smuzhiyun if (id < 0)
341*4882a593Smuzhiyun return id;
342*4882a593Smuzhiyun interface_desc.bInterfaceNumber = id;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun id = usb_string_id(c->cdev);
345*4882a593Smuzhiyun if (id < 0)
346*4882a593Smuzhiyun return id;
347*4882a593Smuzhiyun fastboot_string_defs[0].id = id;
348*4882a593Smuzhiyun interface_desc.iInterface = id;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
351*4882a593Smuzhiyun if (!f_fb->in_ep)
352*4882a593Smuzhiyun return -ENODEV;
353*4882a593Smuzhiyun f_fb->in_ep->driver_data = c->cdev;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
356*4882a593Smuzhiyun if (!f_fb->out_ep)
357*4882a593Smuzhiyun return -ENODEV;
358*4882a593Smuzhiyun f_fb->out_ep->driver_data = c->cdev;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun f->descriptors = fb_fs_function;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (gadget_is_dualspeed(gadget)) {
363*4882a593Smuzhiyun /* Assume endpoint addresses are the same for both speeds */
364*4882a593Smuzhiyun hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
365*4882a593Smuzhiyun hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
366*4882a593Smuzhiyun /* copy HS descriptors */
367*4882a593Smuzhiyun f->hs_descriptors = fb_hs_function;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (gadget_is_superspeed(gadget)) {
371*4882a593Smuzhiyun /* Assume endpoint addresses are the same as full speed */
372*4882a593Smuzhiyun ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
373*4882a593Smuzhiyun ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
374*4882a593Smuzhiyun /* copy SS descriptors */
375*4882a593Smuzhiyun f->ss_descriptors = fb_ss_function;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun s = env_get("serial#");
379*4882a593Smuzhiyun if (s)
380*4882a593Smuzhiyun g_dnl_set_serialnumber((char *)s);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
fastboot_unbind(struct usb_configuration * c,struct usb_function * f)385*4882a593Smuzhiyun static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun memset(fastboot_func, 0, sizeof(*fastboot_func));
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
fastboot_disable(struct usb_function * f)390*4882a593Smuzhiyun static void fastboot_disable(struct usb_function *f)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct f_fastboot *f_fb = func_to_fastboot(f);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun usb_ep_disable(f_fb->out_ep);
395*4882a593Smuzhiyun usb_ep_disable(f_fb->in_ep);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (f_fb->out_req) {
398*4882a593Smuzhiyun free(f_fb->out_req->buf);
399*4882a593Smuzhiyun usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
400*4882a593Smuzhiyun f_fb->out_req = NULL;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun if (f_fb->in_req) {
403*4882a593Smuzhiyun free(f_fb->in_req->buf);
404*4882a593Smuzhiyun usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
405*4882a593Smuzhiyun f_fb->in_req = NULL;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
fastboot_start_ep(struct usb_ep * ep)409*4882a593Smuzhiyun static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun struct usb_request *req;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun req = usb_ep_alloc_request(ep, 0);
414*4882a593Smuzhiyun if (!req)
415*4882a593Smuzhiyun return NULL;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun req->length = EP_BUFFER_SIZE;
418*4882a593Smuzhiyun req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
419*4882a593Smuzhiyun if (!req->buf) {
420*4882a593Smuzhiyun usb_ep_free_request(ep, req);
421*4882a593Smuzhiyun return NULL;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun memset(req->buf, 0, req->length);
425*4882a593Smuzhiyun return req;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
fastboot_set_alt(struct usb_function * f,unsigned interface,unsigned alt)428*4882a593Smuzhiyun static int fastboot_set_alt(struct usb_function *f,
429*4882a593Smuzhiyun unsigned interface, unsigned alt)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun int ret;
432*4882a593Smuzhiyun struct usb_composite_dev *cdev = f->config->cdev;
433*4882a593Smuzhiyun struct usb_gadget *gadget = cdev->gadget;
434*4882a593Smuzhiyun struct f_fastboot *f_fb = func_to_fastboot(f);
435*4882a593Smuzhiyun const struct usb_endpoint_descriptor *d;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun debug("%s: func: %s intf: %d alt: %d\n",
438*4882a593Smuzhiyun __func__, f->name, interface, alt);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out,
441*4882a593Smuzhiyun &ss_ep_out_comp_desc, f_fb->out_ep);
442*4882a593Smuzhiyun ret = usb_ep_enable(f_fb->out_ep, d);
443*4882a593Smuzhiyun if (ret) {
444*4882a593Smuzhiyun puts("failed to enable out ep\n");
445*4882a593Smuzhiyun return ret;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
449*4882a593Smuzhiyun if (!f_fb->out_req) {
450*4882a593Smuzhiyun puts("failed to alloc out req\n");
451*4882a593Smuzhiyun ret = -EINVAL;
452*4882a593Smuzhiyun goto err;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun f_fb->out_req->complete = rx_handler_command;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in,
457*4882a593Smuzhiyun &ss_ep_in_comp_desc, f_fb->in_ep);
458*4882a593Smuzhiyun ret = usb_ep_enable(f_fb->in_ep, d);
459*4882a593Smuzhiyun if (ret) {
460*4882a593Smuzhiyun puts("failed to enable in ep\n");
461*4882a593Smuzhiyun goto err;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
465*4882a593Smuzhiyun if (!f_fb->in_req) {
466*4882a593Smuzhiyun puts("failed alloc req in\n");
467*4882a593Smuzhiyun ret = -EINVAL;
468*4882a593Smuzhiyun goto err;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun f_fb->in_req->complete = fastboot_complete;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
473*4882a593Smuzhiyun if (ret)
474*4882a593Smuzhiyun goto err;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun err:
478*4882a593Smuzhiyun fastboot_disable(f);
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
fastboot_add(struct usb_configuration * c)482*4882a593Smuzhiyun static int fastboot_add(struct usb_configuration *c)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun struct f_fastboot *f_fb = fastboot_func;
485*4882a593Smuzhiyun int status;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun debug("%s: cdev: 0x%p\n", __func__, c->cdev);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (!f_fb) {
490*4882a593Smuzhiyun f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
491*4882a593Smuzhiyun if (!f_fb)
492*4882a593Smuzhiyun return -ENOMEM;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun fastboot_func = f_fb;
495*4882a593Smuzhiyun memset(f_fb, 0, sizeof(*f_fb));
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun f_fb->usb_function.name = "f_fastboot";
499*4882a593Smuzhiyun f_fb->usb_function.bind = fastboot_bind;
500*4882a593Smuzhiyun f_fb->usb_function.unbind = fastboot_unbind;
501*4882a593Smuzhiyun f_fb->usb_function.set_alt = fastboot_set_alt;
502*4882a593Smuzhiyun f_fb->usb_function.disable = fastboot_disable;
503*4882a593Smuzhiyun f_fb->usb_function.strings = fastboot_strings;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun status = usb_add_function(c, &f_fb->usb_function);
506*4882a593Smuzhiyun if (status) {
507*4882a593Smuzhiyun free(f_fb);
508*4882a593Smuzhiyun fastboot_func = f_fb;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun return status;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
514*4882a593Smuzhiyun
fastboot_tx_write(const char * buffer,unsigned int buffer_size)515*4882a593Smuzhiyun static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun struct usb_request *in_req = fastboot_func->in_req;
518*4882a593Smuzhiyun int ret;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun memcpy(in_req->buf, buffer, buffer_size);
521*4882a593Smuzhiyun in_req->length = buffer_size;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun usb_ep_dequeue(fastboot_func->in_ep, in_req);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
526*4882a593Smuzhiyun if (ret)
527*4882a593Smuzhiyun printf("Error %d on queue\n", ret);
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
fastboot_tx_write_str(const char * buffer)531*4882a593Smuzhiyun static int fastboot_tx_write_str(const char *buffer)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun int ret;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun ret = sleep_thread();
536*4882a593Smuzhiyun if (ret < 0)
537*4882a593Smuzhiyun printf("warning: 0x%x, usb transmission is abnormal!\n", ret);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun return fastboot_tx_write(buffer, strlen(buffer));
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
compl_do_reset(struct usb_ep * ep,struct usb_request * req)542*4882a593Smuzhiyun static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun do_reset(NULL, 0, 0, NULL);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
fb_set_reboot_flag(void)547*4882a593Smuzhiyun int __weak fb_set_reboot_flag(void)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun return -ENOSYS;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
cb_reboot(struct usb_ep * ep,struct usb_request * req)552*4882a593Smuzhiyun static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun char *cmd = req->buf;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (!strcmp_l1("reboot-bootloader", cmd)) {
557*4882a593Smuzhiyun if (fb_set_reboot_flag()) {
558*4882a593Smuzhiyun fastboot_tx_write_str("FAILCannot set reboot flag");
559*4882a593Smuzhiyun return;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_BOOTLOADER
563*4882a593Smuzhiyun if (!strcmp_l1("reboot-fastboot", cmd)) {
564*4882a593Smuzhiyun if (android_bcb_write("boot-fastboot")) {
565*4882a593Smuzhiyun fastboot_tx_write_str("FAILCannot set boot-fastboot");
566*4882a593Smuzhiyun return;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (!strcmp_l1("reboot-recovery", cmd)) {
571*4882a593Smuzhiyun if (android_bcb_write("boot-recovery")) {
572*4882a593Smuzhiyun fastboot_tx_write_str("FAILCannot set boot-recovery");
573*4882a593Smuzhiyun return;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun #endif
577*4882a593Smuzhiyun fastboot_func->in_req->complete = compl_do_reset;
578*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
strcmp_l1(const char * s1,const char * s2)581*4882a593Smuzhiyun static int strcmp_l1(const char *s1, const char *s2)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun if (!s1 || !s2)
584*4882a593Smuzhiyun return -1;
585*4882a593Smuzhiyun return strncmp(s1, s2, strlen(s1));
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun struct name_string {
589*4882a593Smuzhiyun const char *str;
590*4882a593Smuzhiyun int expects_args;
591*4882a593Smuzhiyun char delim;
592*4882a593Smuzhiyun };
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun #define NAME_NO_ARGS(s) {.str = s, .expects_args = 0}
595*4882a593Smuzhiyun #define NAME_ARGS(s, d) {.str = s, .expects_args = 1, .delim = d}
596*4882a593Smuzhiyun
name_check_match(const char * str,size_t len,const struct name_string * name)597*4882a593Smuzhiyun static size_t name_check_match(const char *str, size_t len,
598*4882a593Smuzhiyun const struct name_string *name)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun size_t str_len = strlen(name->str);
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /* If name len is greater than input, return 0. */
603*4882a593Smuzhiyun if (str_len > len)
604*4882a593Smuzhiyun return 0;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* If name str does not match input string, return 0. */
607*4882a593Smuzhiyun if (memcmp(name->str, str, str_len))
608*4882a593Smuzhiyun return 0;
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun if (name->expects_args) {
611*4882a593Smuzhiyun /* string should have space for delim */
612*4882a593Smuzhiyun if (len == str_len)
613*4882a593Smuzhiyun return 0;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /* Check delim match */
616*4882a593Smuzhiyun if (name->delim != str[str_len])
617*4882a593Smuzhiyun return 0;
618*4882a593Smuzhiyun } else {
619*4882a593Smuzhiyun /* Name str len should match input len */
620*4882a593Smuzhiyun if (str_len != len)
621*4882a593Smuzhiyun return 0;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun return str_len + name->expects_args;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
fb_add_string(char * dst,size_t chars_left,const char * str,const char * args)627*4882a593Smuzhiyun static void fb_add_string(char *dst, size_t chars_left,
628*4882a593Smuzhiyun const char *str, const char *args)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun if (!str)
631*4882a593Smuzhiyun return;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun int ret = snprintf(dst, chars_left, str, args);
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun if (ret < 0)
636*4882a593Smuzhiyun pr_err("snprintf is error!");
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun
fb_add_number(char * dst,size_t chars_left,const char * format,size_t num)639*4882a593Smuzhiyun static void fb_add_number(char *dst, size_t chars_left,
640*4882a593Smuzhiyun const char *format, size_t num)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun if (!format)
643*4882a593Smuzhiyun return;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun int ret = snprintf(dst, chars_left, format, num);
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (ret > chars_left)
648*4882a593Smuzhiyun pr_err("snprintf is error!");
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
fb_read_var(char * cmd,char * response,fb_getvar_t var,size_t chars_left)651*4882a593Smuzhiyun static int fb_read_var(char *cmd, char *response,
652*4882a593Smuzhiyun fb_getvar_t var, size_t chars_left)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun const char *s;
655*4882a593Smuzhiyun int ret = 0;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun switch (var) {
658*4882a593Smuzhiyun case FB_VERSION:
659*4882a593Smuzhiyun fb_add_string(response, chars_left, FASTBOOT_VERSION, NULL);
660*4882a593Smuzhiyun break;
661*4882a593Smuzhiyun case FB_BOOTLOADER_VERSION:
662*4882a593Smuzhiyun fb_add_string(response, chars_left, U_BOOT_VERSION, NULL);
663*4882a593Smuzhiyun break;
664*4882a593Smuzhiyun case FB_BASEBAND_VERSION:
665*4882a593Smuzhiyun fb_add_string(response, chars_left, "N/A", NULL);
666*4882a593Smuzhiyun break;
667*4882a593Smuzhiyun case FB_PRODUCT:
668*4882a593Smuzhiyun fb_add_string(response, chars_left, CONFIG_SYS_BOARD, NULL);
669*4882a593Smuzhiyun break;
670*4882a593Smuzhiyun case FB_SERIAL_NO:
671*4882a593Smuzhiyun s = env_get("serial#");
672*4882a593Smuzhiyun if (s)
673*4882a593Smuzhiyun fb_add_string(response, chars_left, s, NULL);
674*4882a593Smuzhiyun else
675*4882a593Smuzhiyun ret = -1;
676*4882a593Smuzhiyun break;
677*4882a593Smuzhiyun case FB_SECURE:
678*4882a593Smuzhiyun fb_add_string(response, chars_left, "yes", NULL);
679*4882a593Smuzhiyun break;
680*4882a593Smuzhiyun case FB_VARIANT:
681*4882a593Smuzhiyun fb_add_string(response, chars_left, "userdebug", NULL);
682*4882a593Smuzhiyun break;
683*4882a593Smuzhiyun case FB_DWNLD_SIZE:
684*4882a593Smuzhiyun fb_add_number(response, chars_left, "0x%08x",
685*4882a593Smuzhiyun CONFIG_FASTBOOT_BUF_SIZE);
686*4882a593Smuzhiyun break;
687*4882a593Smuzhiyun case FB_PART_SIZE:
688*4882a593Smuzhiyun case FB_PART_TYPE: {
689*4882a593Smuzhiyun char *part_name = cmd;
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun cmd = strsep(&part_name, ":");
692*4882a593Smuzhiyun if (!cmd || !part_name) {
693*4882a593Smuzhiyun fb_add_string(response, chars_left,
694*4882a593Smuzhiyun "argument Invalid!", NULL);
695*4882a593Smuzhiyun ret = -1;
696*4882a593Smuzhiyun break;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
700*4882a593Smuzhiyun disk_partition_t part_info;
701*4882a593Smuzhiyun struct blk_desc *dev_desc;
702*4882a593Smuzhiyun int part_num = -1;
703*4882a593Smuzhiyun const char *fs_type = NULL;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
706*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
707*4882a593Smuzhiyun #else
708*4882a593Smuzhiyun dev_desc = NULL;
709*4882a593Smuzhiyun #endif
710*4882a593Smuzhiyun if (!dev_desc) {
711*4882a593Smuzhiyun fb_add_string(response, chars_left,
712*4882a593Smuzhiyun "block device not found", NULL);
713*4882a593Smuzhiyun ret = -1;
714*4882a593Smuzhiyun break;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun part_num = part_get_info_by_name(dev_desc, part_name,
718*4882a593Smuzhiyun &part_info);
719*4882a593Smuzhiyun if (part_num < 0) {
720*4882a593Smuzhiyun fb_add_string(response, chars_left,
721*4882a593Smuzhiyun "partition not found", NULL);
722*4882a593Smuzhiyun ret = -1;
723*4882a593Smuzhiyun } else if (!strncmp(PARTITION_TYPE_STRINGS, cmd,
724*4882a593Smuzhiyun strlen(PARTITION_TYPE_STRINGS))) {
725*4882a593Smuzhiyun if (fb_get_fstype("mmc", part_num, &fs_type)) {
726*4882a593Smuzhiyun fb_add_string(response, chars_left,
727*4882a593Smuzhiyun (char *)part_info.type, NULL);
728*4882a593Smuzhiyun } else {
729*4882a593Smuzhiyun fb_add_string(response, chars_left,
730*4882a593Smuzhiyun fs_type, NULL);
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun } else if (!strncmp("partition-size", cmd, 14)) {
733*4882a593Smuzhiyun u64 part_size;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun part_size = (uint64_t)part_info.size;
736*4882a593Smuzhiyun snprintf(response, chars_left, "0x%llx",
737*4882a593Smuzhiyun part_size * dev_desc->blksz);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun #else
740*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
741*4882a593Smuzhiyun ret = -1;
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun break;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun case FB_BLK_SIZE: {
746*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
747*4882a593Smuzhiyun struct blk_desc *dev_desc;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
750*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
751*4882a593Smuzhiyun #else
752*4882a593Smuzhiyun dev_desc = NULL;
753*4882a593Smuzhiyun #endif
754*4882a593Smuzhiyun if (!dev_desc) {
755*4882a593Smuzhiyun fb_add_string(response, chars_left,
756*4882a593Smuzhiyun "block device not found", NULL);
757*4882a593Smuzhiyun ret = -1;
758*4882a593Smuzhiyun } else {
759*4882a593Smuzhiyun fb_add_number(response, chars_left,
760*4882a593Smuzhiyun "0x%lx", dev_desc->blksz);
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun #else
763*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
764*4882a593Smuzhiyun ret = -1;
765*4882a593Smuzhiyun #endif
766*4882a593Smuzhiyun break;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun case FB_ERASE_SIZE: {
769*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
770*4882a593Smuzhiyun lbaint_t erase_grp_size;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun erase_grp_size = fb_mmc_get_erase_grp_size();
773*4882a593Smuzhiyun if (erase_grp_size < 0) {
774*4882a593Smuzhiyun fb_add_string(response, chars_left,
775*4882a593Smuzhiyun "block device not found", NULL);
776*4882a593Smuzhiyun ret = -1;
777*4882a593Smuzhiyun } else {
778*4882a593Smuzhiyun fb_add_number(response, chars_left, "0x"LBAF"",
779*4882a593Smuzhiyun erase_grp_size);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun #else
782*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
783*4882a593Smuzhiyun ret = -1;
784*4882a593Smuzhiyun #endif
785*4882a593Smuzhiyun break;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun case FB_UNLOCKED: {
788*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
789*4882a593Smuzhiyun uint8_t flash_lock_state = 0;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun if (rk_avb_read_flash_lock_state(&flash_lock_state))
792*4882a593Smuzhiyun fb_add_string(response, chars_left, "yes", NULL);
793*4882a593Smuzhiyun else
794*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
795*4882a593Smuzhiyun #else
796*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
797*4882a593Smuzhiyun ret = -1;
798*4882a593Smuzhiyun #endif
799*4882a593Smuzhiyun break;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun case FB_OFF_MODE_CHARGE: {
802*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
803*4882a593Smuzhiyun break;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun case FB_BATT_VOLTAGE: {
806*4882a593Smuzhiyun fb_add_string(response, chars_left, "not implemented", NULL);
807*4882a593Smuzhiyun break;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun case FB_BATT_SOC_OK: {
810*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
811*4882a593Smuzhiyun break;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun case FB_IS_USERSPACE: {
814*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
815*4882a593Smuzhiyun break;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
818*4882a593Smuzhiyun case FB_HAS_COUNT: {
819*4882a593Smuzhiyun char slot_count[2];
820*4882a593Smuzhiyun char temp;
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun slot_count[1] = '\0';
823*4882a593Smuzhiyun if (rk_avb_read_slot_count(&temp) < 0) {
824*4882a593Smuzhiyun fb_add_number(response, chars_left, "%d", 0);
825*4882a593Smuzhiyun ret = -1;
826*4882a593Smuzhiyun break;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun slot_count[0] = temp + 0x30;
829*4882a593Smuzhiyun fb_add_string(response, chars_left, slot_count, NULL);
830*4882a593Smuzhiyun break;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun case FB_HAS_SLOT: {
833*4882a593Smuzhiyun char *part_name = cmd;
834*4882a593Smuzhiyun int has_slot = -1;
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun cmd = strsep(&part_name, ":");
837*4882a593Smuzhiyun if (!cmd || !part_name) {
838*4882a593Smuzhiyun fb_add_string(response, chars_left,
839*4882a593Smuzhiyun "argument Invalid!", NULL);
840*4882a593Smuzhiyun ret = -1;
841*4882a593Smuzhiyun break;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun has_slot = rk_avb_get_part_has_slot_info(part_name);
845*4882a593Smuzhiyun if (has_slot < 0)
846*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
847*4882a593Smuzhiyun else
848*4882a593Smuzhiyun fb_add_string(response, chars_left, "yes", NULL);
849*4882a593Smuzhiyun break;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun case FB_CURR_SLOT: {
852*4882a593Smuzhiyun char slot_surrent[8] = {0};
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun if (!rk_avb_get_current_slot(slot_surrent)) {
855*4882a593Smuzhiyun fb_add_string(response, chars_left,
856*4882a593Smuzhiyun slot_surrent + 1, NULL);
857*4882a593Smuzhiyun } else {
858*4882a593Smuzhiyun fb_add_string(response, chars_left, "get error", NULL);
859*4882a593Smuzhiyun ret = -1;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun break;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun case FB_SLOT_SUFFIXES: {
864*4882a593Smuzhiyun char slot_suffixes_temp[4] = {0};
865*4882a593Smuzhiyun char slot_suffixes[9] = {0};
866*4882a593Smuzhiyun int slot_cnt = 0;
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun rk_avb_read_slot_suffixes(slot_suffixes_temp);
869*4882a593Smuzhiyun while (slot_suffixes_temp[slot_cnt] != '\0') {
870*4882a593Smuzhiyun slot_suffixes[slot_cnt * 2]
871*4882a593Smuzhiyun = slot_suffixes_temp[slot_cnt];
872*4882a593Smuzhiyun slot_suffixes[slot_cnt * 2 + 1] = ',';
873*4882a593Smuzhiyun slot_cnt++;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun slot_suffixes[(slot_cnt - 1) * 2 + 1] = '\0';
877*4882a593Smuzhiyun fb_add_string(response, chars_left, slot_suffixes, NULL);
878*4882a593Smuzhiyun break;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun case FB_SLOT_SUCCESSFUL:{
881*4882a593Smuzhiyun char *slot_name = cmd;
882*4882a593Smuzhiyun AvbABData ab_info;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun cmd = strsep(&slot_name, ":");
885*4882a593Smuzhiyun if (!cmd || !slot_name) {
886*4882a593Smuzhiyun fb_add_string(response, chars_left,
887*4882a593Smuzhiyun "argument Invalid!", NULL);
888*4882a593Smuzhiyun ret = -1;
889*4882a593Smuzhiyun break;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
893*4882a593Smuzhiyun fb_add_string(response, chars_left,
894*4882a593Smuzhiyun "get ab info failed!", NULL);
895*4882a593Smuzhiyun ret = -1;
896*4882a593Smuzhiyun break;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun if (!strcmp(slot_name, "a")) {
900*4882a593Smuzhiyun if (ab_info.slots[0].successful_boot)
901*4882a593Smuzhiyun fb_add_string(response, chars_left,
902*4882a593Smuzhiyun "yes", NULL);
903*4882a593Smuzhiyun else
904*4882a593Smuzhiyun fb_add_string(response, chars_left,
905*4882a593Smuzhiyun "no", NULL);
906*4882a593Smuzhiyun } else if (!strcmp(slot_name, "b")) {
907*4882a593Smuzhiyun if (ab_info.slots[1].successful_boot)
908*4882a593Smuzhiyun fb_add_string(response, chars_left,
909*4882a593Smuzhiyun "yes", NULL);
910*4882a593Smuzhiyun else
911*4882a593Smuzhiyun fb_add_string(response, chars_left,
912*4882a593Smuzhiyun "no", NULL);
913*4882a593Smuzhiyun } else {
914*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun break;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun case FB_SLOT_UNBOOTABLE: {
919*4882a593Smuzhiyun char *slot_name = cmd;
920*4882a593Smuzhiyun AvbABData ab_info;
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun cmd = strsep(&slot_name, ":");
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun if (!cmd || !slot_name) {
925*4882a593Smuzhiyun fb_add_string(response, chars_left,
926*4882a593Smuzhiyun "argument Invalid!", NULL);
927*4882a593Smuzhiyun ret = -1;
928*4882a593Smuzhiyun break;
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
932*4882a593Smuzhiyun fb_add_string(response, chars_left,
933*4882a593Smuzhiyun "get ab info failed!", NULL);
934*4882a593Smuzhiyun ret = -1;
935*4882a593Smuzhiyun break;
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if (!strcmp(slot_name, "a")) {
939*4882a593Smuzhiyun if (!ab_info.slots[0].successful_boot &&
940*4882a593Smuzhiyun !ab_info.slots[0].tries_remaining &&
941*4882a593Smuzhiyun !ab_info.slots[0].priority)
942*4882a593Smuzhiyun fb_add_string(response, chars_left,
943*4882a593Smuzhiyun "yes", NULL);
944*4882a593Smuzhiyun else
945*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
946*4882a593Smuzhiyun } else if (!strcmp(slot_name, "b")) {
947*4882a593Smuzhiyun if (!ab_info.slots[1].successful_boot &&
948*4882a593Smuzhiyun !ab_info.slots[1].tries_remaining &&
949*4882a593Smuzhiyun !ab_info.slots[1].priority)
950*4882a593Smuzhiyun fb_add_string(response, chars_left,
951*4882a593Smuzhiyun "yes", NULL);
952*4882a593Smuzhiyun else
953*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
954*4882a593Smuzhiyun } else {
955*4882a593Smuzhiyun fb_add_string(response, chars_left, "no", NULL);
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun break;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun case FB_SLOT_RETRY_COUNT: {
960*4882a593Smuzhiyun char *slot_name = cmd;
961*4882a593Smuzhiyun AvbABData ab_info;
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun cmd = strsep(&slot_name, ":");
964*4882a593Smuzhiyun if (!cmd || !slot_name) {
965*4882a593Smuzhiyun fb_add_string(response, chars_left,
966*4882a593Smuzhiyun "argument Invalid!", NULL);
967*4882a593Smuzhiyun ret = -1;
968*4882a593Smuzhiyun break;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
972*4882a593Smuzhiyun fb_add_string(response, chars_left,
973*4882a593Smuzhiyun "get ab info failed!", NULL);
974*4882a593Smuzhiyun ret = -1;
975*4882a593Smuzhiyun break;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun if (!strcmp(slot_name, "a")) {
979*4882a593Smuzhiyun fb_add_number(response, chars_left,
980*4882a593Smuzhiyun "%d", ab_info.slots[0].tries_remaining);
981*4882a593Smuzhiyun } else if (!strcmp(slot_name, "b")) {
982*4882a593Smuzhiyun fb_add_number(response, chars_left, "%d",
983*4882a593Smuzhiyun ab_info.slots[1].tries_remaining);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun } else {
986*4882a593Smuzhiyun strcpy(response, "FAILno");
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun break;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun case FB_AT_VBST: {
991*4882a593Smuzhiyun char vbst[VBOOT_STATE_SIZE] = {0};
992*4882a593Smuzhiyun char *p_vbst;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun strcpy(response, "INFO");
995*4882a593Smuzhiyun rk_avb_get_at_vboot_state(vbst);
996*4882a593Smuzhiyun p_vbst = vbst;
997*4882a593Smuzhiyun do {
998*4882a593Smuzhiyun cmd = strsep(&p_vbst, "\n");
999*4882a593Smuzhiyun if (strlen(cmd) > 0) {
1000*4882a593Smuzhiyun memcpy(&response[4], cmd, chars_left);
1001*4882a593Smuzhiyun fastboot_tx_write_str(response);
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun } while (strlen(cmd));
1004*4882a593Smuzhiyun break;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun case FB_SNAPSHOT_STATUS: {
1007*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1008*4882a593Smuzhiyun struct misc_virtual_ab_message state;
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun memset(&state, 0x0, sizeof(state));
1011*4882a593Smuzhiyun if (read_misc_virtual_ab_message(&state) != 0) {
1012*4882a593Smuzhiyun printf("FB_SNAPSHOT_STATUS read_misc_virtual_ab_message failed!\n");
1013*4882a593Smuzhiyun fb_add_string(response, chars_left, "get error", NULL);
1014*4882a593Smuzhiyun ret = -1;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1018*4882a593Smuzhiyun printf("FB_SNAPSHOT_STATUS not virtual A/B metadata!\n");
1019*4882a593Smuzhiyun fb_add_string(response, chars_left, "get error", NULL);
1020*4882a593Smuzhiyun ret = -1;
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun if (state.merge_status == ENUM_MERGE_STATUS_MERGING) {
1024*4882a593Smuzhiyun fb_add_string(response, chars_left, "merging", NULL);
1025*4882a593Smuzhiyun } else if (state.merge_status == ENUM_MERGE_STATUS_SNAPSHOTTED) {
1026*4882a593Smuzhiyun fb_add_string(response, chars_left, "snapshotted", NULL);
1027*4882a593Smuzhiyun } else {
1028*4882a593Smuzhiyun fb_add_string(response, chars_left, "none", NULL);
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun #else
1031*4882a593Smuzhiyun fb_add_string(response, chars_left, "get error", NULL);
1032*4882a593Smuzhiyun ret = -1;
1033*4882a593Smuzhiyun #endif
1034*4882a593Smuzhiyun break;
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun #endif
1038*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
1039*4882a593Smuzhiyun case FB_AT_DH: {
1040*4882a593Smuzhiyun char dhbuf[ATTEST_DH_SIZE];
1041*4882a593Smuzhiyun uint32_t dh_len = ATTEST_DH_SIZE;
1042*4882a593Smuzhiyun uint32_t res = trusty_attest_dh((uint8_t *)dhbuf, &dh_len);
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun if (res) {
1045*4882a593Smuzhiyun fb_add_string(response, chars_left, "dh not set", NULL);
1046*4882a593Smuzhiyun ret = -1;
1047*4882a593Smuzhiyun } else {
1048*4882a593Smuzhiyun fb_add_string(response, chars_left, dhbuf, NULL);
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun break;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun case FB_AT_UUID: {
1053*4882a593Smuzhiyun char uuid[ATTEST_UUID_SIZE] = {0};
1054*4882a593Smuzhiyun uint32_t uuid_len = ATTEST_UUID_SIZE;
1055*4882a593Smuzhiyun uint32_t res = trusty_attest_uuid((uint8_t *)uuid, &uuid_len);
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun uuid[ATTEST_UUID_SIZE - 1] = 0;
1058*4882a593Smuzhiyun if (res) {
1059*4882a593Smuzhiyun fb_add_string(response, chars_left, "dh not set", NULL);
1060*4882a593Smuzhiyun ret = -1;
1061*4882a593Smuzhiyun } else {
1062*4882a593Smuzhiyun fb_add_string(response, chars_left, uuid, NULL);
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun break;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun #endif
1067*4882a593Smuzhiyun default: {
1068*4882a593Smuzhiyun char *envstr;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1);
1071*4882a593Smuzhiyun if (!envstr) {
1072*4882a593Smuzhiyun fb_add_string(response, chars_left,
1073*4882a593Smuzhiyun "malloc error", NULL);
1074*4882a593Smuzhiyun ret = -1;
1075*4882a593Smuzhiyun break;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun sprintf(envstr, "fastboot.%s", cmd);
1079*4882a593Smuzhiyun s = env_get(envstr);
1080*4882a593Smuzhiyun if (s) {
1081*4882a593Smuzhiyun strncat(response, s, chars_left);
1082*4882a593Smuzhiyun } else {
1083*4882a593Smuzhiyun printf("WARNING: unknown variable: %s\n", cmd);
1084*4882a593Smuzhiyun fb_add_string(response, chars_left,
1085*4882a593Smuzhiyun "not implemented", NULL);
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun free(envstr);
1089*4882a593Smuzhiyun break;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun return ret;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun static const struct {
1097*4882a593Smuzhiyun /*
1098*4882a593Smuzhiyun *any changes to this array require an update to the corresponding
1099*4882a593Smuzhiyun *enum in fastboot.h
1100*4882a593Smuzhiyun */
1101*4882a593Smuzhiyun struct name_string name;
1102*4882a593Smuzhiyun fb_getvar_t var;
1103*4882a593Smuzhiyun } getvar_table[] = {
1104*4882a593Smuzhiyun { NAME_NO_ARGS("version"), FB_VERSION},
1105*4882a593Smuzhiyun { NAME_NO_ARGS("version-bootloader"), FB_BOOTLOADER_VERSION},
1106*4882a593Smuzhiyun { NAME_NO_ARGS("version-baseband"), FB_BASEBAND_VERSION},
1107*4882a593Smuzhiyun { NAME_NO_ARGS("product"), FB_PRODUCT},
1108*4882a593Smuzhiyun { NAME_NO_ARGS("serialno"), FB_SERIAL_NO},
1109*4882a593Smuzhiyun { NAME_NO_ARGS("secure"), FB_SECURE},
1110*4882a593Smuzhiyun { NAME_NO_ARGS("max-download-size"), FB_DWNLD_SIZE},
1111*4882a593Smuzhiyun { NAME_NO_ARGS("logical-block-size"), FB_BLK_SIZE},
1112*4882a593Smuzhiyun { NAME_NO_ARGS("erase-block-size"), FB_ERASE_SIZE},
1113*4882a593Smuzhiyun { NAME_ARGS("partition-type", ':'), FB_PART_TYPE},
1114*4882a593Smuzhiyun { NAME_ARGS("partition-size", ':'), FB_PART_SIZE},
1115*4882a593Smuzhiyun { NAME_NO_ARGS("unlocked"), FB_UNLOCKED},
1116*4882a593Smuzhiyun { NAME_NO_ARGS("off-mode-charge"), FB_OFF_MODE_CHARGE},
1117*4882a593Smuzhiyun { NAME_NO_ARGS("battery-voltage"), FB_BATT_VOLTAGE},
1118*4882a593Smuzhiyun { NAME_NO_ARGS("variant"), FB_VARIANT},
1119*4882a593Smuzhiyun { NAME_NO_ARGS("battery-soc-ok"), FB_BATT_SOC_OK},
1120*4882a593Smuzhiyun { NAME_NO_ARGS("is-userspace"), FB_IS_USERSPACE},
1121*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1122*4882a593Smuzhiyun /* Slots related */
1123*4882a593Smuzhiyun { NAME_NO_ARGS("slot-count"), FB_HAS_COUNT},
1124*4882a593Smuzhiyun { NAME_ARGS("has-slot", ':'), FB_HAS_SLOT},
1125*4882a593Smuzhiyun { NAME_NO_ARGS("current-slot"), FB_CURR_SLOT},
1126*4882a593Smuzhiyun { NAME_NO_ARGS("slot-suffixes"), FB_SLOT_SUFFIXES},
1127*4882a593Smuzhiyun { NAME_ARGS("slot-successful", ':'), FB_SLOT_SUCCESSFUL},
1128*4882a593Smuzhiyun { NAME_ARGS("slot-unbootable", ':'), FB_SLOT_UNBOOTABLE},
1129*4882a593Smuzhiyun { NAME_ARGS("slot-retry-count", ':'), FB_SLOT_RETRY_COUNT},
1130*4882a593Smuzhiyun { NAME_NO_ARGS("at-vboot-state"), FB_AT_VBST},
1131*4882a593Smuzhiyun { NAME_NO_ARGS("snapshot-update-status"), FB_SNAPSHOT_STATUS},
1132*4882a593Smuzhiyun #endif
1133*4882a593Smuzhiyun /*
1134*4882a593Smuzhiyun * OEM specific :
1135*4882a593Smuzhiyun * Spec says names starting with lowercase letter are reserved.
1136*4882a593Smuzhiyun */
1137*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
1138*4882a593Smuzhiyun { NAME_NO_ARGS("at-attest-dh"), FB_AT_DH},
1139*4882a593Smuzhiyun { NAME_NO_ARGS("at-attest-uuid"), FB_AT_UUID},
1140*4882a593Smuzhiyun #endif
1141*4882a593Smuzhiyun };
1142*4882a593Smuzhiyun
fb_getvar_single(char * cmd,char * response,size_t chars_left)1143*4882a593Smuzhiyun static int fb_getvar_single(char *cmd, char *response, size_t chars_left)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun int i;
1146*4882a593Smuzhiyun size_t match_len = 0;
1147*4882a593Smuzhiyun size_t len = strlen(cmd);
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
1150*4882a593Smuzhiyun match_len = name_check_match(cmd, len, &getvar_table[i].name);
1151*4882a593Smuzhiyun if (match_len)
1152*4882a593Smuzhiyun break;
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun if (match_len == 0) {
1156*4882a593Smuzhiyun fb_add_string(response, chars_left, "unknown variable", NULL);
1157*4882a593Smuzhiyun return -1;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun if (fb_read_var(cmd, response, getvar_table[i].var, chars_left) < 0)
1161*4882a593Smuzhiyun return -1;
1162*4882a593Smuzhiyun
1163*4882a593Smuzhiyun return 0;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun
fb_getvar_all(void)1166*4882a593Smuzhiyun static void fb_getvar_all(void)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN] = {0};
1169*4882a593Smuzhiyun char resp_tmp[FASTBOOT_RESPONSE_LEN] = {0};
1170*4882a593Smuzhiyun char *actual_resp;
1171*4882a593Smuzhiyun size_t chars_left;
1172*4882a593Smuzhiyun int i, p;
1173*4882a593Smuzhiyun disk_partition_t part_info;
1174*4882a593Smuzhiyun struct blk_desc *dev_desc;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun strcpy(response, "INFO");
1177*4882a593Smuzhiyun chars_left = sizeof(response) - strlen(response) - 1;
1178*4882a593Smuzhiyun actual_resp = response + strlen(response);
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
1181*4882a593Smuzhiyun fb_getvar_t var = getvar_table[i].var;
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun switch (var) {
1184*4882a593Smuzhiyun case FB_PART_TYPE:
1185*4882a593Smuzhiyun case FB_PART_SIZE: {
1186*4882a593Smuzhiyun const char *fs_type = NULL;
1187*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
1188*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
1189*4882a593Smuzhiyun #else
1190*4882a593Smuzhiyun dev_desc = NULL;
1191*4882a593Smuzhiyun #endif
1192*4882a593Smuzhiyun if (!dev_desc) {
1193*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1194*4882a593Smuzhiyun "%s:block device not found",
1195*4882a593Smuzhiyun getvar_table[i].name.str);
1196*4882a593Smuzhiyun fastboot_tx_write_str(response);
1197*4882a593Smuzhiyun break;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
1201*4882a593Smuzhiyun if (part_get_info(dev_desc, p,
1202*4882a593Smuzhiyun &part_info) < 0) {
1203*4882a593Smuzhiyun break;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun if (var == FB_PART_TYPE) {
1207*4882a593Smuzhiyun fs_type = NULL;
1208*4882a593Smuzhiyun if (fb_get_fstype("mmc", p,
1209*4882a593Smuzhiyun &fs_type)) {
1210*4882a593Smuzhiyun fb_add_string(
1211*4882a593Smuzhiyun resp_tmp,
1212*4882a593Smuzhiyun FASTBOOT_RESPONSE_LEN,
1213*4882a593Smuzhiyun (char *)part_info.type,
1214*4882a593Smuzhiyun NULL);
1215*4882a593Smuzhiyun } else {
1216*4882a593Smuzhiyun fb_add_string(
1217*4882a593Smuzhiyun resp_tmp,
1218*4882a593Smuzhiyun FASTBOOT_RESPONSE_LEN,
1219*4882a593Smuzhiyun fs_type,
1220*4882a593Smuzhiyun NULL);
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun snprintf(actual_resp,
1224*4882a593Smuzhiyun chars_left,
1225*4882a593Smuzhiyun "%s:%s:%s",
1226*4882a593Smuzhiyun getvar_table[i].name.str,
1227*4882a593Smuzhiyun part_info.name,
1228*4882a593Smuzhiyun resp_tmp);
1229*4882a593Smuzhiyun } else {
1230*4882a593Smuzhiyun uint64_t part_size;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun part_size = (uint64_t)part_info.size;
1233*4882a593Smuzhiyun snprintf(actual_resp,
1234*4882a593Smuzhiyun chars_left,
1235*4882a593Smuzhiyun "%s:%s:0x%llx",
1236*4882a593Smuzhiyun getvar_table[i].name.str,
1237*4882a593Smuzhiyun part_info.name,
1238*4882a593Smuzhiyun part_size * dev_desc->blksz);
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun fastboot_tx_write_str(response);
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun break;
1243*4882a593Smuzhiyun }
1244*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1245*4882a593Smuzhiyun case FB_HAS_SLOT: {
1246*4882a593Smuzhiyun uchar *ptr_name_tmp;
1247*4882a593Smuzhiyun char c = '_';
1248*4882a593Smuzhiyun int has_slot = -1;
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun #ifdef CONFIG_RKIMG_BOOTLOADER
1251*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
1252*4882a593Smuzhiyun #else
1253*4882a593Smuzhiyun dev_desc = NULL;
1254*4882a593Smuzhiyun #endif
1255*4882a593Smuzhiyun if (!dev_desc) {
1256*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1257*4882a593Smuzhiyun "%s:block device not found",
1258*4882a593Smuzhiyun getvar_table[i].name.str);
1259*4882a593Smuzhiyun fastboot_tx_write_str(response);
1260*4882a593Smuzhiyun break;
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
1264*4882a593Smuzhiyun if (part_get_info(dev_desc, p,
1265*4882a593Smuzhiyun &part_info) < 0) {
1266*4882a593Smuzhiyun break;
1267*4882a593Smuzhiyun } else {
1268*4882a593Smuzhiyun ptr_name_tmp = (uchar *)strrchr(
1269*4882a593Smuzhiyun (char *)part_info.name, c);
1270*4882a593Smuzhiyun if (ptr_name_tmp &&
1271*4882a593Smuzhiyun part_info.name[ptr_name_tmp -
1272*4882a593Smuzhiyun part_info.name + 2] == '\0')
1273*4882a593Smuzhiyun fb_add_string(
1274*4882a593Smuzhiyun resp_tmp,
1275*4882a593Smuzhiyun ptr_name_tmp -
1276*4882a593Smuzhiyun part_info.name + 1,
1277*4882a593Smuzhiyun (char *)part_info.name,
1278*4882a593Smuzhiyun NULL);
1279*4882a593Smuzhiyun else
1280*4882a593Smuzhiyun strcpy(resp_tmp,
1281*4882a593Smuzhiyun (char *)part_info.name);
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun has_slot = rk_avb_get_part_has_slot_info(
1284*4882a593Smuzhiyun resp_tmp);
1285*4882a593Smuzhiyun if (has_slot < 0) {
1286*4882a593Smuzhiyun snprintf(actual_resp,
1287*4882a593Smuzhiyun chars_left,
1288*4882a593Smuzhiyun "%s:%s:no",
1289*4882a593Smuzhiyun getvar_table[i].name.str,
1290*4882a593Smuzhiyun resp_tmp);
1291*4882a593Smuzhiyun } else {
1292*4882a593Smuzhiyun snprintf(actual_resp,
1293*4882a593Smuzhiyun chars_left,
1294*4882a593Smuzhiyun "%s:%s:yes",
1295*4882a593Smuzhiyun getvar_table[i].name.str,
1296*4882a593Smuzhiyun resp_tmp);
1297*4882a593Smuzhiyun p++;
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun fastboot_tx_write_str(response);
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun break;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun case FB_SLOT_SUCCESSFUL: {
1307*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1308*4882a593Smuzhiyun AvbABData ab_info;
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
1311*4882a593Smuzhiyun fb_add_string(actual_resp,
1312*4882a593Smuzhiyun chars_left,
1313*4882a593Smuzhiyun "%s:get ab info failed!",
1314*4882a593Smuzhiyun getvar_table[i].name.str);
1315*4882a593Smuzhiyun fastboot_tx_write_str(response);
1316*4882a593Smuzhiyun break;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun if (ab_info.slots[0].successful_boot)
1320*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1321*4882a593Smuzhiyun "%s:a:yes",
1322*4882a593Smuzhiyun getvar_table[i].name.str);
1323*4882a593Smuzhiyun else
1324*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1325*4882a593Smuzhiyun "%s:a:no",
1326*4882a593Smuzhiyun getvar_table[i].name.str);
1327*4882a593Smuzhiyun fastboot_tx_write_str(response);
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun if (ab_info.slots[1].successful_boot)
1330*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1331*4882a593Smuzhiyun "%s:b:yes",
1332*4882a593Smuzhiyun getvar_table[i].name.str);
1333*4882a593Smuzhiyun else
1334*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1335*4882a593Smuzhiyun "%s:b:no",
1336*4882a593Smuzhiyun getvar_table[i].name.str);
1337*4882a593Smuzhiyun fastboot_tx_write_str(response);
1338*4882a593Smuzhiyun #else
1339*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1340*4882a593Smuzhiyun "%s:not find ab info!",
1341*4882a593Smuzhiyun getvar_table[i].name.str);
1342*4882a593Smuzhiyun fastboot_tx_write_str(response);
1343*4882a593Smuzhiyun #endif
1344*4882a593Smuzhiyun break;
1345*4882a593Smuzhiyun }
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun case FB_SLOT_UNBOOTABLE: {
1348*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1349*4882a593Smuzhiyun AvbABData ab_info;
1350*4882a593Smuzhiyun
1351*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
1352*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1353*4882a593Smuzhiyun "%s:not find ab info!",
1354*4882a593Smuzhiyun getvar_table[i].name.str);
1355*4882a593Smuzhiyun fastboot_tx_write_str(response);
1356*4882a593Smuzhiyun break;
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun if (!ab_info.slots[0].successful_boot &&
1360*4882a593Smuzhiyun !ab_info.slots[0].tries_remaining &&
1361*4882a593Smuzhiyun !ab_info.slots[0].priority)
1362*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1363*4882a593Smuzhiyun "%s:a:yes",
1364*4882a593Smuzhiyun getvar_table[i].name.str);
1365*4882a593Smuzhiyun else
1366*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1367*4882a593Smuzhiyun "%s:a:no",
1368*4882a593Smuzhiyun getvar_table[i].name.str);
1369*4882a593Smuzhiyun fastboot_tx_write_str(response);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun if (!ab_info.slots[1].successful_boot &&
1372*4882a593Smuzhiyun !ab_info.slots[1].tries_remaining &&
1373*4882a593Smuzhiyun !ab_info.slots[1].priority)
1374*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1375*4882a593Smuzhiyun "%s:b:yes",
1376*4882a593Smuzhiyun getvar_table[i].name.str);
1377*4882a593Smuzhiyun else
1378*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1379*4882a593Smuzhiyun "%s:b:no",
1380*4882a593Smuzhiyun getvar_table[i].name.str);
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun fastboot_tx_write_str(response);
1383*4882a593Smuzhiyun #else
1384*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1385*4882a593Smuzhiyun "%s:not find ab info!",
1386*4882a593Smuzhiyun getvar_table[i].name.str);
1387*4882a593Smuzhiyun fastboot_tx_write_str(response);
1388*4882a593Smuzhiyun #endif
1389*4882a593Smuzhiyun break;
1390*4882a593Smuzhiyun }
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun case FB_SLOT_RETRY_COUNT: {
1393*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1394*4882a593Smuzhiyun AvbABData ab_info;
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun if (rk_avb_get_ab_info(&ab_info) < 0) {
1397*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1398*4882a593Smuzhiyun "%s:not find ab info!",
1399*4882a593Smuzhiyun getvar_table[i].name.str);
1400*4882a593Smuzhiyun fastboot_tx_write_str(response);
1401*4882a593Smuzhiyun break;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun snprintf(actual_resp, chars_left, "%s:a:%d",
1405*4882a593Smuzhiyun getvar_table[i].name.str,
1406*4882a593Smuzhiyun ab_info.slots[1].tries_remaining);
1407*4882a593Smuzhiyun fastboot_tx_write_str(response);
1408*4882a593Smuzhiyun snprintf(actual_resp, chars_left, "%s:b:%d",
1409*4882a593Smuzhiyun getvar_table[i].name.str,
1410*4882a593Smuzhiyun ab_info.slots[1].tries_remaining);
1411*4882a593Smuzhiyun fastboot_tx_write_str(response);
1412*4882a593Smuzhiyun #else
1413*4882a593Smuzhiyun fb_add_string(actual_resp, chars_left,
1414*4882a593Smuzhiyun "%s:not find ab info!",
1415*4882a593Smuzhiyun getvar_table[i].name.str);
1416*4882a593Smuzhiyun fastboot_tx_write_str(response);
1417*4882a593Smuzhiyun #endif
1418*4882a593Smuzhiyun break;
1419*4882a593Smuzhiyun }
1420*4882a593Smuzhiyun #endif
1421*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1422*4882a593Smuzhiyun case FB_AT_VBST:
1423*4882a593Smuzhiyun break;
1424*4882a593Smuzhiyun #endif
1425*4882a593Smuzhiyun default:
1426*4882a593Smuzhiyun fb_getvar_single((char *)getvar_table[i].name.str,
1427*4882a593Smuzhiyun resp_tmp, FASTBOOT_RESPONSE_LEN);
1428*4882a593Smuzhiyun snprintf(actual_resp, chars_left, "%s:%s",
1429*4882a593Smuzhiyun getvar_table[i].name.str, resp_tmp);
1430*4882a593Smuzhiyun fastboot_tx_write_str(response);
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun }
1433*4882a593Smuzhiyun }
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
get_current_slot(void)1436*4882a593Smuzhiyun static int get_current_slot(void)
1437*4882a593Smuzhiyun {
1438*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1439*4882a593Smuzhiyun char cmd[8] = {0};
1440*4882a593Smuzhiyun unsigned int slot_number = -1;
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun memset(cmd, 0x0, sizeof(cmd));
1443*4882a593Smuzhiyun rk_avb_get_current_slot(cmd);
1444*4882a593Smuzhiyun if (strncmp("_a", cmd, 2) == 0) {
1445*4882a593Smuzhiyun slot_number = 0;
1446*4882a593Smuzhiyun } else if (strncmp("_b", cmd, 2) == 0) {
1447*4882a593Smuzhiyun slot_number = 1;
1448*4882a593Smuzhiyun } else {
1449*4882a593Smuzhiyun pr_err("%s: FAILunkown slot name\n", __func__);
1450*4882a593Smuzhiyun return -1;
1451*4882a593Smuzhiyun }
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun return slot_number;
1454*4882a593Smuzhiyun #else
1455*4882a593Smuzhiyun pr_err("%s: FAILnot implemented\n", __func__);
1456*4882a593Smuzhiyun return -1;
1457*4882a593Smuzhiyun #endif
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
should_prevent_userdata_wipe(void)1461*4882a593Smuzhiyun static int should_prevent_userdata_wipe(void)
1462*4882a593Smuzhiyun {
1463*4882a593Smuzhiyun struct misc_virtual_ab_message state;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun memset(&state, 0x0, sizeof(state));
1466*4882a593Smuzhiyun if (read_misc_virtual_ab_message(&state) != 0) {
1467*4882a593Smuzhiyun pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1468*4882a593Smuzhiyun return 0;
1469*4882a593Smuzhiyun }
1470*4882a593Smuzhiyun
1471*4882a593Smuzhiyun if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1472*4882a593Smuzhiyun pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1473*4882a593Smuzhiyun return 0;
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun if (state.merge_status == (uint8_t)ENUM_MERGE_STATUS_MERGING ||
1477*4882a593Smuzhiyun (state.merge_status == (uint8_t)ENUM_MERGE_STATUS_SNAPSHOTTED &&
1478*4882a593Smuzhiyun state.source_slot != get_current_slot())) {
1479*4882a593Smuzhiyun return 1;
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun
1482*4882a593Smuzhiyun return 0;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun #endif
1485*4882a593Smuzhiyun
get_virtual_ab_merge_status(void)1486*4882a593Smuzhiyun static int get_virtual_ab_merge_status(void)
1487*4882a593Smuzhiyun {
1488*4882a593Smuzhiyun struct misc_virtual_ab_message state;
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun memset(&state, 0x0, sizeof(state));
1491*4882a593Smuzhiyun if (read_misc_virtual_ab_message(&state) != 0) {
1492*4882a593Smuzhiyun pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1493*4882a593Smuzhiyun return -1;
1494*4882a593Smuzhiyun }
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1497*4882a593Smuzhiyun pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1498*4882a593Smuzhiyun return -1;
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun return state.merge_status;
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun #endif
1504*4882a593Smuzhiyun
cb_getvar(struct usb_ep * ep,struct usb_request * req)1505*4882a593Smuzhiyun static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun char *cmd = req->buf;
1508*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN] = {0};
1509*4882a593Smuzhiyun const char *str_read_all = "all";
1510*4882a593Smuzhiyun size_t len = 0;
1511*4882a593Smuzhiyun size_t chars_left;
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun strsep(&cmd, ":");
1514*4882a593Smuzhiyun if (!cmd) {
1515*4882a593Smuzhiyun pr_err("missing variable");
1516*4882a593Smuzhiyun fastboot_tx_write_str("FAILmissing var");
1517*4882a593Smuzhiyun return;
1518*4882a593Smuzhiyun }
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun len = strlen(cmd);
1521*4882a593Smuzhiyun if (len == strlen(str_read_all) &&
1522*4882a593Smuzhiyun (strncmp(cmd, str_read_all, len) == 0)) {
1523*4882a593Smuzhiyun fb_getvar_all();
1524*4882a593Smuzhiyun fastboot_tx_write_str("OKAYDone!");
1525*4882a593Smuzhiyun } else {
1526*4882a593Smuzhiyun strcpy(response, "OKAY");
1527*4882a593Smuzhiyun chars_left = sizeof(response) - strlen(response) - 1;
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun if (fb_getvar_single(cmd, &response[strlen(response)],
1530*4882a593Smuzhiyun chars_left) < 0) {
1531*4882a593Smuzhiyun strcpy(cmd, "FAILunknown variable");
1532*4882a593Smuzhiyun strncat(cmd, &response[strlen(response)], chars_left);
1533*4882a593Smuzhiyun fastboot_tx_write_str(cmd);
1534*4882a593Smuzhiyun return;
1535*4882a593Smuzhiyun }
1536*4882a593Smuzhiyun fastboot_tx_write_str(response);
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun return;
1540*4882a593Smuzhiyun }
1541*4882a593Smuzhiyun
rx_bytes_expected(struct usb_ep * ep)1542*4882a593Smuzhiyun static unsigned int rx_bytes_expected(struct usb_ep *ep)
1543*4882a593Smuzhiyun {
1544*4882a593Smuzhiyun int rx_remain = download_size - download_bytes;
1545*4882a593Smuzhiyun unsigned int rem;
1546*4882a593Smuzhiyun unsigned int maxpacket = ep->maxpacket;
1547*4882a593Smuzhiyun
1548*4882a593Smuzhiyun if (rx_remain <= 0)
1549*4882a593Smuzhiyun return 0;
1550*4882a593Smuzhiyun else if (rx_remain > EP_BUFFER_SIZE)
1551*4882a593Smuzhiyun return EP_BUFFER_SIZE;
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun /*
1554*4882a593Smuzhiyun * Some controllers e.g. DWC3 don't like OUT transfers to be
1555*4882a593Smuzhiyun * not ending in maxpacket boundary. So just make them happy by
1556*4882a593Smuzhiyun * always requesting for integral multiple of maxpackets.
1557*4882a593Smuzhiyun * This shouldn't bother controllers that don't care about it.
1558*4882a593Smuzhiyun */
1559*4882a593Smuzhiyun rem = rx_remain % maxpacket;
1560*4882a593Smuzhiyun if (rem > 0)
1561*4882a593Smuzhiyun rx_remain = rx_remain + (maxpacket - rem);
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun return rx_remain;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun #define BYTES_PER_DOT 0x20000
rx_handler_dl_image(struct usb_ep * ep,struct usb_request * req)1567*4882a593Smuzhiyun static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
1568*4882a593Smuzhiyun {
1569*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN];
1570*4882a593Smuzhiyun unsigned int transfer_size = download_size - download_bytes;
1571*4882a593Smuzhiyun const unsigned char *buffer = req->buf;
1572*4882a593Smuzhiyun unsigned int buffer_size = req->actual;
1573*4882a593Smuzhiyun unsigned int pre_dot_num, now_dot_num;
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun if (req->status != 0) {
1576*4882a593Smuzhiyun printf("Bad status: %d\n", req->status);
1577*4882a593Smuzhiyun return;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
1580*4882a593Smuzhiyun if (buffer_size < transfer_size)
1581*4882a593Smuzhiyun transfer_size = buffer_size;
1582*4882a593Smuzhiyun
1583*4882a593Smuzhiyun memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
1584*4882a593Smuzhiyun buffer, transfer_size);
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun pre_dot_num = download_bytes / BYTES_PER_DOT;
1587*4882a593Smuzhiyun download_bytes += transfer_size;
1588*4882a593Smuzhiyun now_dot_num = download_bytes / BYTES_PER_DOT;
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun if (pre_dot_num != now_dot_num) {
1591*4882a593Smuzhiyun putc('.');
1592*4882a593Smuzhiyun if (!(now_dot_num % 74))
1593*4882a593Smuzhiyun putc('\n');
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun /* Check if transfer is done */
1597*4882a593Smuzhiyun if (download_bytes >= download_size) {
1598*4882a593Smuzhiyun /*
1599*4882a593Smuzhiyun * Reset global transfer variable, keep download_bytes because
1600*4882a593Smuzhiyun * it will be used in the next possible flashing command
1601*4882a593Smuzhiyun */
1602*4882a593Smuzhiyun download_size = 0;
1603*4882a593Smuzhiyun req->complete = rx_handler_command;
1604*4882a593Smuzhiyun req->length = EP_BUFFER_SIZE;
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun strcpy(response, "OKAY");
1607*4882a593Smuzhiyun fastboot_tx_write_str(response);
1608*4882a593Smuzhiyun
1609*4882a593Smuzhiyun printf("\ndownloading of %d bytes finished\n", download_bytes);
1610*4882a593Smuzhiyun } else {
1611*4882a593Smuzhiyun req->length = rx_bytes_expected(ep);
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun
1614*4882a593Smuzhiyun req->actual = 0;
1615*4882a593Smuzhiyun usb_ep_queue(ep, req, 0);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
cb_download(struct usb_ep * ep,struct usb_request * req)1618*4882a593Smuzhiyun static void cb_download(struct usb_ep *ep, struct usb_request *req)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun char *cmd = req->buf;
1621*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN];
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun strsep(&cmd, ":");
1624*4882a593Smuzhiyun download_size = simple_strtoul(cmd, NULL, 16);
1625*4882a593Smuzhiyun download_bytes = 0;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun printf("Starting download of %d bytes\n", download_size);
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun if (0 == download_size) {
1630*4882a593Smuzhiyun strcpy(response, "FAILdata invalid size");
1631*4882a593Smuzhiyun } else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) {
1632*4882a593Smuzhiyun download_size = 0;
1633*4882a593Smuzhiyun strcpy(response, "FAILdata too large");
1634*4882a593Smuzhiyun } else {
1635*4882a593Smuzhiyun sprintf(response, "DATA%08x", download_size);
1636*4882a593Smuzhiyun req->complete = rx_handler_dl_image;
1637*4882a593Smuzhiyun req->length = rx_bytes_expected(ep);
1638*4882a593Smuzhiyun }
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun fastboot_tx_write_str(response);
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun
tx_handler_ul(struct usb_ep * ep,struct usb_request * req)1643*4882a593Smuzhiyun static void tx_handler_ul(struct usb_ep *ep, struct usb_request *req)
1644*4882a593Smuzhiyun {
1645*4882a593Smuzhiyun unsigned int xfer_size = 0;
1646*4882a593Smuzhiyun unsigned int pre_dot_num, now_dot_num;
1647*4882a593Smuzhiyun unsigned int remain_size = 0;
1648*4882a593Smuzhiyun unsigned int transferred_size = req->actual;
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun if (req->status != 0) {
1651*4882a593Smuzhiyun printf("Bad status: %d\n", req->status);
1652*4882a593Smuzhiyun return;
1653*4882a593Smuzhiyun }
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun if (start_upload) {
1656*4882a593Smuzhiyun pre_dot_num = upload_bytes / BYTES_PER_DOT;
1657*4882a593Smuzhiyun upload_bytes += transferred_size;
1658*4882a593Smuzhiyun now_dot_num = upload_bytes / BYTES_PER_DOT;
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun if (pre_dot_num != now_dot_num) {
1661*4882a593Smuzhiyun putc('.');
1662*4882a593Smuzhiyun if (!(now_dot_num % 74))
1663*4882a593Smuzhiyun putc('\n');
1664*4882a593Smuzhiyun }
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun remain_size = upload_size - upload_bytes;
1668*4882a593Smuzhiyun xfer_size = (remain_size > EP_BUFFER_SIZE) ?
1669*4882a593Smuzhiyun EP_BUFFER_SIZE : remain_size;
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun debug("%s: remain_size=%d, transferred_size=%d",
1672*4882a593Smuzhiyun __func__, remain_size, transferred_size);
1673*4882a593Smuzhiyun debug("xfer_size=%d, upload_bytes=%d, upload_size=%d!\n",
1674*4882a593Smuzhiyun xfer_size, upload_bytes, upload_size);
1675*4882a593Smuzhiyun
1676*4882a593Smuzhiyun if (remain_size <= 0) {
1677*4882a593Smuzhiyun fastboot_func->in_req->complete = fastboot_complete;
1678*4882a593Smuzhiyun wakeup_thread();
1679*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1680*4882a593Smuzhiyun printf("\nuploading of %d bytes finished\n", upload_bytes);
1681*4882a593Smuzhiyun upload_bytes = 0;
1682*4882a593Smuzhiyun upload_size = 0;
1683*4882a593Smuzhiyun start_upload = false;
1684*4882a593Smuzhiyun return;
1685*4882a593Smuzhiyun }
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun /* Remove the transfer callback which response the upload */
1688*4882a593Smuzhiyun /* request from host */
1689*4882a593Smuzhiyun if (!upload_bytes)
1690*4882a593Smuzhiyun start_upload = true;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun fastboot_tx_write((char *)((phys_addr_t)CONFIG_FASTBOOT_BUF_ADDR + \
1693*4882a593Smuzhiyun upload_bytes),
1694*4882a593Smuzhiyun xfer_size);
1695*4882a593Smuzhiyun }
1696*4882a593Smuzhiyun
cb_upload(struct usb_ep * ep,struct usb_request * req)1697*4882a593Smuzhiyun static void cb_upload(struct usb_ep *ep, struct usb_request *req)
1698*4882a593Smuzhiyun {
1699*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN];
1700*4882a593Smuzhiyun
1701*4882a593Smuzhiyun printf("Starting upload of %d bytes\n", upload_size);
1702*4882a593Smuzhiyun
1703*4882a593Smuzhiyun if (0 == upload_size) {
1704*4882a593Smuzhiyun strcpy(response, "FAILdata invalid size");
1705*4882a593Smuzhiyun } else {
1706*4882a593Smuzhiyun start_upload = false;
1707*4882a593Smuzhiyun sprintf(response, "DATA%08x", upload_size);
1708*4882a593Smuzhiyun fastboot_func->in_req->complete = tx_handler_ul;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun fastboot_tx_write_str(response);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun
do_bootm_on_complete(struct usb_ep * ep,struct usb_request * req)1714*4882a593Smuzhiyun static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun char boot_addr_start[12];
1717*4882a593Smuzhiyun char *bootm_args[] = { "bootm", boot_addr_start, NULL };
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun puts("Booting kernel..\n");
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR);
1722*4882a593Smuzhiyun do_bootm(NULL, 0, 2, bootm_args);
1723*4882a593Smuzhiyun
1724*4882a593Smuzhiyun /* This only happens if image is somehow faulty so we start over */
1725*4882a593Smuzhiyun do_reset(NULL, 0, 0, NULL);
1726*4882a593Smuzhiyun }
1727*4882a593Smuzhiyun
cb_boot(struct usb_ep * ep,struct usb_request * req)1728*4882a593Smuzhiyun static void cb_boot(struct usb_ep *ep, struct usb_request *req)
1729*4882a593Smuzhiyun {
1730*4882a593Smuzhiyun fastboot_func->in_req->complete = do_bootm_on_complete;
1731*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun
do_exit_on_complete(struct usb_ep * ep,struct usb_request * req)1734*4882a593Smuzhiyun static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
1735*4882a593Smuzhiyun {
1736*4882a593Smuzhiyun g_dnl_trigger_detach();
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
cb_continue(struct usb_ep * ep,struct usb_request * req)1739*4882a593Smuzhiyun static void cb_continue(struct usb_ep *ep, struct usb_request *req)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun fastboot_func->in_req->complete = do_exit_on_complete;
1742*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun
cb_set_active(struct usb_ep * ep,struct usb_request * req)1745*4882a593Smuzhiyun static void cb_set_active(struct usb_ep *ep, struct usb_request *req)
1746*4882a593Smuzhiyun {
1747*4882a593Smuzhiyun char *cmd = req->buf;
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun debug("%s: %s\n", __func__, cmd);
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun strsep(&cmd, ":");
1752*4882a593Smuzhiyun if (!cmd) {
1753*4882a593Smuzhiyun pr_err("missing slot name");
1754*4882a593Smuzhiyun fastboot_tx_write_str("FAILmissing slot name");
1755*4882a593Smuzhiyun return;
1756*4882a593Smuzhiyun }
1757*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1758*4882a593Smuzhiyun if (get_virtual_ab_merge_status() == ENUM_MERGE_STATUS_MERGING) {
1759*4882a593Smuzhiyun pr_err("virtual A/B is merging, abort the operation");
1760*4882a593Smuzhiyun fastboot_tx_write_str("FAILvirtual A/B is merging, abort");
1761*4882a593Smuzhiyun return;
1762*4882a593Smuzhiyun }
1763*4882a593Smuzhiyun #endif
1764*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1765*4882a593Smuzhiyun unsigned int slot_number;
1766*4882a593Smuzhiyun if (strncmp("a", cmd, 1) == 0) {
1767*4882a593Smuzhiyun slot_number = 0;
1768*4882a593Smuzhiyun rk_avb_set_slot_active(&slot_number);
1769*4882a593Smuzhiyun } else if (strncmp("b", cmd, 1) == 0) {
1770*4882a593Smuzhiyun slot_number = 1;
1771*4882a593Smuzhiyun rk_avb_set_slot_active(&slot_number);
1772*4882a593Smuzhiyun } else {
1773*4882a593Smuzhiyun fastboot_tx_write_str("FAILunkown slot name");
1774*4882a593Smuzhiyun return;
1775*4882a593Smuzhiyun }
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1778*4882a593Smuzhiyun return;
1779*4882a593Smuzhiyun #else
1780*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1781*4882a593Smuzhiyun return;
1782*4882a593Smuzhiyun #endif
1783*4882a593Smuzhiyun }
1784*4882a593Smuzhiyun
1785*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
cb_flash(struct usb_ep * ep,struct usb_request * req)1786*4882a593Smuzhiyun static void cb_flash(struct usb_ep *ep, struct usb_request *req)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun char *cmd = req->buf;
1789*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN] = {0};
1790*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1791*4882a593Smuzhiyun uint8_t flash_lock_state;
1792*4882a593Smuzhiyun
1793*4882a593Smuzhiyun if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
1794*4882a593Smuzhiyun /* write the device flashing unlock when first read */
1795*4882a593Smuzhiyun if (rk_avb_write_flash_lock_state(1)) {
1796*4882a593Smuzhiyun fastboot_tx_write_str("FAILflash lock state write failure");
1797*4882a593Smuzhiyun return;
1798*4882a593Smuzhiyun }
1799*4882a593Smuzhiyun if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
1800*4882a593Smuzhiyun fastboot_tx_write_str("FAILflash lock state read failure");
1801*4882a593Smuzhiyun return;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun if (flash_lock_state == 0) {
1806*4882a593Smuzhiyun fastboot_tx_write_str("FAILThe device is locked, can not flash!");
1807*4882a593Smuzhiyun printf("The device is locked, can not flash!\n");
1808*4882a593Smuzhiyun return;
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun #endif
1811*4882a593Smuzhiyun strsep(&cmd, ":");
1812*4882a593Smuzhiyun if (!cmd) {
1813*4882a593Smuzhiyun pr_err("missing partition name");
1814*4882a593Smuzhiyun fastboot_tx_write_str("FAILmissing partition name");
1815*4882a593Smuzhiyun return;
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
1818*4882a593Smuzhiyun if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
1819*4882a593Smuzhiyun if (should_prevent_userdata_wipe()) {
1820*4882a593Smuzhiyun pr_err("FAILThe virtual A/B merging, can not flash userdata or metadata!\n");
1821*4882a593Smuzhiyun fastboot_tx_write_str("FAILvirtual A/B merging,abort flash!");
1822*4882a593Smuzhiyun return;
1823*4882a593Smuzhiyun }
1824*4882a593Smuzhiyun }
1825*4882a593Smuzhiyun #endif
1826*4882a593Smuzhiyun fastboot_fail("no flash device defined", response);
1827*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
1828*4882a593Smuzhiyun fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
1829*4882a593Smuzhiyun download_bytes, response);
1830*4882a593Smuzhiyun #endif
1831*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
1832*4882a593Smuzhiyun fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
1833*4882a593Smuzhiyun download_bytes, response);
1834*4882a593Smuzhiyun #endif
1835*4882a593Smuzhiyun fastboot_tx_write_str(response);
1836*4882a593Smuzhiyun }
1837*4882a593Smuzhiyun
cb_flashing(struct usb_ep * ep,struct usb_request * req)1838*4882a593Smuzhiyun static void cb_flashing(struct usb_ep *ep, struct usb_request *req)
1839*4882a593Smuzhiyun {
1840*4882a593Smuzhiyun char *cmd = req->buf;
1841*4882a593Smuzhiyun
1842*4882a593Smuzhiyun if (strncmp("lock", cmd + 9, 4) == 0) {
1843*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1844*4882a593Smuzhiyun uint8_t flash_lock_state;
1845*4882a593Smuzhiyun flash_lock_state = 0;
1846*4882a593Smuzhiyun if (rk_avb_write_flash_lock_state(flash_lock_state))
1847*4882a593Smuzhiyun fastboot_tx_write_str("FAILflash lock state"
1848*4882a593Smuzhiyun " write failure");
1849*4882a593Smuzhiyun else
1850*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1851*4882a593Smuzhiyun #else
1852*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1853*4882a593Smuzhiyun #endif
1854*4882a593Smuzhiyun } else if (strncmp("unlock", cmd + 9, 6) == 0) {
1855*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1856*4882a593Smuzhiyun uint8_t flash_lock_state;
1857*4882a593Smuzhiyun flash_lock_state = 1;
1858*4882a593Smuzhiyun if (rk_avb_write_flash_lock_state(flash_lock_state))
1859*4882a593Smuzhiyun fastboot_tx_write_str("FAILflash lock state"
1860*4882a593Smuzhiyun " write failure");
1861*4882a593Smuzhiyun else
1862*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1863*4882a593Smuzhiyun #else
1864*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1865*4882a593Smuzhiyun #endif
1866*4882a593Smuzhiyun } else if (strncmp("lock_critical", cmd + 9, 12) == 0) {
1867*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1868*4882a593Smuzhiyun } else if (strncmp("unlock_critical", cmd + 9, 14) == 0) {
1869*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1870*4882a593Smuzhiyun } else if (strncmp("get_unlock_ability", cmd + 9, 17) == 0) {
1871*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1872*4882a593Smuzhiyun } else if (strncmp("get_unlock_bootloader_nonce", cmd + 4, 27) == 0) {
1873*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1874*4882a593Smuzhiyun } else if (strncmp("unlock_bootloader", cmd + 9, 17) == 0) {
1875*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1876*4882a593Smuzhiyun } else if (strncmp("lock_bootloader", cmd + 9, 15) == 0) {
1877*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1878*4882a593Smuzhiyun } else {
1879*4882a593Smuzhiyun fastboot_tx_write_str("FAILunknown flashing command");
1880*4882a593Smuzhiyun }
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun #endif
1883*4882a593Smuzhiyun
cb_oem_perm_attr(void)1884*4882a593Smuzhiyun static void cb_oem_perm_attr(void)
1885*4882a593Smuzhiyun {
1886*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1887*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1888*4882a593Smuzhiyun sha256_context ctx;
1889*4882a593Smuzhiyun uint8_t digest[SHA256_SUM_LEN] = {0};
1890*4882a593Smuzhiyun uint8_t digest_temp[SHA256_SUM_LEN] = {0};
1891*4882a593Smuzhiyun uint8_t perm_attr_temp[PERM_ATTR_TOTAL_SIZE] = {0};
1892*4882a593Smuzhiyun uint8_t flag = 0;
1893*4882a593Smuzhiyun #endif
1894*4882a593Smuzhiyun if (PERM_ATTR_TOTAL_SIZE != download_bytes) {
1895*4882a593Smuzhiyun printf("Permanent attribute size is not equal!\n");
1896*4882a593Smuzhiyun fastboot_tx_write_str("FAILincorrect perm attribute size");
1897*4882a593Smuzhiyun return;
1898*4882a593Smuzhiyun }
1899*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1900*4882a593Smuzhiyun if (rk_avb_read_perm_attr_flag(&flag)) {
1901*4882a593Smuzhiyun printf("rk_avb_read_perm_attr_flag error!\n");
1902*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr read failed");
1903*4882a593Smuzhiyun return;
1904*4882a593Smuzhiyun }
1905*4882a593Smuzhiyun
1906*4882a593Smuzhiyun if (flag == PERM_ATTR_SUCCESS_FLAG) {
1907*4882a593Smuzhiyun if (rk_avb_read_attribute_hash(digest_temp,
1908*4882a593Smuzhiyun SHA256_SUM_LEN)) {
1909*4882a593Smuzhiyun printf("The efuse IO can not be used!\n");
1910*4882a593Smuzhiyun fastboot_tx_write_str("FAILefuse IO can not be used");
1911*4882a593Smuzhiyun return;
1912*4882a593Smuzhiyun }
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
1915*4882a593Smuzhiyun if (rk_avb_read_permanent_attributes(perm_attr_temp,
1916*4882a593Smuzhiyun PERM_ATTR_TOTAL_SIZE)) {
1917*4882a593Smuzhiyun printf("rk_avb_write_permanent_attributes error!\n");
1918*4882a593Smuzhiyun fastboot_tx_write_str("FAILread perm attr error");
1919*4882a593Smuzhiyun return;
1920*4882a593Smuzhiyun }
1921*4882a593Smuzhiyun
1922*4882a593Smuzhiyun sha256_starts(&ctx);
1923*4882a593Smuzhiyun sha256_update(&ctx,
1924*4882a593Smuzhiyun (const uint8_t *)perm_attr_temp,
1925*4882a593Smuzhiyun PERM_ATTR_TOTAL_SIZE);
1926*4882a593Smuzhiyun sha256_finish(&ctx, digest);
1927*4882a593Smuzhiyun if (memcmp(digest, digest_temp, SHA256_SUM_LEN) == 0) {
1928*4882a593Smuzhiyun printf("The hash has been written!\n");
1929*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1930*4882a593Smuzhiyun return;
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun }
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun if (rk_avb_write_perm_attr_flag(0)) {
1935*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr flag write failure");
1936*4882a593Smuzhiyun return;
1937*4882a593Smuzhiyun }
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun #endif
1940*4882a593Smuzhiyun if (rk_avb_write_permanent_attributes((uint8_t *)
1941*4882a593Smuzhiyun CONFIG_FASTBOOT_BUF_ADDR,
1942*4882a593Smuzhiyun download_bytes)) {
1943*4882a593Smuzhiyun if (rk_avb_write_perm_attr_flag(0)) {
1944*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr flag write failure");
1945*4882a593Smuzhiyun return;
1946*4882a593Smuzhiyun }
1947*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr write failed");
1948*4882a593Smuzhiyun return;
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
1951*4882a593Smuzhiyun memset(digest, 0, SHA256_SUM_LEN);
1952*4882a593Smuzhiyun sha256_starts(&ctx);
1953*4882a593Smuzhiyun sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
1954*4882a593Smuzhiyun PERM_ATTR_TOTAL_SIZE);
1955*4882a593Smuzhiyun sha256_finish(&ctx, digest);
1956*4882a593Smuzhiyun
1957*4882a593Smuzhiyun if (rk_avb_write_attribute_hash((uint8_t *)digest,
1958*4882a593Smuzhiyun SHA256_SUM_LEN)) {
1959*4882a593Smuzhiyun if (rk_avb_read_attribute_hash(digest_temp,
1960*4882a593Smuzhiyun SHA256_SUM_LEN)) {
1961*4882a593Smuzhiyun printf("The efuse IO can not be used!\n");
1962*4882a593Smuzhiyun fastboot_tx_write_str("FAILefuse IO can not be used");
1963*4882a593Smuzhiyun return;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
1966*4882a593Smuzhiyun if (rk_avb_write_perm_attr_flag(0)) {
1967*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr flag write failure");
1968*4882a593Smuzhiyun return;
1969*4882a593Smuzhiyun }
1970*4882a593Smuzhiyun printf("The hash has been written, but is different!\n");
1971*4882a593Smuzhiyun fastboot_tx_write_str("FAILhash comparison failure");
1972*4882a593Smuzhiyun return;
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun }
1975*4882a593Smuzhiyun #endif
1976*4882a593Smuzhiyun if (rk_avb_write_perm_attr_flag(PERM_ATTR_SUCCESS_FLAG)) {
1977*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attr flag write failure");
1978*4882a593Smuzhiyun return;
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun
1981*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
1982*4882a593Smuzhiyun #else
1983*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
1984*4882a593Smuzhiyun #endif
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun
cb_oem_perm_attr_rsa_cer(void)1987*4882a593Smuzhiyun static void cb_oem_perm_attr_rsa_cer(void)
1988*4882a593Smuzhiyun {
1989*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
1990*4882a593Smuzhiyun if (download_bytes != 256) {
1991*4882a593Smuzhiyun printf("Permanent attribute rsahash size is not equal!\n");
1992*4882a593Smuzhiyun fastboot_tx_write_str("FAILperm attribute rsahash size error");
1993*4882a593Smuzhiyun return;
1994*4882a593Smuzhiyun }
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun if (rk_avb_set_perm_attr_cer((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
1997*4882a593Smuzhiyun download_bytes)) {
1998*4882a593Smuzhiyun fastboot_tx_write_str("FAILSet perm attr cer fail!");
1999*4882a593Smuzhiyun return;
2000*4882a593Smuzhiyun }
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2003*4882a593Smuzhiyun #else
2004*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2005*4882a593Smuzhiyun #endif
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun
cb_oem(struct usb_ep * ep,struct usb_request * req)2008*4882a593Smuzhiyun static void cb_oem(struct usb_ep *ep, struct usb_request *req)
2009*4882a593Smuzhiyun {
2010*4882a593Smuzhiyun char *cmd = req->buf;
2011*4882a593Smuzhiyun
2012*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
2013*4882a593Smuzhiyun if (strncmp("format", cmd + 4, 6) == 0) {
2014*4882a593Smuzhiyun char cmdbuf[32];
2015*4882a593Smuzhiyun sprintf(cmdbuf, "gpt write mmc %x $partitions",
2016*4882a593Smuzhiyun CONFIG_FASTBOOT_FLASH_MMC_DEV);
2017*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
2018*4882a593Smuzhiyun if (should_prevent_userdata_wipe()) {
2019*4882a593Smuzhiyun printf("FAILThe virtual A/B merging, can not format!\n");
2020*4882a593Smuzhiyun fastboot_tx_write_str("FAILvirtual A/B merging,abort format!");
2021*4882a593Smuzhiyun } else {
2022*4882a593Smuzhiyun if (run_command(cmdbuf, 0))
2023*4882a593Smuzhiyun fastboot_tx_write_str("FAILmmc write failure");
2024*4882a593Smuzhiyun else
2025*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2026*4882a593Smuzhiyun }
2027*4882a593Smuzhiyun #else
2028*4882a593Smuzhiyun if (run_command(cmdbuf, 0))
2029*4882a593Smuzhiyun fastboot_tx_write_str("FAILmmc write failure");
2030*4882a593Smuzhiyun else
2031*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2032*4882a593Smuzhiyun #endif
2033*4882a593Smuzhiyun } else
2034*4882a593Smuzhiyun #endif
2035*4882a593Smuzhiyun if (strncmp("unlock", cmd + 4, 8) == 0) {
2036*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2037*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2038*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2039*4882a593Smuzhiyun return;
2040*4882a593Smuzhiyun #else
2041*4882a593Smuzhiyun uint8_t unlock = 0;
2042*4882a593Smuzhiyun TEEC_Result result;
2043*4882a593Smuzhiyun debug("oem unlock\n");
2044*4882a593Smuzhiyun result = trusty_read_oem_unlock(&unlock);
2045*4882a593Smuzhiyun if (result) {
2046*4882a593Smuzhiyun printf("read oem unlock status with error : 0x%x\n", result);
2047*4882a593Smuzhiyun fastboot_tx_write_str("FAILRead oem unlock status failed");
2048*4882a593Smuzhiyun return;
2049*4882a593Smuzhiyun }
2050*4882a593Smuzhiyun if (unlock) {
2051*4882a593Smuzhiyun printf("oem unlock ignored, device already unlocked\n");
2052*4882a593Smuzhiyun fastboot_tx_write_str("FAILalready unlocked");
2053*4882a593Smuzhiyun return;
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun printf("oem unlock requested:\n");
2056*4882a593Smuzhiyun printf("\tUnlocking forces a factory reset and could\n");
2057*4882a593Smuzhiyun printf("\topen your device up to a world of hurt. If you\n");
2058*4882a593Smuzhiyun printf("\tare sure you know what you're doing, then accept\n");
2059*4882a593Smuzhiyun printf("\tvia 'fastboot oem unlock_accept'.\n");
2060*4882a593Smuzhiyun env_set("unlock", "unlock");
2061*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2062*4882a593Smuzhiyun #endif
2063*4882a593Smuzhiyun #else
2064*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2065*4882a593Smuzhiyun return;
2066*4882a593Smuzhiyun #endif
2067*4882a593Smuzhiyun } else if (strncmp("unlock_accept", cmd + 4, 13) == 0) {
2068*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2069*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2070*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2071*4882a593Smuzhiyun return;
2072*4882a593Smuzhiyun #else
2073*4882a593Smuzhiyun char *unlock = env_get("unlock");
2074*4882a593Smuzhiyun TEEC_Result result;
2075*4882a593Smuzhiyun debug("oem unlock_accept\n");
2076*4882a593Smuzhiyun if (unlock == NULL || strncmp("unlock", unlock, 6) != 0) {
2077*4882a593Smuzhiyun printf("oem unlock_accept ignored, not pending\n");
2078*4882a593Smuzhiyun fastboot_tx_write_str("FAILoem unlock not requested");
2079*4882a593Smuzhiyun return;
2080*4882a593Smuzhiyun }
2081*4882a593Smuzhiyun env_set("unlock", "");
2082*4882a593Smuzhiyun printf("Erasing userdata partition\n");
2083*4882a593Smuzhiyun struct blk_desc *dev_desc;
2084*4882a593Smuzhiyun disk_partition_t part_info;
2085*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
2086*4882a593Smuzhiyun if (!dev_desc) {
2087*4882a593Smuzhiyun printf("%s: dev_desc is NULL!\n", __func__);
2088*4882a593Smuzhiyun return;
2089*4882a593Smuzhiyun }
2090*4882a593Smuzhiyun int ret = part_get_info_by_name(dev_desc, "userdata",
2091*4882a593Smuzhiyun &part_info);
2092*4882a593Smuzhiyun if (ret < 0) {
2093*4882a593Smuzhiyun printf("not found userdata partition");
2094*4882a593Smuzhiyun printf("Erase failed with error %d\n", ret);
2095*4882a593Smuzhiyun fastboot_tx_write_str("FAILErasing userdata failed");
2096*4882a593Smuzhiyun return;
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun ret = blk_derase(dev_desc, part_info.start, part_info.size);
2099*4882a593Smuzhiyun if (ret != part_info.size) {
2100*4882a593Smuzhiyun printf("Erase failed with error %d\n", ret);
2101*4882a593Smuzhiyun fastboot_tx_write_str("FAILErasing userdata failed");
2102*4882a593Smuzhiyun return;
2103*4882a593Smuzhiyun }
2104*4882a593Smuzhiyun printf("Erasing succeeded\n");
2105*4882a593Smuzhiyun
2106*4882a593Smuzhiyun result = trusty_write_oem_unlock(1);
2107*4882a593Smuzhiyun if (result) {
2108*4882a593Smuzhiyun printf("write oem unlock status with error : 0x%x\n", result);
2109*4882a593Smuzhiyun fastboot_tx_write_str("FAILWrite oem unlock status failed");
2110*4882a593Smuzhiyun return;
2111*4882a593Smuzhiyun }
2112*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2113*4882a593Smuzhiyun
2114*4882a593Smuzhiyun /*
2115*4882a593Smuzhiyun * now reboot into recovery to do a format of the
2116*4882a593Smuzhiyun * userdata partition so it's ready to use on next boot
2117*4882a593Smuzhiyun */
2118*4882a593Smuzhiyun board_run_recovery_wipe_data();
2119*4882a593Smuzhiyun #endif
2120*4882a593Smuzhiyun #else
2121*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2122*4882a593Smuzhiyun return;
2123*4882a593Smuzhiyun #endif
2124*4882a593Smuzhiyun } else if (strncmp("lock", cmd + 4, 8) == 0) {
2125*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2126*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2127*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2128*4882a593Smuzhiyun return;
2129*4882a593Smuzhiyun #else
2130*4882a593Smuzhiyun TEEC_Result result;
2131*4882a593Smuzhiyun uint8_t unlock = 0;
2132*4882a593Smuzhiyun trusty_read_oem_unlock(&unlock);
2133*4882a593Smuzhiyun if (!unlock) {
2134*4882a593Smuzhiyun printf("oem lock ignored, already locked\n");
2135*4882a593Smuzhiyun fastboot_tx_write_str("FAILalready locked");
2136*4882a593Smuzhiyun return;
2137*4882a593Smuzhiyun }
2138*4882a593Smuzhiyun
2139*4882a593Smuzhiyun result = trusty_write_oem_unlock(0);
2140*4882a593Smuzhiyun if (result) {
2141*4882a593Smuzhiyun printf("write oem unlock status with error : 0x%x\n", result);
2142*4882a593Smuzhiyun fastboot_tx_write_str("FAILWrite oem unlock status failed");
2143*4882a593Smuzhiyun return;
2144*4882a593Smuzhiyun }
2145*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2146*4882a593Smuzhiyun #endif
2147*4882a593Smuzhiyun #else
2148*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2149*4882a593Smuzhiyun return;
2150*4882a593Smuzhiyun #endif
2151*4882a593Smuzhiyun } else if (strncmp("at-get-ca-request", cmd + 4, 17) == 0) {
2152*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
2153*4882a593Smuzhiyun uint8_t out[ATTEST_CA_OUT_SIZE];
2154*4882a593Smuzhiyun uint32_t operation_size = download_bytes;
2155*4882a593Smuzhiyun uint32_t out_len = ATTEST_CA_OUT_SIZE;
2156*4882a593Smuzhiyun uint32_t res = 0;
2157*4882a593Smuzhiyun
2158*4882a593Smuzhiyun res = trusty_attest_get_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2159*4882a593Smuzhiyun &operation_size, out, &out_len);
2160*4882a593Smuzhiyun if (res) {
2161*4882a593Smuzhiyun fastboot_tx_write_str("FAILtrusty_attest_get_ca failed");
2162*4882a593Smuzhiyun return;
2163*4882a593Smuzhiyun }
2164*4882a593Smuzhiyun upload_size = out_len;
2165*4882a593Smuzhiyun memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR, out, out_len);
2166*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2167*4882a593Smuzhiyun #else
2168*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2169*4882a593Smuzhiyun return;
2170*4882a593Smuzhiyun #endif
2171*4882a593Smuzhiyun } else if (strncmp("at-set-ca-response", cmd + 4, 18) == 0) {
2172*4882a593Smuzhiyun #ifdef CONFIG_OPTEE_CLIENT
2173*4882a593Smuzhiyun uint32_t ca_response_size = download_bytes;
2174*4882a593Smuzhiyun uint32_t res = 0;
2175*4882a593Smuzhiyun
2176*4882a593Smuzhiyun res = trusty_attest_set_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2177*4882a593Smuzhiyun &ca_response_size);
2178*4882a593Smuzhiyun if (res)
2179*4882a593Smuzhiyun fastboot_tx_write_str("FAILtrusty_attest_set_ca failed");
2180*4882a593Smuzhiyun else
2181*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2182*4882a593Smuzhiyun #else
2183*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2184*4882a593Smuzhiyun return;
2185*4882a593Smuzhiyun #endif
2186*4882a593Smuzhiyun } else if (strncmp("at-get-vboot-unlock-challenge", cmd + 4, 29) == 0) {
2187*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2188*4882a593Smuzhiyun uint32_t challenge_len = 0;
2189*4882a593Smuzhiyun int ret = 0;
2190*4882a593Smuzhiyun
2191*4882a593Smuzhiyun ret = rk_generate_unlock_challenge((void *)CONFIG_FASTBOOT_BUF_ADDR, &challenge_len);
2192*4882a593Smuzhiyun if (ret == 0) {
2193*4882a593Smuzhiyun upload_size = challenge_len;
2194*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2195*4882a593Smuzhiyun } else {
2196*4882a593Smuzhiyun fastboot_tx_write_str("FAILgenerate unlock challenge fail!");
2197*4882a593Smuzhiyun }
2198*4882a593Smuzhiyun #else
2199*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2200*4882a593Smuzhiyun return;
2201*4882a593Smuzhiyun #endif
2202*4882a593Smuzhiyun } else if (strncmp("at-lock-vboot", cmd + 4, 13) == 0) {
2203*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2204*4882a593Smuzhiyun uint8_t lock_state;
2205*4882a593Smuzhiyun lock_state = 0;
2206*4882a593Smuzhiyun if (rk_avb_write_lock_state(lock_state))
2207*4882a593Smuzhiyun fastboot_tx_write_str("FAILwrite lock state failed");
2208*4882a593Smuzhiyun else
2209*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2210*4882a593Smuzhiyun #else
2211*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2212*4882a593Smuzhiyun #endif
2213*4882a593Smuzhiyun } else if (strncmp("at-unlock-vboot", cmd + 4, 15) == 0) {
2214*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2215*4882a593Smuzhiyun uint8_t lock_state;
2216*4882a593Smuzhiyun char out_is_trusted = true;
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun if (rk_avb_read_lock_state(&lock_state))
2219*4882a593Smuzhiyun fastboot_tx_write_str("FAILlock sate read failure");
2220*4882a593Smuzhiyun if (lock_state >> 1 == 1) {
2221*4882a593Smuzhiyun fastboot_tx_write_str("FAILThe vboot is disable!");
2222*4882a593Smuzhiyun } else {
2223*4882a593Smuzhiyun lock_state = 1;
2224*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_ENABLE_ATH_UNLOCK
2225*4882a593Smuzhiyun if (rk_auth_unlock((void *)CONFIG_FASTBOOT_BUF_ADDR,
2226*4882a593Smuzhiyun &out_is_trusted)) {
2227*4882a593Smuzhiyun printf("rk_auth_unlock ops error!\n");
2228*4882a593Smuzhiyun fastboot_tx_write_str("FAILrk_auth_unlock ops error!");
2229*4882a593Smuzhiyun return;
2230*4882a593Smuzhiyun }
2231*4882a593Smuzhiyun #endif
2232*4882a593Smuzhiyun if (out_is_trusted == true) {
2233*4882a593Smuzhiyun if (rk_avb_write_lock_state(lock_state))
2234*4882a593Smuzhiyun fastboot_tx_write_str("FAILwrite lock state failed");
2235*4882a593Smuzhiyun else
2236*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2237*4882a593Smuzhiyun } else {
2238*4882a593Smuzhiyun fastboot_tx_write_str("FAILauthenticated unlock fail");
2239*4882a593Smuzhiyun }
2240*4882a593Smuzhiyun }
2241*4882a593Smuzhiyun #else
2242*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2243*4882a593Smuzhiyun #endif
2244*4882a593Smuzhiyun } else if (strncmp("fuse at-perm-attr", cmd + 4, 16) == 0) {
2245*4882a593Smuzhiyun cb_oem_perm_attr();
2246*4882a593Smuzhiyun } else if (strncmp("fuse at-rsa-perm-attr", cmd + 4, 25) == 0) {
2247*4882a593Smuzhiyun cb_oem_perm_attr_rsa_cer();
2248*4882a593Smuzhiyun } else if (strncmp("fuse at-bootloader-vboot-key", cmd + 4, 27) == 0) {
2249*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2250*4882a593Smuzhiyun sha256_context ctx;
2251*4882a593Smuzhiyun uint8_t digest[SHA256_SUM_LEN];
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun if (download_bytes != VBOOT_KEY_HASH_SIZE) {
2254*4882a593Smuzhiyun fastboot_tx_write_str("FAILinvalid vboot key length");
2255*4882a593Smuzhiyun printf("The vboot key size error!\n");
2256*4882a593Smuzhiyun return;
2257*4882a593Smuzhiyun }
2258*4882a593Smuzhiyun
2259*4882a593Smuzhiyun sha256_starts(&ctx);
2260*4882a593Smuzhiyun sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
2261*4882a593Smuzhiyun VBOOT_KEY_SIZE);
2262*4882a593Smuzhiyun sha256_finish(&ctx, digest);
2263*4882a593Smuzhiyun
2264*4882a593Smuzhiyun if (rk_avb_write_vbootkey_hash((uint8_t *)digest,
2265*4882a593Smuzhiyun SHA256_SUM_LEN)) {
2266*4882a593Smuzhiyun fastboot_tx_write_str("FAILvbootkey hash write failure");
2267*4882a593Smuzhiyun return;
2268*4882a593Smuzhiyun }
2269*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2270*4882a593Smuzhiyun #else
2271*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2272*4882a593Smuzhiyun #endif
2273*4882a593Smuzhiyun } else if (strncmp("init-ab-metadata", cmd + 4, 16) == 0) {
2274*4882a593Smuzhiyun #ifdef CONFIG_RK_AVB_LIBAVB_USER
2275*4882a593Smuzhiyun if (rk_avb_init_ab_metadata()) {
2276*4882a593Smuzhiyun fastboot_tx_write_str("FAILinit ab data fail!");
2277*4882a593Smuzhiyun return;
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun fastboot_tx_write_str("OKAY");
2280*4882a593Smuzhiyun #else
2281*4882a593Smuzhiyun fastboot_tx_write_str("FAILnot implemented");
2282*4882a593Smuzhiyun #endif
2283*4882a593Smuzhiyun } else {
2284*4882a593Smuzhiyun fastboot_tx_write_str("FAILunknown oem command");
2285*4882a593Smuzhiyun }
2286*4882a593Smuzhiyun }
2287*4882a593Smuzhiyun
2288*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
cb_erase(struct usb_ep * ep,struct usb_request * req)2289*4882a593Smuzhiyun static void cb_erase(struct usb_ep *ep, struct usb_request *req)
2290*4882a593Smuzhiyun {
2291*4882a593Smuzhiyun char *cmd = req->buf;
2292*4882a593Smuzhiyun char response[FASTBOOT_RESPONSE_LEN] = {0};
2293*4882a593Smuzhiyun
2294*4882a593Smuzhiyun strsep(&cmd, ":");
2295*4882a593Smuzhiyun if (!cmd) {
2296*4882a593Smuzhiyun pr_err("missing partition name");
2297*4882a593Smuzhiyun fastboot_tx_write_str("FAILmissing partition name");
2298*4882a593Smuzhiyun return;
2299*4882a593Smuzhiyun }
2300*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_AB
2301*4882a593Smuzhiyun if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
2302*4882a593Smuzhiyun if (should_prevent_userdata_wipe()) {
2303*4882a593Smuzhiyun pr_err("virtual A/B merging, can not erase userdata or metadata!\n");
2304*4882a593Smuzhiyun fastboot_tx_write_str("FAILvirtual A/B merging,abort erase!");
2305*4882a593Smuzhiyun return;
2306*4882a593Smuzhiyun }
2307*4882a593Smuzhiyun }
2308*4882a593Smuzhiyun #endif
2309*4882a593Smuzhiyun fastboot_fail("no flash device defined", response);
2310*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
2311*4882a593Smuzhiyun fb_mmc_erase(cmd, response);
2312*4882a593Smuzhiyun #endif
2313*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
2314*4882a593Smuzhiyun fb_nand_erase(cmd, response);
2315*4882a593Smuzhiyun #endif
2316*4882a593Smuzhiyun fastboot_tx_write_str(response);
2317*4882a593Smuzhiyun }
2318*4882a593Smuzhiyun #endif
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun struct cmd_dispatch_info {
2321*4882a593Smuzhiyun char *cmd;
2322*4882a593Smuzhiyun void (*cb)(struct usb_ep *ep, struct usb_request *req);
2323*4882a593Smuzhiyun };
2324*4882a593Smuzhiyun
2325*4882a593Smuzhiyun static const struct cmd_dispatch_info cmd_dispatch_info[] = {
2326*4882a593Smuzhiyun {
2327*4882a593Smuzhiyun .cmd = "reboot",
2328*4882a593Smuzhiyun .cb = cb_reboot,
2329*4882a593Smuzhiyun }, {
2330*4882a593Smuzhiyun .cmd = "getvar:",
2331*4882a593Smuzhiyun .cb = cb_getvar,
2332*4882a593Smuzhiyun }, {
2333*4882a593Smuzhiyun .cmd = "download:",
2334*4882a593Smuzhiyun .cb = cb_download,
2335*4882a593Smuzhiyun }, {
2336*4882a593Smuzhiyun .cmd = "upload",
2337*4882a593Smuzhiyun .cb = cb_upload,
2338*4882a593Smuzhiyun }, {
2339*4882a593Smuzhiyun .cmd = "boot",
2340*4882a593Smuzhiyun .cb = cb_boot,
2341*4882a593Smuzhiyun }, {
2342*4882a593Smuzhiyun .cmd = "continue",
2343*4882a593Smuzhiyun .cb = cb_continue,
2344*4882a593Smuzhiyun }, {
2345*4882a593Smuzhiyun .cmd = "set_active",
2346*4882a593Smuzhiyun .cb = cb_set_active,
2347*4882a593Smuzhiyun },
2348*4882a593Smuzhiyun #ifdef CONFIG_FASTBOOT_FLASH
2349*4882a593Smuzhiyun {
2350*4882a593Smuzhiyun .cmd = "flashing",
2351*4882a593Smuzhiyun .cb = cb_flashing,
2352*4882a593Smuzhiyun },
2353*4882a593Smuzhiyun {
2354*4882a593Smuzhiyun .cmd = "flash",
2355*4882a593Smuzhiyun .cb = cb_flash,
2356*4882a593Smuzhiyun }, {
2357*4882a593Smuzhiyun .cmd = "erase",
2358*4882a593Smuzhiyun .cb = cb_erase,
2359*4882a593Smuzhiyun },
2360*4882a593Smuzhiyun #endif
2361*4882a593Smuzhiyun {
2362*4882a593Smuzhiyun .cmd = "oem",
2363*4882a593Smuzhiyun .cb = cb_oem,
2364*4882a593Smuzhiyun },
2365*4882a593Smuzhiyun };
2366*4882a593Smuzhiyun
rx_handler_command(struct usb_ep * ep,struct usb_request * req)2367*4882a593Smuzhiyun static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
2368*4882a593Smuzhiyun {
2369*4882a593Smuzhiyun char *cmdbuf = req->buf;
2370*4882a593Smuzhiyun void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
2371*4882a593Smuzhiyun int i;
2372*4882a593Smuzhiyun
2373*4882a593Smuzhiyun if (req->status != 0 || req->length == 0)
2374*4882a593Smuzhiyun return;
2375*4882a593Smuzhiyun
2376*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
2377*4882a593Smuzhiyun if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
2378*4882a593Smuzhiyun func_cb = cmd_dispatch_info[i].cb;
2379*4882a593Smuzhiyun break;
2380*4882a593Smuzhiyun }
2381*4882a593Smuzhiyun }
2382*4882a593Smuzhiyun
2383*4882a593Smuzhiyun if (!func_cb) {
2384*4882a593Smuzhiyun pr_err("unknown command: %.*s", req->actual, cmdbuf);
2385*4882a593Smuzhiyun fastboot_tx_write_str("FAILunknown command");
2386*4882a593Smuzhiyun } else {
2387*4882a593Smuzhiyun if (req->actual < req->length) {
2388*4882a593Smuzhiyun u8 *buf = (u8 *)req->buf;
2389*4882a593Smuzhiyun buf[req->actual] = 0;
2390*4882a593Smuzhiyun func_cb(ep, req);
2391*4882a593Smuzhiyun } else {
2392*4882a593Smuzhiyun pr_err("buffer overflow");
2393*4882a593Smuzhiyun fastboot_tx_write_str("FAILbuffer overflow");
2394*4882a593Smuzhiyun }
2395*4882a593Smuzhiyun }
2396*4882a593Smuzhiyun
2397*4882a593Smuzhiyun *cmdbuf = '\0';
2398*4882a593Smuzhiyun req->actual = 0;
2399*4882a593Smuzhiyun usb_ep_queue(ep, req, 0);
2400*4882a593Smuzhiyun }
2401