Add support extract boot loader from wic image
[mfgtools.git] / libuuu / sdp.cpp
blob82513a1959ceabc3246b8b372fda579e130dec9b
1 /*
2 * Copyright 2018 NXP.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
32 #include <string>
33 #include "sdps.h"
34 #include "hidreport.h"
35 #include "liberror.h"
36 #include "libcomm.h"
37 #include "buffer.h"
38 #include "sdp.h"
39 #include "rominfo.h"
40 #include "libusb.h"
41 #include "trans.h"
43 #include <cstring>
45 int SDPCmdBase::check_ack(HIDReport *report, uint32_t ack)
47 if (get_hab_type(report) == HabUnknown)
48 return -1;
50 uint32_t status;
51 if (get_status(report, status, 4))
52 return -1;
54 if (ack != status)
56 set_last_err_string("Status Miss matched");
57 return -1;
59 return 0;
62 SDPCmdBase::HAB_t SDPCmdBase::get_hab_type(HIDReport *report)
64 uint32_t status;
65 if (get_status(report, status, 3))
66 return HabUnknown;
68 if (status == HabEnabled)
69 return HabEnabled;
71 if (status == HabDisabled)
72 return HabDisabled;
74 set_last_err_string("unknown hab type");
75 return HabUnknown;
78 int SDPCmdBase::get_status(HIDReport *p, uint32_t &status, uint8_t report_id)
80 m_input.resize(1025);
81 m_input[0] = report_id;
82 int ret = p->read(m_input);
83 if (ret < 0)
84 return -1;
86 if (m_input.size() < (1 + sizeof(uint32_t)))
88 set_last_err_string("HID report size is too small");
89 return -1;
92 status = *(uint32_t*)(m_input.data() + 1);
93 return 0;
96 int SDPCmdBase::init_cmd()
98 memset(&m_spdcmd, 0, sizeof(m_spdcmd)); return 0;
101 IvtHeader *SDPCmdBase::search_ivt_header(shared_ptr<FileBuffer> data, size_t &off, size_t limit)
103 if (limit >= data->m_avaible_size)
104 limit = data->m_avaible_size;
106 for (; off < limit; off += 0x4)
108 IvtHeader *p = (IvtHeader*)(data->data() + off);
109 if (p->IvtBarker == IVT_BARKER_HEADER)
110 return p;
111 if (p->IvtBarker == IVT_BARKER2_HEADER)
113 BootData *pDB = (BootData *) &(data->at(off + p->BootData - p->SelfAddr));
115 /*Skip HDMI firmware for i.MX8MQ*/
116 if (pDB->PluginFlag & 0xFFFFFFFE)
117 continue;
118 return p;
121 off = -1;
122 return nullptr;
125 int SDPCmdBase::send_cmd(HIDReport *p)
127 return p->write(&m_spdcmd, sizeof(m_spdcmd), 1);
130 SDPDcdCmd::SDPDcdCmd(char *p) : SDPCmdBase(p)
132 insert_param_info("dcd", nullptr, Param::Type::e_null);
133 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
134 insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32);
135 m_dcd_addr = 0;
138 int SDPDcdCmd::run(CmdCtx*ctx)
140 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
141 if (rom == nullptr)
143 string_ex err;
144 err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__);
145 set_last_err_string(err);
146 return -1;
148 init_cmd();
150 shared_ptr<FileBuffer> buff = get_file_buffer(m_filename, false);
152 buff->request_data(WIC_BOOTPART_SIZE);
154 size_t off = 0;
155 IvtHeader *pIVT = search_ivt_header(buff, off);
156 if (pIVT == nullptr)
158 return 0;
161 if (pIVT->DCDAddress == 0)
162 return 0;
164 uint8_t * pdcd = &(buff->at(off + pIVT->DCDAddress - pIVT->SelfAddr));
166 if (pdcd[0] != HAB_TAG_DCD)
168 string_ex err;
169 err.format("%s:%d DCD TAG miss matched", __FUNCTION__, __LINE__);
170 set_last_err_string(err);
171 return -1;
174 uint32_t size = (pdcd[1] << 8) | pdcd[2];
176 buff->request_data(off + size);
178 m_spdcmd.m_cmd = ROM_KERNEL_CMD_DCD_WRITE;
179 m_spdcmd.m_addr = EndianSwap(m_dcd_addr ? m_dcd_addr : rom->free_addr);
180 m_spdcmd.m_count = EndianSwap(size);
182 HIDTrans dev;
183 if (dev.open(ctx->m_dev))
184 return -1;
186 HIDReport report(&dev);
187 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
188 return -1;
190 if (report.write(pdcd, size, 2))
191 return -1;
193 if (check_ack(&report, ROM_WRITE_ACK))
194 return -1;
196 return 0;
199 SDPSkipDCDCmd::SDPSkipDCDCmd(char *p) : SDPCmdBase(p)
201 m_spdcmd.m_cmd = ROM_KERNEL_CMD_SKIP_DCD_HEADER;
204 int SDPSkipDCDCmd::run(CmdCtx*ctx)
206 HIDTrans dev;
207 if (dev.open(ctx->m_dev))
208 return -1;
210 HIDReport report(&dev);
211 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
212 return -1;
214 if (check_ack(&report, ROM_OK_ACK))
215 return -1;
217 return 0;
220 SDPBootCmd::SDPBootCmd(char *p) : SDPCmdBase(p)
222 insert_param_info("boot", nullptr, Param::Type::e_null);
223 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
224 insert_param_info("-nojump", &m_nojump, Param::Type::e_bool);
225 insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool);
226 insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32);
229 int SDPBootCmd::run(CmdCtx *ctx)
231 string str;
232 str = "SDP: dcd -f ";
233 str += m_filename;
234 if (m_dcd_addr) {
235 str += " -dcdaddr ";
236 str += std::to_string(m_dcd_addr);
238 SDPDcdCmd dcd((char *)str.c_str());
239 if (dcd.parser()) return -1;
240 if (dcd.run(ctx)) return -1;
242 str = "SDP: write -f ";
243 str += m_filename;
244 str += " -ivt 0";
245 SDPWriteCmd wr((char *)str.c_str());
246 if (wr.parser()) return -1;
247 if (wr.run(ctx)) return -1;
249 str = "SDP: jump -f ";
250 str += m_filename;
251 str += " -ivt 0";
252 if (m_clear_dcd)
253 str += " -cleardcd";
255 SDPJumpCmd jmp((char *)str.c_str());
256 if (!m_nojump)
258 if (jmp.parser()) return -1;
259 if (jmp.run(ctx)) return -1;
262 SDPBootlogCmd log(nullptr);
263 log.run(ctx);
265 return 0;
268 SDPStatusCmd::SDPStatusCmd(char *p) : SDPCmdBase(p)
270 m_spdcmd.m_cmd = ROM_KERNEL_CMD_ERROR_STATUS;
271 insert_param_info("status", nullptr, Param::Type::e_null);
274 int SDPStatusCmd::run(CmdCtx *ctx)
276 HIDTrans dev;
277 if (dev.open(ctx->m_dev))
278 return -1;
280 HIDReport report(&dev);
281 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
282 return -1;
284 if (get_hab_type(&report) == HabUnknown)
285 return -1;
287 uint32_t status;
288 if (get_status(&report, status, 4))
289 return -1;
291 return 0;
294 SDPWriteCmd::SDPWriteCmd(char *p) : SDPCmdBase(p)
296 m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_FILE;
297 m_PlugIn = -1;
298 m_Ivt = -1;
299 m_max_download_pre_cmd = 0x200000;
300 m_offset = 0;
301 m_bIvtReserve = false;
302 m_download_addr = 0;
303 m_bskipspl = false;
304 m_bscanterm = false;
306 insert_param_info("write", nullptr, Param::Type::e_null);
307 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
308 insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32);
309 insert_param_info("-addr", &m_download_addr, Param::Type::e_uint32);
310 insert_param_info("-offset", &m_offset, Param::Type::e_uint32);
311 insert_param_info("-skipspl", &m_bskipspl, Param::Type::e_bool);
312 insert_param_info("-skipfhdr", &m_bskipfhdr, Param::Type::e_bool);
313 insert_param_info("-scanterm", &m_bscanterm, Param::Type::e_bool);
316 int SDPWriteCmd::run(CmdCtx*ctx)
318 size_t size;
319 uint8_t *pbuff;
320 int offset = 0;
322 shared_ptr<FileBuffer> fbuff = get_file_buffer(m_filename, false);
324 if (fbuff == nullptr)
325 return -1;
327 fbuff->request_data(WIC_BOOTPART_SIZE);
329 if (m_Ivt < 0)
331 pbuff = fbuff->data();
332 size = fbuff->size();
334 offset = m_offset;
336 if (m_bskipfhdr)
337 offset += GetFlashHeaderSize(fbuff, offset);
339 size_t pos = 0, length;
340 if (m_bscanterm)
342 if (IsMBR(fbuff))
344 length = ScanTerm(fbuff, pos);
345 if (length == 0)
347 set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto");
348 return -1;
351 offset = pos - length;
352 if (offset < 0)
354 set_last_err_string("This wic boot length is wrong");
355 return -1;
357 size = pos;
361 if (m_bskipspl) {
362 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
363 if(! (rom->flags & ROM_INFO_AUTO_SCAN_UBOOT_POS))
365 set_last_err_string("SPL doesn't support auto scan uboot position");
366 return -1;
369 size_t off = offset;
370 IvtHeader *pIvt = search_ivt_header(fbuff, off, 0x100000);
371 if (pIvt)
373 BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr));
374 offset = off + pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr);
376 else
378 offset += GetContainerActualSize(fbuff, offset);
381 fbuff->request_data(offset);
383 if (offset >= fbuff->m_avaible_size)
385 set_last_err_string("Unknown Image type, can't use skipspl format");
386 return -1;
390 size -= offset;
392 else
394 size_t off = 0;
395 IvtHeader *pIvt = search_ivt_header(fbuff, off);
396 for (int i = 0; i < m_Ivt; i++)
398 off += sizeof(IvtHeader);
399 pIvt = search_ivt_header(fbuff, off);
401 if (pIvt == nullptr)
403 set_last_err_string("Cannot find valid IVT header");
404 return -1;
407 BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr));
409 m_download_addr = pIvt->SelfAddr;
410 //size = fbuff->size() - off;
411 size = pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr);
413 fbuff->request_data(size);
415 //ImageSize may be bigger than Imagesize because ImageSize include IVT offset
416 //Difference boot storage have difference IVT offset.
417 if (size > fbuff->size() - off)
418 size = fbuff->size() - off;
420 pbuff = (uint8_t*)pIvt;
422 return run(ctx, pbuff + offset, size, m_download_addr);
425 int SDPWriteCmd::run(CmdCtx *ctx, void *pbuff, size_t size, uint32_t addr)
427 HIDTrans dev;
428 if (dev.open(ctx->m_dev))
429 return -1;
431 HIDReport report(&dev);
433 report.set_notify_total(size);
435 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
437 size_t max = m_max_download_pre_cmd;
439 /* SPL needn't split transfer */
440 if (rom && (rom ->flags & ROM_INFO_HID_SDP_NO_MAX_PER_TRANS))
441 max = size;
443 for (size_t i=0; i < size; i += max)
445 size_t sz;
446 sz = size - i;
447 if (sz > max)
448 sz = max;
450 m_spdcmd.m_addr = EndianSwap((uint32_t)(addr + i)); // force use 32bit endian swap function;
451 m_spdcmd.m_count = EndianSwap((uint32_t)sz); //force use 32bit endian swap function;
453 report.set_position_base(i);
454 report.set_skip_notify(true);
456 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
457 return -1;
459 report.set_skip_notify(false);
461 if (report.write(((uint8_t*)pbuff)+i, sz, 2))
462 return -1;
464 if (check_ack(&report, ROM_STATUS_ACK))
465 return -1;
468 return 0;
471 SDPReadMemCmd::SDPReadMemCmd(char *p) : SDPCmdBase(p)
473 m_spdcmd.m_cmd = ROM_KERNEL_CMD_RD_MEM;
475 insert_param_info("rdmem", nullptr, Param::Type::e_null);
476 insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32);
477 insert_param_info("-format", &m_mem_format, Param::Type::e_uint32);
480 int SDPReadMemCmd::run(CmdCtx *ctx)
482 HIDTrans dev;
483 if (dev.open(ctx->m_dev))
484 return -1;
486 HIDReport report(&dev);
488 printf("\nReading address 0x%08X ...\n", m_mem_addr);
489 m_spdcmd.m_addr = EndianSwap(m_mem_addr);
490 m_spdcmd.m_format = m_mem_format;
491 switch (m_mem_format) {
492 case 0x8:
493 m_spdcmd.m_count = EndianSwap((uint32_t)0x1);
494 break;
495 case 0x10:
496 m_spdcmd.m_count = EndianSwap((uint32_t)0x2);
497 break;
498 case 0x20:
499 m_spdcmd.m_count = EndianSwap((uint32_t)0x4);
500 break;
501 default:
502 set_last_err_string("Invalid format, use <8|16|32>");
503 return -1;
504 break;
507 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
508 return -1;
510 if (get_hab_type(&report) == HabUnknown)
511 return -1;
513 uint32_t mem_value;
514 if (get_status(&report, mem_value, 4) == 0)
516 printf("\nValue of address 0x%08X: ", m_mem_addr);
517 switch (m_mem_format) {
518 case 0x8:
519 printf("0x%02X\n", mem_value & 0xff);
520 break;
521 case 0x10:
522 printf("0x%04X\n", mem_value & 0xffff);
523 break;
524 case 0x20:
525 printf("0x%08X\n", mem_value);
526 break;
527 default:
528 set_last_err_string("Invalid format, use <8|16|32>");
529 return -1;
533 return 0;
536 SDPWriteMemCmd::SDPWriteMemCmd(char *p) : SDPCmdBase(p)
538 m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_MEM;
540 insert_param_info("wrmem", nullptr, Param::Type::e_null);
541 insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32);
542 insert_param_info("-format", &m_mem_format, Param::Type::e_uint32);
543 insert_param_info("-value", &m_mem_value, Param::Type::e_uint32);
546 int SDPWriteMemCmd::run(CmdCtx *ctx)
548 HIDTrans dev;
549 if (dev.open(ctx->m_dev))
550 return -1;
552 HIDReport report(&dev);
554 printf("\nWriting 0x%08X to address 0x%08X ...\n", m_mem_value, m_mem_addr);
555 m_spdcmd.m_addr = EndianSwap(m_mem_addr);
556 m_spdcmd.m_format = m_mem_format;
557 switch (m_mem_format) {
558 case 0x8:
559 m_spdcmd.m_count = EndianSwap((uint32_t)0x1);
560 break;
561 case 0x10:
562 m_spdcmd.m_count = EndianSwap((uint32_t)0x2);
563 break;
564 case 0x20:
565 m_spdcmd.m_count = EndianSwap((uint32_t)0x4);
566 break;
567 default:
568 set_last_err_string("Invalid format, use <8|16|32>");
569 return -1;
570 break;
572 m_spdcmd.m_data = EndianSwap(m_mem_value);
574 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
575 return -1;
577 if (get_hab_type(&report) == HabUnknown)
578 return -1;
580 uint32_t status;
582 if (get_status(&report, status, 4) < 0 || status != ROM_WRITE_ACK) {
584 string_ex err;
585 err.format("%s:%d Failed to write to address 0x%X",
586 __FUNCTION__, __LINE__, m_mem_addr);
587 set_last_err_string(err);
590 return 0;
593 SDPJumpCmd::SDPJumpCmd(char *p) : SDPCmdBase(p)
595 m_spdcmd.m_cmd = ROM_KERNEL_CMD_JUMP_ADDR;
596 insert_param_info("jump", nullptr, Param::Type::e_null);
597 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
598 insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32);
599 insert_param_info("-plugin", &m_PlugIn, Param::Type::e_bool);
600 insert_param_info("-addr", &m_jump_addr, Param::Type::e_uint32);
601 insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool);
604 int SDPJumpCmd::run(CmdCtx *ctx)
606 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
608 HIDTrans dev;
609 if (dev.open(ctx->m_dev))
610 return -1;
612 HIDReport report(&dev);
614 if (rom == nullptr)
616 string_ex err;
617 err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__);
618 set_last_err_string(err);
619 return -1;
622 if (rom->flags & ROM_INFO_SPL_JUMP)
624 m_spdcmd.m_addr = EndianSwap(m_jump_addr);
625 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
626 return -1;
628 //Omit last return value.
629 check_ack(&report, ROM_OK_ACK);
630 return 0;
633 shared_ptr<FileBuffer> buff = get_file_buffer(m_filename, false);
635 buff->request_data(WIC_BOOTPART_SIZE);
637 size_t off = 0;
638 IvtHeader *pIVT = search_ivt_header(buff, off, WIC_BOOTPART_SIZE);
640 for (int i = 0; i < m_Ivt; i++)
642 off += sizeof(IvtHeader);
643 pIVT = search_ivt_header(buff, off);
646 if (pIVT == nullptr)
648 set_last_err_string("Cannot find valid IVT header");
649 return -1;
652 m_spdcmd.m_addr = EndianSwap(pIVT->SelfAddr);
655 if (rom->flags & ROM_INFO_HID_SKIP_DCD && !m_clear_dcd)
657 SDPSkipDCDCmd skipcmd(nullptr);
658 if (skipcmd.run(ctx))
659 return -1;
661 else
662 { /*Clear DCD*/
663 vector<uint8_t> ivt;
664 /* Need send out whole report size buffer avoid overwrite other data
665 * Some platform require receive whole package for report id = 2
667 ivt.resize(report.get_out_package_size());
669 size_t sz = buff->size();
670 sz -= (uint8_t*)pIVT - (uint8_t*)buff->data();
672 if (sz > ivt.size())
673 sz = ivt.size();
675 memcpy(ivt.data(), pIVT, sz);
677 IvtHeader *header = (IvtHeader *)ivt.data();
678 header->DCDAddress = 0;
680 SDPWriteCmd writecmd(nullptr);
681 if(writecmd.run(ctx, header, ivt.size(), pIVT->SelfAddr))
682 return -1;
685 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
686 return -1;
688 //Omit last return value.
689 check_ack(&report, ROM_OK_ACK);
691 return 0;
694 SDPBootlogCmd::SDPBootlogCmd(char *p) : SDPCmdBase(p)
696 insert_param_info("blog", nullptr, Param::Type::e_null);
699 int SDPBootlogCmd::run(CmdCtx *ctx)
701 HIDTrans dev{2000};
703 if (dev.open(ctx->m_dev))
704 return -1;
706 HIDReport report(&dev);
708 vector<uint8_t> v(65);
709 v[0] = 'I';
711 uuu_notify nt;
712 nt.type = uuu_notify::NOTIFY_CMD_INFO;
714 int ret;
715 while (1)
717 ret = report.read(v);
718 if (ret)
719 return 0;
720 else
722 nt.str = (char*)(v.data() + 4);
723 v[5] = 0;
724 call_notify(nt);
725 continue;
728 return 0;