#!/usr/bin/perl # #[20190307][xiaokeweng@asrmicro.com] # COMM: Tnitial perl script ,do (RW+ZI) region compress. The header of # image which to fetch compress area is recordered from C code , # may refer to /csw/bsp/src/loadTable.c for more detail. # TODO: Armlink could do RW region compress during armlink # but our scatter file did include ZI data inside into the RW region. # Do further check to refactor the scatter file. # #[20190309][xiaokeweng@asrmicro.com] # COMM: correct typo & fix issue which LZMA compressed info inside split_result[6] # did not count the LZMA header&tail part size inside. it only caculate for # compress ratio. Using [-s ] to get the true size of compressed file. # #[20190310][xiaokeweng@asrmicro.com] # COMM: bad CPZ_LOAD_ADDR raw data, missing the initial zero address after hex_32_reorder # fix with format-output during syswrite. # #[20201017][xiaokeweng@asrmicro.com] # COMM: implement file_merge func to avoid CAT/COPY switch in defferent host env. # use Fcntl; use File::Basename; use File::Spec::Functions; $DEBUG=0; $LOADTABLE_HEADER_LENGTH=1024; $CPZ_MARK_STRING="RW_CPZ_"; $IMG_FILENAME = $ARGV[0]; $IMG_GENERAL_INFO = $ARGV[1]; $PART_1 = "part1"; $PART_2 = "part2"; $COMPRE = "compressed.bin"; $TMP = "tmp"; $TMP_LZMA = "tmp_lzma"; #$INIT_LOAD_ADDRESS=0x80200000; $INIT_LOAD_MARK_STRING="CP_EXEC"; $PAD_LENGTH=4096; if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin') { $EXE_SUFFIX = ".exe"; } else { $EXE_SUFFIX = "_lnx"; } $LZMA = catfile(dirname(__FILE__), "lzma_asr$EXE_SUFFIX"); sysopen(INPUT_STREAM,"$IMG_FILENAME",O_BINARY|O_RDWR) or error_exit("Can't open [$IMG_FILENAME] for reading; $!"); print sprintf ("|%-8s|%-74s\n","INPUT",$IMG_FILENAME); # load the frist {$LOADTABLE_HEADER_LENGTH} binary to parse # check {$INIT_LOAD_MARK_STRING} flag which appends the cp core execute address # #/csw/BSP/inc/loadTable.h # typedef struct{ # char name[12]; # UINT32 value; # }armlink_symbol_item; # # sysread(INPUT_STREAM,$loadtable_header,$LOADTABLE_HEADER_LENGTH); $index=index($loadtable_header,$INIT_LOAD_MARK_STRING); if ($index == -1){ error_exit("NO compress string [$INIT_LOAD_MARK_STRING] detect, exit"); }else{ sysseek(INPUT_STREAM,$index+12,0); sysread(INPUT_STREAM,$INIT_LOAD_ADDRESS,4); $INIT_LOAD_ADDRESS = raw_to_hex($INIT_LOAD_ADDRESS); #print sprintf ("0x%.08x\n",$INIT_LOAD_ADDRESS); } # check {$CPZ_MARK_STRING} flag which repsent the regiong compress info # #debug_msg("loadtable_header:[\n$loadtable_header\n]"); $index=index($loadtable_header,$CPZ_MARK_STRING); debug_msg("index=$index"); if ($index == -1){ error_exit("NO compress string [$CPZ_MARK_STRING] detect, exit"); }else{ #open OUTBIN_P1,">$IMG_FILENAME\_$PART_1" or error_exit("can't open $IMG_FILENAME\_$PART_1 for output"); sysopen(OUTBIN_P1,"$IMG_FILENAME\_$PART_1",O_BINARY|O_CREAT|O_RDWR); debug_msg("create the empty $IMG_FILENAME\_$PART_1"); close OUTBIN_P1; #open OUTBIN_P2,">$IMG_FILENAME\_$PART_2" or error_exit("can't open $IMG_FILENAME\_$PART_2 for output"); sysopen(OUTBIN_P2,"$IMG_FILENAME\_$PART_2",O_BINARY|O_CREAT|O_RDWR); debug_msg("create the empty $IMG_FILENAME\_$PART_2"); close OUTBIN_P2; }; # parse each item start with $CPZ_MARK_STRING, # the format detail refer to csw/BSP/inc/loadTable.h # #typedef struct #{ # char RW_REGION_MARK[8]; # char RW_REGION_NAME[8]; # UINT32 RW_REGION_EXEC_ADDR; # UINT32 RW_REGION_LOAD_ADDR; # UINT32 RW_REGION_LENGTH; # UINT32 RW_REGION_COMPRESSED_ADDR; #}rw_region_item; # print sprintf ("|%-8s|%-8s|%-8s.%-8s.%-8s.%-8s|%-30s|\n", "MARK","NAME","EXEADDR","LOADADDR","LENGTH","CPZLADDR","COMPRESS STASTIC"); print sprintf ("|%-8s|%-8s|%-8s.%-8s.%-8s.%-8s|%-30s|\n", "--------","--------","--------","--------","--------","--------","------------------------------"); sysseek(INPUT_STREAM,$index,0); while(1){ sysread(INPUT_STREAM,$mark,8);debug_msg("mark = $mark"); unless($mark =~ /$CPZ_MARK_STRING/){last;} sysread(INPUT_STREAM,$name,8); sysread(INPUT_STREAM,$exec_addr,4);$exec_addr = raw_to_hex($exec_addr); sysread(INPUT_STREAM,$load_addr,4);$load_addr = raw_to_hex($load_addr); sysread(INPUT_STREAM,$length,4);$length = raw_to_hex($length); sysread(INPUT_STREAM,$cpz_load_addr,4);$cpz_load_addr = raw_to_hex($cpz_load_addr); # recorder the first compress region offset for PART_1 # unless( "$mark" cmp "$CPZ_MARK_STRING".1){ $p1_length=($load_addr-$INIT_LOAD_ADDRESS); $tmp_cpz_load_addr=($load_addr); debug_msg("p1_length=$p1_length"); if($p1_length&($PAD_LENGTH-1)){ $p1_pad_length = $PAD_LENGTH - $p1_length&($PAD_LENGTH-1); #print sprintf ("p1_pad_length %.8x\n",$p1_pad_length); $tmp_cpz_load_addr = $tmp_cpz_load_addr + $p1_pad_length; #print sprintf ("tmp_cpz_load_addr %.8x\n",$tmp_cpz_load_addr); } } #print sprintf ("[%8s][%8s][0x%.08x][0x%.08x][0x%.08x]\n",$mark,$name,$exec_addr,$load_addr,$length); # step1: cut uncompressed Region into OUTBIN_TMP file # open TMP_INPUT_STREAM, $IMG_FILENAME or error_exit("Can't open [$IMG_FILENAME] for reading; $!"); sysopen(TMP_INPUT_STREAM,$IMG_FILENAME,O_BINARY|O_RDONLY); sysseek(TMP_INPUT_STREAM,$load_addr-$INIT_LOAD_ADDRESS,0); sysread(TMP_INPUT_STREAM,$buf,$length); sysopen(OUTBIN_TMP,"$mark\_$TMP",O_BINARY|O_CREAT|O_WRONLY); syswrite(OUTBIN_TMP,$buf,$length); close TMP_INPUT_STREAM; close OUTBIN_TMP; # step2: compressed the OUTBIN_TMP & get the lzma info # $lowercase_tmp_lzma_file=lc("$mark\_$TMP_LZMA"); # set to lowercase to avoid case-change under linux env , with WINE lzma.exe invoke $temp_index=index($IMG_GENERAL_INFO,"8M"); if ($temp_index == -1){ $temp_index=index($IMG_GENERAL_INFO,"4M"); if ($temp_index == -1){ qx("$LZMA" ds 19 e $mark\_$TMP $lowercase_tmp_lzma_file 2>&1 ); }else{ print sprintf ("|%s|\n","LteOnly 4M RAM"); qx("$LZMA" ds 17 e $mark\_$TMP $lowercase_tmp_lzma_file 2>&1 ); } }else{ print sprintf ("|%s|\n","LteOnly 8M RAM"); qx("$LZMA" ds 18 e $mark\_$TMP $lowercase_tmp_lzma_file 2>&1 ); } $tmp_lzma_size=-s "$lowercase_tmp_lzma_file"; sysopen(OUTBIN_TMP_LZMA,"$lowercase_tmp_lzma_file",O_BINARY|O_WRONLY|O_APPEND); if($tmp_lzma_size&($PAD_LENGTH-1)){ $temp_pad_length = $PAD_LENGTH - $tmp_lzma_size&($PAD_LENGTH-1); #print sprintf ("temp_pad_length %.8x\n",$temp_pad_length); while($temp_pad_length--){ #print OUTBIN_TMP_LZMA '0'; syswrite(OUTBIN_TMP_LZMA,pack("H1","0"),1); } #syswrite(OUTBIN_TMP_LZMA,$bufpad,$temp_pad_length); } close OUTBIN_TMP_LZMA; $tmp_file_size=-s "$mark\_$TMP"; $tmp_lzma_size=-s "$lowercase_tmp_lzma_file"; print sprintf ("|%8s|%7s |%.08x.%.08x.%.08x.%.08x|%.08x->%.08x\n", $mark,substr($name,0,7),$exec_addr,$load_addr,$length,$tmp_cpz_load_addr, $tmp_file_size,$tmp_lzma_size); # step3: record the current load addr into image header # if (==1st ) RW_REGION_COMPRESSED_ADDR = RW_REGION_LOAD_ADDR; # if (>=2nd ) RW_REGION_COMPRESSED_ADDR = last(RW_REGION_COMPRESSED_ADDR)+last(COMPRESSED_LENGTH); # my $tell=sysseek(INPUT_STREAM,0,1); sysseek(INPUT_STREAM,$tell-8,0); debug_msg(sysseek(INPUT_STREAM,0,1)); $tmp_size = hex_32_reorder($tmp_lzma_size); #print sprintf "debug - tmp_raw=0x%.08x\n",$tmp_raw; syswrite(INPUT_STREAM,pack("H*",sprintf("%08x",$tmp_size)),4); debug_msg(sysseek(INPUT_STREAM,0,1)); $tmp_raw = hex_32_reorder($tmp_cpz_load_addr); #print sprintf "debug - tmp_raw=0x%.08x\n",$tmp_raw; syswrite(INPUT_STREAM,pack("H*",sprintf("%08x",$tmp_raw)),4); $tmp_cpz_load_addr = $tmp_cpz_load_addr+$tmp_lzma_size; #print sprintf ("tmp_cpz_load_addr=[%.08x][%d]\n",$tmp_cpz_load_addr,$tmp_cpz_load_addr); # step4: append compressed file into $IMG_FILENAME\_PART_2 one by one # sysopen(OUTBIN_TMP_LZMA,"$lowercase_tmp_lzma_file",O_BINARY|O_RDWR); sysopen(OUTBIN_P2,"$IMG_FILENAME\_$PART_2",O_BINARY|O_WRONLY|O_APPEND); while(){ print OUTBIN_P2 $_; } # step5: trash clean # unlink glob("$mark*"); close OUTBIN_P2; close OUTBIN_TMP_LZMA; } #print sprintf ("[%-8s][%-8s][%-8s][%-8s][%-8s][%-8s][%-33s]\n", # "--------","--------","--------","--------","--------","--------","---------------------------------"); unlink glob("*$TMP_LZMA"); # step6: append compressed file into $IMG_FILENAME\_PART_2 one by one # sysseek(INPUT_STREAM,0,0); sysopen(INPUT_STREAM,"$IMG_FILENAME",O_BINARY|O_RDONLY); sysread(INPUT_STREAM,$buf,$p1_length); sysopen(OUTBIN_P1,"$IMG_FILENAME\_$PART_1",O_BINARY|O_WRONLY|O_APPEND); syswrite(OUTBIN_P1,$buf,$p1_length); if($p1_length&($PAD_LENGTH-1)){ $p1_pad_length = $PAD_LENGTH - $p1_length&($PAD_LENGTH-1); #print sprintf ("p1_pad_length %.8x\n",$p1_pad_length); while($p1_pad_length--){ #print OUTBIN_P1 '0'; syswrite(OUTBIN_P1,pack("H1","0"),1); } #syswrite(OUTBIN_P1,$bufpad,$p1_pad_length); } close OUTBIN_P1; # step6: PART1 + PART2 > IMG_FILENAME & dump IMAGE size compress summery # #print sprintf ("[%-8s][%-8s][%-8s][%-8s][%-8s][%-8s][%-33s]\n", # "--------","--------","--------","--------","--------","--------","---------------------------------"); my $original_size= -s $IMG_FILENAME; unlink("$IMG_FILENAME"); close INPUT_STREAM; $temp_index=index($IMG_GENERAL_INFO,"_TRUNCATE"); if ($temp_index == -1){ file_merge("$IMG_FILENAME\_$PART_1","$IMG_FILENAME\_$PART_2",$IMG_FILENAME); my $compressed_size= -s $IMG_FILENAME; }else{ unlink("$IMG_FILENAME"); rename("$IMG_FILENAME\_$PART_1","$IMG_FILENAME"); $COMPRE_NAME=substr($IMG_FILENAME,0,length($IMG_FILENAME)-4); rename("$IMG_FILENAME\_$PART_2","$COMPRE_NAME\_$COMPRE"); my $uncompressed_size= -s $IMG_FILENAME; my $compressed_size_temp= -s "$COMPRE_NAME\_$COMPRE"; $compressed_size = $uncompressed_size + $compressed_size_temp; } print sprintf ("|%-8s|%-8s|%-8s.%-8s.%-8s.%-8s|%-30s|\n", "--------","--------","--------","--------","--------","--------","------------------------------"); print sprintf ("|%-53s|%6s0x%.08x -> 0x%.08x|\n","","", $original_size,$compressed_size); print sprintf ("|%-53s|%6s%6.3f(MB) -> %6.3f(MB)|\n","","", $original_size/1024/1024,$compressed_size/1024/1024); print sprintf ("|%s|\n","------------------------------------------------------------------------------------"); unlink("$IMG_FILENAME\_$PART_1"); unlink("$IMG_FILENAME\_$PART_2"); exit(0); # functions # sub hex_32_reorder{ local $m_hex = $_[0]; $m_hex = ((($m_hex&0x000000ff)<<24)| (($m_hex&0x0000ff00)<<8)| (($m_hex&0x00ff0000)>>8)| (($m_hex&0xff000000)>>24)); return $m_hex; } sub raw_to_hex{ local $m_hex = hex(unpack("H*",$_[0])); $m_hex = hex_32_reorder($m_hex); return $m_hex; } sub debug_msg{ unless($DEBUG){return}; local $DEBUG_MSG="DEBUG >>> :"; print "$DEBUG_MSG @_"; print "\n"; } sub error_exit{ local $ERROR_MSG="\nERROR:**"; print "----------------------"; print "$ERROR_MSG @_"; print "\n"; exit(1); } sub file_merge{ open(RH,$_[0]) or die "$!"; binmode RH; my @src_1=; close RH; open(RH,$_[1]) or die "$!"; binmode RH; my @src_2=; close RH; #create&overwrite for input file arg0 open(WH,">$_[2]") or die "$!"; binmode WH; my $i; for($i = 0; $i < @src_1; $i++){ print WH $src_1[$i]; } close WH; #append for input file arg1 open(WH,">>$_[2]") or die "$!"; binmode WH; my $i; for($i = 0; $i < @src_2; $i++){ print WH $src_2[$i]; } close WH; }