1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/binding.h>
6 #include <ddk/debug.h>
7 #include <ddk/device.h>
8 #include <usb/usb.h>
9 #include <fuchsia/mem/c/fidl.h>
10 #include <zircon/assert.h>
11 #include <zircon/usb/test/fwloader/c/fidl.h>
12 #include <zircon/hw/usb.h>
13 
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "fx3.h"
18 
19 #define FLASH_FIRMWARE_PATH  "cyfxflashprog.img"
20 #define TESTER_FIRMWARE_PATH "fx3.img"
21 
22 // The header contains the 2 byte "CY" signature, and 2 byte image metadata.
23 #define IMAGE_HEADER_SIZE 4
24 
25 #define VENDOR_REQ_MAX_SIZE     4096
26 #define VENDOR_REQ_TIMEOUT_SECS 1
27 
28 #define LSW(x) ((x) & 0xffff)
29 #define MSW(x) ((x) >> 16)
30 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
31 
32 typedef struct {
33     zx_device_t* zxdev;
34     usb_protocol_t usb;
35 } fx3_t;
36 
fx3_write(fx3_t * fx3,uint8_t * buf,size_t len,uint32_t addr)37 static zx_status_t fx3_write(fx3_t* fx3, uint8_t* buf, size_t len, uint32_t addr) {
38     if (len > VENDOR_REQ_MAX_SIZE) {
39         return ZX_ERR_INVALID_ARGS;
40     }
41     zx_status_t status;
42     status = usb_control_out(&fx3->usb, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
43                              FX3_REQ_FIRMWARE_TRANSFER, LSW(addr), MSW(addr),
44                              ZX_SEC(VENDOR_REQ_TIMEOUT_SECS), buf, len);
45     if (status != ZX_OK) {
46         return status;
47     }
48     return ZX_OK;
49 }
50 
51 // Jumps to the given address on FX3 System RAM.
fx3_program_entry(fx3_t * fx3,uint32_t ram_addr)52 static zx_status_t fx3_program_entry(fx3_t* fx3, uint32_t ram_addr) {
53     return fx3_write(fx3, NULL, 0, ram_addr);
54 }
55 
fx3_validate_image_header(fx3_t * fx3,zx_handle_t fw_vmo)56 static zx_status_t fx3_validate_image_header(fx3_t* fx3, zx_handle_t fw_vmo) {
57     uint8_t header[IMAGE_HEADER_SIZE];
58     zx_status_t status = zx_vmo_read(fw_vmo, &header, 0, IMAGE_HEADER_SIZE);
59     if (status != ZX_OK) {
60         return status;
61     }
62     if (header[0] != 'C' || header[1] != 'Y') {
63         return ZX_ERR_BAD_STATE;
64     }
65     zxlogf(TRACE, "image header: ctl 0x%02x type 0x%02x\n", header[2], header[3]);
66     return ZX_OK;
67 }
68 
69 // Writes the section data at the given device RAM address.
70 // Returns ZX_OK if successful, and increments checksum with the section checksum.
fx3_write_section(fx3_t * fx3,zx_handle_t fw_vmo,size_t offset,size_t len,uint32_t ram_addr,uint32_t * checksum)71 static zx_status_t fx3_write_section(fx3_t* fx3, zx_handle_t fw_vmo, size_t offset,
72                                      size_t len, uint32_t ram_addr, uint32_t* checksum) {
73     uint8_t write_buf[VENDOR_REQ_MAX_SIZE];
74 
75     while (len > 0) {
76         size_t len_to_write = MIN(len, VENDOR_REQ_MAX_SIZE);
77         ZX_DEBUG_ASSERT(len_to_write % 4 == 0);
78         zx_status_t status = zx_vmo_read(fw_vmo, write_buf, offset, len_to_write);
79         if (status != ZX_OK) {
80             return status;
81         }
82         status = fx3_write(fx3, write_buf, len_to_write, ram_addr);
83         if (status != ZX_OK) {
84             return status;
85         }
86         uint32_t* image_data = (uint32_t*)write_buf;
87         for (uint32_t i = 0; i < len_to_write / 4; ++i) {
88             *checksum += image_data[i];
89         }
90         len -= len_to_write;
91         offset += len_to_write;
92         ram_addr += len_to_write;
93     }
94     return ZX_OK;
95 }
96 
97 // Writes the firmware to the device RAM and boots it.
fx3_load_firmware(fx3_t * fx3,zx_handle_t fw_vmo,size_t fw_size)98 static zx_status_t fx3_load_firmware(fx3_t* fx3, zx_handle_t fw_vmo, size_t fw_size) {
99     size_t vmo_size;
100     zx_status_t status = zx_vmo_get_size(fw_vmo, &vmo_size);
101     if (status != ZX_OK) {
102         zxlogf(ERROR, "failed to get firmware vmo size, err: %d\n", status);
103         return ZX_ERR_INVALID_ARGS;
104     }
105     if (vmo_size < fw_size) {
106         zxlogf(ERROR, "invalid vmo, vmo size was %lu, fw size was %lu\n", vmo_size, fw_size);
107         return ZX_ERR_INVALID_ARGS;
108     }
109     // The fwloader expects the firmware image file to be in the format shown in
110     // EZ-USB/FX3 Boot Options, Table 14.
111     status = fx3_validate_image_header(fx3, fw_vmo);
112     if (status != ZX_OK) {
113         zxlogf(ERROR, "invalid firmware image header, err: %d\n", status);
114         return status;
115     }
116 
117     size_t offset = IMAGE_HEADER_SIZE;
118     uint32_t checksum = 0;
119     // Section header fields.
120     uint32_t len_dwords = 0;
121     uint32_t ram_addr = 0;
122     while (offset < fw_size) {
123         // Read the section header, containing the section length in long words, and ram address.
124         status = zx_vmo_read(fw_vmo, &len_dwords, offset, sizeof(len_dwords));
125         if (status != ZX_OK) {
126             return status;
127         }
128         offset += sizeof(len_dwords);
129         status = zx_vmo_read(fw_vmo, &ram_addr, offset, sizeof(ram_addr));
130         if (status != ZX_OK) {
131             return status;
132         }
133         offset += sizeof(ram_addr);
134         zxlogf(TRACE, "section len %u B ram addr 0x%x\n", len_dwords * 4, ram_addr);
135 
136         if (len_dwords == 0) {
137             // Reached termination of image.
138             break;
139         }
140         status = fx3_write_section(fx3, fw_vmo, offset, len_dwords * 4, ram_addr, &checksum);
141         if (status != ZX_OK) {
142             zxlogf(ERROR, "fx3_write_section failed, err: %d\n", status);
143             return status;
144         }
145         offset += (len_dwords * 4);
146     }
147     if (len_dwords != 0) {
148         // Didn't get termination of image indicator.
149         return ZX_ERR_BAD_STATE;
150     }
151     uint32_t expected_checksum;
152     status = zx_vmo_read(fw_vmo, &expected_checksum, offset, sizeof(expected_checksum));
153     if (status != ZX_OK) {
154         zxlogf(ERROR, "could not read expected checksum, err: %d\n", status);
155         return status;
156     }
157     if (checksum != expected_checksum) {
158         zxlogf(ERROR, "got bad checksum %u, want %u\n", checksum, expected_checksum);
159         return ZX_ERR_BAD_STATE;
160     }
161     status = fx3_program_entry(fx3, ram_addr);
162     if (status == ZX_OK) {
163         return ZX_OK;
164     } else if (status == ZX_ERR_IO_REFUSED) {
165         // When using the second stage bootloader, the control request may send an error code
166         // back after we jump to the program entry.
167         zxlogf(TRACE, "fx3_program_entry got expected err: %d\n", status);
168         return ZX_OK;
169     } else {
170         zxlogf(ERROR, "fx3_program_entry got unexpected err: %d\n", status);
171         return status;
172     }
173 }
174 
fidl_LoadPrebuiltFirmware(void * ctx,zircon_usb_test_fwloader_PrebuiltType type,fidl_txn_t * txn)175 static zx_status_t fidl_LoadPrebuiltFirmware(void* ctx, zircon_usb_test_fwloader_PrebuiltType type,
176                                              fidl_txn_t* txn) {
177     fx3_t* fx3 = ctx;
178 
179     const char* fw_path = NULL;
180     switch (type) {
181     case zircon_usb_test_fwloader_PrebuiltType_FLASH:
182         fw_path = FLASH_FIRMWARE_PATH;
183         break;
184     case zircon_usb_test_fwloader_PrebuiltType_TESTER:
185         fw_path = TESTER_FIRMWARE_PATH;
186         break;
187     default:
188         zxlogf(ERROR, "unsupported firmware type: %u\n", type);
189         return ZX_ERR_NOT_SUPPORTED;
190     }
191 
192     zx_handle_t fw_vmo;
193     size_t fw_size;
194     zx_status_t status = load_firmware(fx3->zxdev, fw_path, &fw_vmo, &fw_size);
195     if (status != ZX_OK) {
196         zxlogf(ERROR, "failed to load firmware at path ""%s"", err: %d\n", fw_path, status);
197         return zircon_usb_test_fwloader_DeviceLoadPrebuiltFirmware_reply(txn, status);
198     }
199     status = fx3_load_firmware(fx3, fw_vmo, fw_size);
200     zx_handle_close(fw_vmo);
201     return zircon_usb_test_fwloader_DeviceLoadPrebuiltFirmware_reply(txn, status);
202 }
203 
fidl_LoadFirmware(void * ctx,const fuchsia_mem_Buffer * firmware,fidl_txn_t * txn)204 static zx_status_t fidl_LoadFirmware(void* ctx, const fuchsia_mem_Buffer* firmware,
205                                      fidl_txn_t* txn) {
206     fx3_t* fx3 = ctx;
207     zx_status_t status = fx3_load_firmware(fx3, firmware->vmo, firmware->size);
208     zx_handle_close(firmware->vmo);
209     return zircon_usb_test_fwloader_DeviceLoadFirmware_reply(txn, status);
210 }
211 
212 static zircon_usb_test_fwloader_Device_ops_t fidl_ops = {
213     .LoadPrebuiltFirmware = fidl_LoadPrebuiltFirmware,
214     .LoadFirmware = fidl_LoadFirmware,
215 };
216 
fx3_message(void * ctx,fidl_msg_t * msg,fidl_txn_t * txn)217 static zx_status_t fx3_message(void* ctx, fidl_msg_t* msg, fidl_txn_t* txn) {
218     return zircon_usb_test_fwloader_Device_dispatch(ctx, txn, msg, &fidl_ops);
219 }
220 
fx3_free(fx3_t * ctx)221 static void fx3_free(fx3_t* ctx) {
222     free(ctx);
223 }
224 
fx3_unbind(void * ctx)225 static void fx3_unbind(void* ctx) {
226     zxlogf(INFO, "fx3_unbind\n");
227     fx3_t* fx3 = ctx;
228 
229     device_remove(fx3->zxdev);
230 }
231 
fx3_release(void * ctx)232 static void fx3_release(void* ctx) {
233     fx3_t* fx3 = ctx;
234     fx3_free(fx3);
235 }
236 
237 static zx_protocol_device_t fx3_device_protocol = {
238     .version = DEVICE_OPS_VERSION,
239     .message = fx3_message,
240     .unbind = fx3_unbind,
241     .release = fx3_release,
242 };
243 
fx3_bind(void * ctx,zx_device_t * device)244 static zx_status_t fx3_bind(void* ctx, zx_device_t* device) {
245     zxlogf(TRACE, "fx3_bind\n");
246 
247     fx3_t* fx3 = calloc(1, sizeof(fx3_t));
248     if (!fx3) {
249         return ZX_ERR_NO_MEMORY;
250     }
251     zx_status_t result = device_get_protocol(device, ZX_PROTOCOL_USB, &fx3->usb);
252     if (result != ZX_OK) {
253         fx3_free(fx3);
254         return result;
255     }
256 
257     device_add_args_t args = {
258         .version = DEVICE_ADD_ARGS_VERSION,
259         .name = "fx3",
260         .ctx = fx3,
261         .ops = &fx3_device_protocol,
262         .flags = DEVICE_ADD_NON_BINDABLE,
263         .proto_id = ZX_PROTOCOL_USB_TEST_FWLOADER,
264     };
265 
266     zx_status_t status = device_add(device, &args, &fx3->zxdev);
267     if (status != ZX_OK) {
268         fx3_free(fx3);
269         return status;
270     }
271     return ZX_OK;
272 }
273 
274 static zx_driver_ops_t fx3_driver_ops = {
275     .version = DRIVER_OPS_VERSION,
276     .bind = fx3_bind,
277 };
278 
279 ZIRCON_DRIVER_BEGIN(fx3, fx3_driver_ops, "zircon", "0.1", 4)
280     BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB),
281     BI_ABORT_IF(NE, BIND_USB_VID, CYPRESS_VID),
282     BI_MATCH_IF(EQ, BIND_USB_PID, FX3_DEFAULT_BOOTLOADER_PID),
283     BI_MATCH_IF(EQ, BIND_USB_PID, FX3_SECOND_STAGE_BOOTLOADER_PID),
284 ZIRCON_DRIVER_END(fx3)
285