libuuu: sdp: SDPWriteCmd: allow to skip check_ack
[mfgtools.git] / libuuu / sdp.cpp
blobdf32c2bfcfe7f34fb8e5cbbe3f471f486d102a68
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));
99 insert_param_info("-scanlimited", &m_scan_limited, Param::Type::e_uint64);
100 return 0;
103 IvtHeader *SDPCmdBase::search_ivt_header(shared_ptr<DataBuffer> data, size_t &off, size_t limit)
105 if (limit >= data->size())
106 limit = data->size();
108 for (; off < limit; off += 0x4)
110 IvtHeader *p = (IvtHeader*)(data->data() + off);
111 if (p->IvtBarker == IVT_BARKER_HEADER)
112 return p;
113 if (p->IvtBarker == IVT_BARKER2_HEADER)
115 BootData *pDB = (BootData *) &(data->at(off + p->BootData - p->SelfAddr));
117 /*Skip HDMI firmware for i.MX8MQ*/
118 if (pDB->PluginFlag & 0xFFFFFFFE)
119 continue;
120 return p;
123 off = -1;
124 return nullptr;
127 int SDPCmdBase::send_cmd(HIDReport *p)
129 return p->write(&m_spdcmd, sizeof(m_spdcmd), 1);
132 SDPDcdCmd::SDPDcdCmd(char *p) : SDPCmdBase(p)
134 insert_param_info("dcd", nullptr, Param::Type::e_null);
135 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
136 insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32);
137 m_dcd_addr = 0;
140 int SDPDcdCmd::run(CmdCtx*ctx)
142 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
143 if (rom == nullptr)
145 string_ex err;
146 err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__);
147 set_last_err_string(err);
148 return -1;
150 init_cmd();
152 shared_ptr<FileBuffer> p = get_file_buffer(m_filename, true);
154 if (!p)
155 return -1;
157 shared_ptr<DataBuffer> buff;
158 buff = p->request_data(0, m_scan_limited);
159 if (!buff) return -1;
161 size_t off = 0;
162 IvtHeader *pIVT = search_ivt_header(buff, off);
163 if (pIVT == nullptr)
165 return 0;
168 if (pIVT->DCDAddress == 0)
169 return 0;
171 uint8_t * pdcd = &(buff->at(off + pIVT->DCDAddress - pIVT->SelfAddr));
173 if (pdcd[0] != HAB_TAG_DCD)
175 string_ex err;
176 err.format("%s:%d DCD TAG miss matched", __FUNCTION__, __LINE__);
177 set_last_err_string(err);
178 return -1;
181 uint32_t size = (pdcd[1] << 8) | pdcd[2];
183 if (size >= m_scan_limited)
185 set_last_err_string("dcd bigger than 8M");
186 return -1;
189 // point maybe change after new requisition buffer.
190 pdcd = &(buff->at(off + pIVT->DCDAddress - pIVT->SelfAddr));
192 m_spdcmd.m_cmd = ROM_KERNEL_CMD_DCD_WRITE;
193 m_spdcmd.m_addr = EndianSwap(m_dcd_addr ? m_dcd_addr : rom->free_addr);
194 m_spdcmd.m_count = EndianSwap(size);
196 HIDTrans dev(m_timeout);
197 if (dev.open(ctx->m_dev))
198 return -1;
200 HIDReport report(&dev);
201 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
202 return -1;
204 if (report.write(pdcd, size, 2))
205 return -1;
207 if (check_ack(&report, ROM_WRITE_ACK))
208 return -1;
210 return 0;
213 SDPSkipDCDCmd::SDPSkipDCDCmd(char *p) : SDPCmdBase(p)
215 m_spdcmd.m_cmd = ROM_KERNEL_CMD_SKIP_DCD_HEADER;
218 int SDPSkipDCDCmd::run(CmdCtx*ctx)
220 HIDTrans dev(m_timeout);
221 if (dev.open(ctx->m_dev))
222 return -1;
224 HIDReport report(&dev);
225 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
226 return -1;
228 if (check_ack(&report, ROM_OK_ACK))
229 return -1;
231 return 0;
234 SDPBootCmd::SDPBootCmd(char *p) : SDPCmdBase(p)
236 insert_param_info("boot", nullptr, Param::Type::e_null);
237 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
238 insert_param_info("-nojump", &m_nojump, Param::Type::e_bool);
239 insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool);
240 insert_param_info("-dcdaddr", &m_dcd_addr, Param::Type::e_uint32);
241 insert_param_info("-scanlimited", &m_scan_limited, Param::Type::e_uint64);
244 int SDPBootCmd::run(CmdCtx *ctx)
246 string str;
247 str = "SDP: dcd -f ";
248 str += m_filename;
249 if (m_dcd_addr) {
250 str += " -dcdaddr ";
251 str += std::to_string(m_dcd_addr);
254 if (m_scan_limited != UINT64_MAX)
256 str += " -scanlimited ";
257 str += std::to_string(m_scan_limited);
260 SDPDcdCmd dcd((char *)str.c_str());
262 if (m_scan_limited != UINT64_MAX)
264 str += " -scanlimited ";
265 str += std::to_string(m_scan_limited);
268 if (dcd.parser()) return -1;
269 if (dcd.run(ctx)) return -1;
271 str = "SDP: write -f ";
272 str += m_filename;
273 str += " -ivt 0";
275 if (m_scan_limited != UINT64_MAX)
277 str += " -scanlimited ";
278 str += std::to_string(m_scan_limited);
281 SDPWriteCmd wr((char *)str.c_str());
282 if (wr.parser()) return -1;
283 if (wr.run(ctx)) return -1;
285 str = "SDP: jump -f ";
286 str += m_filename;
287 str += " -ivt 0";
288 if (m_clear_dcd)
289 str += " -cleardcd";
291 if (m_scan_limited != UINT64_MAX)
293 str += " -scanlimited ";
294 str += std::to_string(m_scan_limited);
297 SDPJumpCmd jmp((char *)str.c_str());
298 if (!m_nojump)
300 if (jmp.parser()) return -1;
301 if (jmp.run(ctx)) return -1;
304 SDPBootlogCmd log(nullptr);
305 log.run(ctx);
307 return 0;
310 SDPStatusCmd::SDPStatusCmd(char *p) : SDPCmdBase(p)
312 m_spdcmd.m_cmd = ROM_KERNEL_CMD_ERROR_STATUS;
313 insert_param_info("status", nullptr, Param::Type::e_null);
316 int SDPStatusCmd::run(CmdCtx *ctx)
318 HIDTrans dev(m_timeout);
319 if (dev.open(ctx->m_dev))
320 return -1;
322 HIDReport report(&dev);
323 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
324 return -1;
326 if (get_hab_type(&report) == HabUnknown)
327 return -1;
329 uint32_t status;
330 if (get_status(&report, status, 4))
331 return -1;
333 return 0;
336 SDPWriteCmd::SDPWriteCmd(char *p) : SDPCmdBase(p)
338 m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_FILE;
339 m_PlugIn = -1;
340 m_Ivt = -1;
341 m_max_download_pre_cmd = 0x200000;
342 m_offset = 0;
343 m_bIvtReserve = false;
344 m_download_addr = 0;
345 m_bskipspl = false;
346 m_bscanterm = false;
348 insert_param_info("write", nullptr, Param::Type::e_null);
349 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
350 insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32);
351 insert_param_info("-addr", &m_download_addr, Param::Type::e_uint32);
352 insert_param_info("-offset", &m_offset, Param::Type::e_uint32);
353 insert_param_info("-skipspl", &m_bskipspl, Param::Type::e_bool);
354 insert_param_info("-skipfhdr", &m_bskipfhdr, Param::Type::e_bool);
355 insert_param_info("-scanterm", &m_bscanterm, Param::Type::e_bool);
358 int SDPWriteCmd::run(CmdCtx*ctx)
360 size_t size;
361 uint8_t *pbuff;
362 ssize_t offset = 0;
364 shared_ptr<FileBuffer> p1= get_file_buffer(m_filename, true);
366 if (p1 == nullptr)
367 return -1;
369 shared_ptr<DataBuffer> fbuff;
371 fbuff = p1->request_data(0, m_scan_limited);
372 if (!fbuff) return -1;
374 if (m_Ivt < 0)
376 pbuff = fbuff->data();
377 size = fbuff->size();
379 offset = m_offset;
381 if (m_bskipfhdr)
382 offset += GetFlashHeaderSize(fbuff, offset);
384 size_t pos = 0, length;
385 if (m_bscanterm)
387 if (IsMBR(fbuff))
389 length = ScanTerm(fbuff, pos);
390 if (length == 0)
392 set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto");
393 return -1;
396 offset = pos - length;
397 if (offset < 0)
399 set_last_err_string("This wic boot length is wrong");
400 return -1;
402 size = pos;
406 if (m_bskipspl) {
407 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
408 if(! (rom->flags & ROM_INFO_AUTO_SCAN_UBOOT_POS))
410 set_last_err_string("SPL doesn't support auto scan uboot position");
411 return -1;
414 size_t off = offset;
415 IvtHeader *pIvt = search_ivt_header(fbuff, off, 0x100000);
416 if (pIvt)
418 if (pIvt->BootData)
420 BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr));
421 offset = off + pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr);
424 else
426 offset += GetContainerActualSize(fbuff, offset);
429 if (size_t(offset) >= fbuff->size())
431 set_last_err_string("Unknown Image type, can't use skipspl format");
432 return -1;
436 size -= offset;
438 else
440 size_t off = 0;
441 IvtHeader *pIvt = search_ivt_header(fbuff, off);
442 for (int i = 0; i < m_Ivt; i++)
444 off += sizeof(IvtHeader);
445 pIvt = search_ivt_header(fbuff, off, m_scan_limited);
447 if (pIvt == nullptr)
449 set_last_err_string("Cannot find valid IVT header");
450 return -1;
453 BootData *pDB = (BootData *) &(fbuff->at(off + pIvt->BootData - pIvt->SelfAddr));
455 m_download_addr = pIvt->SelfAddr;
456 //size = fbuff->size() - off;
457 size = pDB->ImageSize - (pIvt->SelfAddr - pDB->ImageStartAddr);
459 if (size >= m_scan_limited)
461 set_last_err_string("TODO: image is too big");
462 return -1;
465 //ImageSize may be bigger than Imagesize because ImageSize include IVT offset
466 //Difference boot storage have difference IVT offset.
467 if (size > fbuff->size() - off)
468 size = fbuff->size() - off;
470 pbuff = (uint8_t*)pIvt;
472 return run(ctx, pbuff + offset, size, m_download_addr);
475 int SDPWriteCmd::run(CmdCtx *ctx, void *pbuff, size_t size, uint32_t addr, bool validate)
477 HIDTrans dev(m_timeout);
478 if (dev.open(ctx->m_dev))
479 return -1;
481 HIDReport report(&dev);
483 report.set_notify_total(size);
485 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
487 size_t max = m_max_download_pre_cmd;
489 /* SPL needn't split transfer */
490 if (rom && (rom ->flags & ROM_INFO_HID_SDP_NO_MAX_PER_TRANS))
491 max = size;
493 for (size_t i=0; i < size; i += max)
495 size_t sz;
496 sz = size - i;
497 if (sz > max)
498 sz = max;
500 m_spdcmd.m_addr = EndianSwap((uint32_t)(addr + i)); // force use 32bit endian swap function;
501 m_spdcmd.m_count = EndianSwap((uint32_t)sz); //force use 32bit endian swap function;
503 report.set_position_base(i);
504 report.set_skip_notify(true);
506 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
507 return -1;
509 report.set_skip_notify(false);
511 if (report.write(((uint8_t*)pbuff)+i, sz, 2))
512 return -1;
514 if (validate && check_ack(&report, ROM_STATUS_ACK))
515 return -1;
518 return 0;
521 SDPReadMemCmd::SDPReadMemCmd(char *p) : SDPCmdBase(p)
523 m_spdcmd.m_cmd = ROM_KERNEL_CMD_RD_MEM;
525 insert_param_info("rdmem", nullptr, Param::Type::e_null);
526 insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32);
527 insert_param_info("-format", &m_mem_format, Param::Type::e_uint32);
530 int SDPReadMemCmd::run(CmdCtx *ctx)
532 HIDTrans dev(m_timeout);
533 if (dev.open(ctx->m_dev))
534 return -1;
536 HIDReport report(&dev);
538 printf("\nReading address 0x%08X ...\n", m_mem_addr);
539 m_spdcmd.m_addr = EndianSwap(m_mem_addr);
540 m_spdcmd.m_format = m_mem_format;
541 switch (m_mem_format) {
542 case 0x8:
543 m_spdcmd.m_count = EndianSwap((uint32_t)0x1);
544 break;
545 case 0x10:
546 m_spdcmd.m_count = EndianSwap((uint32_t)0x2);
547 break;
548 case 0x20:
549 m_spdcmd.m_count = EndianSwap((uint32_t)0x4);
550 break;
551 default:
552 set_last_err_string("Invalid format, use <8|16|32>");
553 return -1;
554 break;
557 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
558 return -1;
560 if (get_hab_type(&report) == HabUnknown)
561 return -1;
563 uint32_t mem_value;
564 if (get_status(&report, mem_value, 4) == 0)
566 printf("\nValue of address 0x%08X: ", m_mem_addr);
567 switch (m_mem_format) {
568 case 0x8:
569 printf("0x%02X\n", mem_value & 0xff);
570 break;
571 case 0x10:
572 printf("0x%04X\n", mem_value & 0xffff);
573 break;
574 case 0x20:
575 printf("0x%08X\n", mem_value);
576 break;
577 default:
578 set_last_err_string("Invalid format, use <8|16|32>");
579 return -1;
583 return 0;
586 SDPWriteMemCmd::SDPWriteMemCmd(char *p) : SDPCmdBase(p)
588 m_spdcmd.m_cmd = ROM_KERNEL_CMD_WR_MEM;
590 insert_param_info("wrmem", nullptr, Param::Type::e_null);
591 insert_param_info("-addr", &m_mem_addr, Param::Type::e_uint32);
592 insert_param_info("-format", &m_mem_format, Param::Type::e_uint32);
593 insert_param_info("-value", &m_mem_value, Param::Type::e_uint32);
596 int SDPWriteMemCmd::run(CmdCtx *ctx)
598 HIDTrans dev(m_timeout);
599 if (dev.open(ctx->m_dev))
600 return -1;
602 HIDReport report(&dev);
604 printf("\nWriting 0x%08X to address 0x%08X ...\n", m_mem_value, m_mem_addr);
605 m_spdcmd.m_addr = EndianSwap(m_mem_addr);
606 m_spdcmd.m_format = m_mem_format;
607 switch (m_mem_format) {
608 case 0x8:
609 m_spdcmd.m_count = EndianSwap((uint32_t)0x1);
610 break;
611 case 0x10:
612 m_spdcmd.m_count = EndianSwap((uint32_t)0x2);
613 break;
614 case 0x20:
615 m_spdcmd.m_count = EndianSwap((uint32_t)0x4);
616 break;
617 default:
618 set_last_err_string("Invalid format, use <8|16|32>");
619 return -1;
620 break;
622 m_spdcmd.m_data = EndianSwap(m_mem_value);
624 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
625 return -1;
627 if (get_hab_type(&report) == HabUnknown)
628 return -1;
630 uint32_t status;
632 if (get_status(&report, status, 4) < 0 || status != ROM_WRITE_ACK) {
634 string_ex err;
635 err.format("%s:%d Failed to write to address 0x%X",
636 __FUNCTION__, __LINE__, m_mem_addr);
637 set_last_err_string(err);
640 return 0;
643 SDPJumpCmd::SDPJumpCmd(char *p) : SDPCmdBase(p)
645 m_spdcmd.m_cmd = ROM_KERNEL_CMD_JUMP_ADDR;
646 insert_param_info("jump", nullptr, Param::Type::e_null);
647 insert_param_info("-f", &m_filename, Param::Type::e_string_filename);
648 insert_param_info("-ivt", &m_Ivt, Param::Type::e_uint32);
649 insert_param_info("-plugin", &m_PlugIn, Param::Type::e_bool);
650 insert_param_info("-addr", &m_jump_addr, Param::Type::e_uint32);
651 insert_param_info("-cleardcd", &m_clear_dcd, Param::Type::e_bool);
654 int SDPJumpCmd::run(CmdCtx *ctx)
656 const ROM_INFO * rom = search_rom_info(ctx->m_config_item);
658 HIDTrans dev(m_timeout);
659 if (dev.open(ctx->m_dev))
660 return -1;
662 HIDReport report(&dev);
664 if (rom == nullptr)
666 string_ex err;
667 err.format("%s:%d can't get rom info", __FUNCTION__, __LINE__);
668 set_last_err_string(err);
669 return -1;
672 if (rom->flags & ROM_INFO_SPL_JUMP)
674 m_spdcmd.m_addr = EndianSwap(m_jump_addr);
675 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
676 return -1;
678 //Omit last return value.
679 check_ack(&report, ROM_OK_ACK);
680 return 0;
683 shared_ptr<FileBuffer> p1 = get_file_buffer(m_filename, true);
684 if (!p1)
685 return -1;
687 shared_ptr<DataBuffer> buff;
688 buff = p1->request_data(0, m_scan_limited);
689 if (!buff) return -1;
691 size_t off = 0;
692 IvtHeader *pIVT = search_ivt_header(buff, off, m_scan_limited);
694 for (int i = 0; i < m_Ivt; i++)
696 off += sizeof(IvtHeader);
697 pIVT = search_ivt_header(buff, off);
700 if (pIVT == nullptr)
702 set_last_err_string("Cannot find valid IVT header");
703 return -1;
706 m_spdcmd.m_addr = EndianSwap(pIVT->SelfAddr);
709 if (rom->flags & ROM_INFO_HID_SKIP_DCD && !m_clear_dcd)
711 SDPSkipDCDCmd skipcmd(nullptr);
712 if (skipcmd.run(ctx))
713 return -1;
715 else
716 { /*Clear DCD*/
717 vector<uint8_t> ivt;
718 /* Need send out whole report size buffer avoid overwrite other data
719 * Some platform require receive whole package for report id = 2
721 ivt.resize(report.get_out_package_size());
723 size_t sz = buff->size();
724 sz -= (uint8_t*)pIVT - (uint8_t*)buff->data();
726 if (sz > ivt.size())
727 sz = ivt.size();
729 memcpy(ivt.data(), pIVT, sz);
731 IvtHeader *header = (IvtHeader *)ivt.data();
732 header->DCDAddress = 0;
734 SDPWriteCmd writecmd(nullptr);
735 if(writecmd.run(ctx, header, ivt.size(), pIVT->SelfAddr))
736 return -1;
739 if (report.write(&m_spdcmd, sizeof(m_spdcmd), 1))
740 return -1;
742 //Omit last return value.
743 check_ack(&report, ROM_OK_ACK);
745 return 0;
748 SDPBootlogCmd::SDPBootlogCmd(char *p) : SDPCmdBase(p)
750 insert_param_info("blog", nullptr, Param::Type::e_null);
753 int SDPBootlogCmd::run(CmdCtx *ctx)
755 HIDTrans dev{2000};
757 if (dev.open(ctx->m_dev))
758 return -1;
760 HIDReport report(&dev);
762 vector<uint8_t> v(65);
763 v[0] = 'I';
765 uuu_notify nt;
766 nt.type = uuu_notify::NOTIFY_CMD_INFO;
768 int ret;
769 while (1)
771 ret = report.read(v);
772 if (ret)
773 return 0;
774 else
776 nt.str = (char*)(v.data() + 4);
777 v[5] = 0;
778 call_notify(nt);
779 continue;
782 return 0;