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.
34 #include "hidreport.h"
45 int SDPCmdBase::check_ack(HIDReport
*report
, uint32_t ack
)
47 if (get_hab_type(report
) == HabUnknown
)
51 if (get_status(report
, status
, 4))
56 set_last_err_string("Status Miss matched");
62 SDPCmdBase::HAB_t
SDPCmdBase::get_hab_type(HIDReport
*report
)
65 if (get_status(report
, status
, 3))
68 if (status
== HabEnabled
)
71 if (status
== HabDisabled
)
74 set_last_err_string("unknown hab type");
78 int SDPCmdBase::get_status(HIDReport
*p
, uint32_t &status
, uint8_t report_id
)
81 m_input
[0] = report_id
;
82 int ret
= p
->read(m_input
);
86 if (m_input
.size() < (1 + sizeof(uint32_t)))
88 set_last_err_string("HID report size is too small");
92 status
= *(uint32_t*)(m_input
.data() + 1);
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
);
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
)
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)
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
);
140 int SDPDcdCmd::run(CmdCtx
*ctx
)
142 const ROM_INFO
* rom
= search_rom_info(ctx
->m_config_item
);
146 err
.format("%s:%d can't get rom info", __FUNCTION__
, __LINE__
);
147 set_last_err_string(err
);
152 shared_ptr
<FileBuffer
> p
= get_file_buffer(m_filename
, true);
157 shared_ptr
<DataBuffer
> buff
;
158 buff
= p
->request_data(0, m_scan_limited
);
159 if (!buff
) return -1;
162 IvtHeader
*pIVT
= search_ivt_header(buff
, off
);
168 if (pIVT
->DCDAddress
== 0)
171 uint8_t * pdcd
= &(buff
->at(off
+ pIVT
->DCDAddress
- pIVT
->SelfAddr
));
173 if (pdcd
[0] != HAB_TAG_DCD
)
176 err
.format("%s:%d DCD TAG miss matched", __FUNCTION__
, __LINE__
);
177 set_last_err_string(err
);
181 uint32_t size
= (pdcd
[1] << 8) | pdcd
[2];
183 if (size
>= m_scan_limited
)
185 set_last_err_string("dcd bigger than 8M");
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
))
200 HIDReport
report(&dev
);
201 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
204 if (report
.write(pdcd
, size
, 2))
207 if (check_ack(&report
, ROM_WRITE_ACK
))
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
))
224 HIDReport
report(&dev
);
225 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
228 if (check_ack(&report
, ROM_OK_ACK
))
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
)
247 str
= "SDP: dcd -f ";
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 ";
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 ";
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());
300 if (jmp
.parser()) return -1;
301 if (jmp
.run(ctx
)) return -1;
304 SDPBootlogCmd
log(nullptr);
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
))
322 HIDReport
report(&dev
);
323 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
326 if (get_hab_type(&report
) == HabUnknown
)
330 if (get_status(&report
, status
, 4))
336 SDPWriteCmd::SDPWriteCmd(char *p
) : SDPCmdBase(p
)
338 m_spdcmd
.m_cmd
= ROM_KERNEL_CMD_WR_FILE
;
341 m_max_download_pre_cmd
= 0x200000;
343 m_bIvtReserve
= 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
)
364 shared_ptr
<FileBuffer
> p1
= get_file_buffer(m_filename
, true);
369 shared_ptr
<DataBuffer
> fbuff
;
371 fbuff
= p1
->request_data(0, m_scan_limited
);
372 if (!fbuff
) return -1;
376 pbuff
= fbuff
->data();
377 size
= fbuff
->size();
382 offset
+= GetFlashHeaderSize(fbuff
, offset
);
384 size_t pos
= 0, length
;
389 length
= ScanTerm(fbuff
, pos
);
392 set_last_err_string("This wic have NOT terminate tag after bootloader, please use new yocto");
396 offset
= pos
- length
;
399 set_last_err_string("This wic boot length is wrong");
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");
415 IvtHeader
*pIvt
= search_ivt_header(fbuff
, off
, 0x100000);
420 BootData
*pDB
= (BootData
*) &(fbuff
->at(off
+ pIvt
->BootData
- pIvt
->SelfAddr
));
421 offset
= off
+ pDB
->ImageSize
- (pIvt
->SelfAddr
- pDB
->ImageStartAddr
);
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");
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
);
449 set_last_err_string("Cannot find valid IVT header");
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");
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
))
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
))
493 for (size_t i
=0; i
< size
; i
+= 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))
509 report
.set_skip_notify(false);
511 if (report
.write(((uint8_t*)pbuff
)+i
, sz
, 2))
514 if (validate
&& check_ack(&report
, ROM_STATUS_ACK
))
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
))
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
) {
543 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x1);
546 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x2);
549 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x4);
552 set_last_err_string("Invalid format, use <8|16|32>");
557 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
560 if (get_hab_type(&report
) == HabUnknown
)
564 if (get_status(&report
, mem_value
, 4) == 0)
566 printf("\nValue of address 0x%08X: ", m_mem_addr
);
567 switch (m_mem_format
) {
569 printf("0x%02X\n", mem_value
& 0xff);
572 printf("0x%04X\n", mem_value
& 0xffff);
575 printf("0x%08X\n", mem_value
);
578 set_last_err_string("Invalid format, use <8|16|32>");
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
))
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
) {
609 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x1);
612 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x2);
615 m_spdcmd
.m_count
= EndianSwap((uint32_t)0x4);
618 set_last_err_string("Invalid format, use <8|16|32>");
622 m_spdcmd
.m_data
= EndianSwap(m_mem_value
);
624 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
627 if (get_hab_type(&report
) == HabUnknown
)
632 if (get_status(&report
, status
, 4) < 0 || status
!= ROM_WRITE_ACK
) {
635 err
.format("%s:%d Failed to write to address 0x%X",
636 __FUNCTION__
, __LINE__
, m_mem_addr
);
637 set_last_err_string(err
);
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
))
662 HIDReport
report(&dev
);
667 err
.format("%s:%d can't get rom info", __FUNCTION__
, __LINE__
);
668 set_last_err_string(err
);
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))
678 //Omit last return value.
679 check_ack(&report
, ROM_OK_ACK
);
683 shared_ptr
<FileBuffer
> p1
= get_file_buffer(m_filename
, true);
687 shared_ptr
<DataBuffer
> buff
;
688 buff
= p1
->request_data(0, m_scan_limited
);
689 if (!buff
) return -1;
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
);
702 set_last_err_string("Cannot find valid IVT header");
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
))
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();
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
))
739 if (report
.write(&m_spdcmd
, sizeof(m_spdcmd
), 1))
742 //Omit last return value.
743 check_ack(&report
, ROM_OK_ACK
);
748 SDPBootlogCmd::SDPBootlogCmd(char *p
) : SDPCmdBase(p
)
750 insert_param_info("blog", nullptr, Param::Type::e_null
);
753 int SDPBootlogCmd::run(CmdCtx
*ctx
)
757 if (dev
.open(ctx
->m_dev
))
760 HIDReport
report(&dev
);
762 vector
<uint8_t> v(65);
766 nt
.type
= uuu_notify::NOTIFY_CMD_INFO
;
771 ret
= report
.read(v
);
776 nt
.str
= (char*)(v
.data() + 4);