| #!/usr/bin/perl |
| # |
| # Copyright 2016-2021, Cypress Semiconductor Corporation (an Infineon company) or |
| # an affiliate of Cypress Semiconductor Corporation. All rights reserved. |
| # |
| # This software, including source code, documentation and related |
| # materials ("Software") is owned by Cypress Semiconductor Corporation |
| # or one of its affiliates ("Cypress") and is protected by and subject to |
| # worldwide patent protection (United States and foreign), |
| # United States copyright laws and international treaty provisions. |
| # Therefore, you may use this Software only as provided in the license |
| # agreement accompanying the software package from which you |
| # obtained this Software ("EULA"). |
| # If no EULA applies, Cypress hereby grants you a personal, non-exclusive, |
| # non-transferable license to copy, modify, and compile the Software |
| # source code solely for use in connection with Cypress's |
| # integrated circuit products. Any reproduction, modification, translation, |
| # compilation, or representation of this Software except as specified |
| # above is prohibited without the express written permission of Cypress. |
| # |
| # Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND, |
| # EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress |
| # reserves the right to make changes to the Software without notice. Cypress |
| # does not assume any liability arising out of the application or use of the |
| # Software or any product or circuit described in the Software. Cypress does |
| # not authorize its products for use in any products where a malfunction or |
| # failure of the Cypress product may reasonably be expected to result in |
| # significant property damage, injury or death ("High Risk Product"). By |
| # including Cypress's product in a High Risk Product, the manufacturer |
| # of such system or application assumes all risk of such use and in doing |
| # so agrees to indemnify Cypress against all liability. |
| # |
| use READELF; |
| # read patch.elf and generate linker directive file |
| |
| # call with "perl wiced-gen-ld.pl <args> patch.elf out=<*.ld>" |
| # the "patch.elf" is parsed to determine where to start the application memory |
| # the "out=<*.ld>" file is the output linker script |
| # arguments: |
| # SRAM_BEGIN_ADDR=0x123456, SRAM_LENGTH=0x1234: start and length of SRAM section for app code and data |
| # NUM_PATCH_ENTRIES=256: used to calculate reserved space in SRAM for patch entries |
| # ISTATIC_BEGIN=0x123456, ISTATIC_LEN=0x1234: start and length of static section data, typically encrypted keys |
| # PRAM_OBJ=abc.o;def.o;ghi.o: code/rodata for patch ram |
| # XIP_LEN=0x1234, XIP_OBJ=abc.o;def.o;ghi.o: execute in place area for on-chip-flash starting at 0x504000, contains code and rodata from listed object files |
| # UNUSED_BEGIN=0x123456, UNUSED_LEN=0x1234: start and length of an UNUSED section defined to avoid loading anything into |
| # DIRECT_LOAD=1: indicates RAM download rather than FLASH |
| # overlay=overlays.ld: a linker script snippet generated for an overlay section |
| |
| # ram is extended with PRAM (taking from patch space) or XIP (taking from on-chip-flash, code or rodata only) |
| # .dsp_pram_section is for dsp download (libraries/codec_ak4679_lib/akm4679_dsp_*.h) |
| |
| # look up for memory map and section input/output information |
| my $mem_lut = { |
| ".app_xip_area" => { |
| "sections" => [ |
| "KEEP(*(.xs_header))", |
| # argument XIP_OBJ will add section matches $(XIP_OBJ)(.text.* .gnu.linkonce.t.* .rodata .constdata* .rodata.* .gnu.linkonce.r.* ) |
| # special section for Position Independent trampoline functions. |
| "*(.pisec_*)", |
| "KEEP(*(.data_in_xip_area))", |
| "KEEP(*(.dsp_pram_section))",], |
| "mem_type" => "xip_section", |
| "pre" => ["xip_area_begin"], |
| "post" => ["spar_irom_end","xip_area_end"],}, |
| ".setup" => { |
| "sections" => [ |
| "*(.init_code)", |
| "*(.init_text)", |
| "*(.init_data)", |
| "*(.spar_setup)"], |
| "mem_type" => "ram", |
| "pre" => [], |
| "post" => [],}, |
| ".text" => { |
| "sections" => [ |
| "*(.app_init_code)", |
| "*(.emb_text)", |
| "*(.text)", |
| "*(.text_in_ram)", |
| "*(.text.*)", |
| "*(EmHeAacDec)", |
| "*(.gnu.linkonce.t.*)", |
| "*(.glue_7t)", |
| "*(.glue_7)", |
| "*(.vfp11_veneer)", |
| "*(.v4_bx)", |
| "*(.ARM.extab*)", |
| "*(.gnu.linkonce.armextab.*)", |
| "*(.ARM.exidx*)", |
| "*(.gnu.linkonce.armexidx.*)", |
| "*(.vpc_decoder_section)", |
| "PROVIDE_HIDDEN (__init_array_start = .);", |
| "KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))", |
| "KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))", |
| "PROVIDE_HIDDEN (__init_array_end = .);"], |
| "mem_type" => "ram", |
| "pre" => [], |
| "post" => [],}, |
| ".text.mbedtls" => { |
| "sections" => [ |
| "libmbedtls.*.o(.text.*)", |
| ], |
| "mem_type" => "ram", |
| "pre" => [], |
| "post" => [], |
| }, |
| ".rodata" => { |
| "sections" => [ |
| "*(const_drom_var)", |
| "*(.rodata)", |
| "*(.constdata*)", |
| "*(.rodata.*)", |
| "*(.gnu.linkonce.r.*)", |
| "*(.data.rom)"], |
| "mem_type" => "ram", |
| "pre" => [], |
| "post" => ["spar_irom_end"],}, |
| ".data" => { |
| "sections" => [ |
| "*(.data)", |
| "*(.data.*)", |
| "*(.gnu.linkonce.d.*)", |
| "*(.init_patch_table)"], |
| "mem_type" => "ram", |
| "pre" => ["spar_iram_begin", "spar_iram_data_begin"], |
| "post" => ["spar_iram_data_end"],}, |
| ".bss" => { |
| "sections" => [ |
| "*(.bss)", |
| "*(.bss.*)", |
| "*(.gnu.linkonce.b.*)", |
| "*(COMMON)"], |
| "mem_type" => "ram", |
| "pre" => ["spar_iram_bss_begin"], |
| "post" => ["spar_iram_bss_end", "spar_iram_end"],}, |
| ".unused" => { |
| "sections" => [ |
| "*(.code_in_retention_ram)", |
| "*(.data_in_retention_ram)"], |
| "mem_type" => "unused", |
| "pre" => ["unused_iram_begin"], |
| "post" => ["unused_iram_end"],}, |
| ".aon" => { |
| "sections" => [ |
| "*(always_on_ram_var)", |
| "*(.aon_code)", |
| "*(.data_in_retention_ram)", |
| "*(.code_in_retention_ram)"], |
| "mem_type" => "aon", |
| "pre" => ["aon_iram_begin"], |
| "post" => ["aon_iram_end"],}, |
| ".static_area" => { |
| "sections" => [ |
| "KEEP(*(.data_in_static_area))"], |
| "mem_type" => "static_section", |
| "pre" => ["static_area_begin"], |
| "post" => ["static_area_end"],}, |
| ".pram_rodata" => { |
| "sections" => [ |
| "KEEP(*(.dsp_pram_section))"], |
| "mem_type" => "pram", |
| "pre" => [], |
| "post" => ["pram_area_end"],}, |
| ".log_section" => { |
| "sections" => [ |
| "KEEP(*(log_data))"], |
| "mem_type" => "log_section", |
| "pre" => [], |
| "post" => [],}, |
| }; |
| |
| my $xip_extra_in = [ |
| "PROVIDE_HIDDEN (__init_array_start = .);", |
| "KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))", |
| "KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))", |
| "PROVIDE_HIDDEN (__init_array_end = .);", |
| "*(.app_init_code)", |
| "*(.emb_text)", |
| "*(.text)", |
| "*(EmHeAacDec)", |
| "*(.text.*)", |
| "*(.gnu.linkonce.t.*)", |
| "*(i.*)", |
| "*(.glue_7t)", |
| "*(.glue_7)", |
| "*(.vfp11_veneer)", |
| "*(.v4_bx)", |
| "*(.ARM.extab*)", |
| "*(.gnu.linkonce.armextab.*)", |
| "*(.ARM.exidx*)", |
| "*(.gnu.linkonce.armexidx.*)", |
| "*(const_drom_var)", |
| "*(.rodata)", |
| "*(.constdata*)", |
| "*(.rodata.*)", |
| "*(.gnu.linkonce.r.*)", |
| "*(.data.rom)", |
| ]; |
| |
| main(); |
| |
| sub main |
| { |
| my $param; |
| # print "args: @ARGS\n"; |
| |
| foreach my $arg (@ARGV) { |
| if($arg =~ /\.elf$/) { |
| $param->{'elf'} = $arg; |
| } |
| if($arg =~ /\.sym$/) { |
| $param->{'sym'} = $arg; |
| } |
| elsif($arg =~ /^ISTATIC_BEGIN=(\w+)/) { |
| $param->{'ISTATIC_BEGIN'} = hex($1); |
| } |
| elsif($arg =~ /^ISTATIC_LEN=(\w+)/) { |
| $param->{'ISTATIC_LEN'} = hex($1); |
| } |
| elsif($arg =~ /^UNUSED_BEGIN=(\w+)/) { |
| $param->{'UNUSED_BEGIN'} = hex($1); |
| } |
| elsif($arg =~ /^UNUSED_LEN=(\w+)/) { |
| $param->{'UNUSED_LEN'} = hex($1); |
| } |
| elsif($arg =~ /^AON_AREA_END=(\w+)/) { |
| $param->{'AON_AREA_END'} = hex($1); |
| } |
| elsif($arg =~ /^SRAM_BEGIN_ADDR=(\w+)/) { |
| $param->{'SRAM_BEGIN_ADDR'} = hex($1); |
| } |
| elsif($arg =~ /^SRAM_LENGTH=(\w+)/) { |
| $param->{'SRAM_LENGTH'} = hex($1); |
| } |
| elsif($arg =~ /^PATCH_RAM_OBJ=(.*)/) { |
| $param->{'PATCH_RAM_OBJ'} = $1; |
| my @patch_ram_obj = split ";", $1; |
| my @patch_ram_o; |
| foreach my $obj (@patch_ram_obj) { |
| $obj =~ s/^\./\*/; |
| $obj .= " (.text.* .gnu.linkonce.t.* .rodata .constdata* .rodata.* .gnu.linkonce.r.*)"; |
| push @patch_ram_o, $obj; |
| } |
| unshift @{$mem_lut->{'.pram_rodata'}->{sections}}, @patch_ram_o; |
| } |
| elsif($arg =~ /^NUM_PATCH_ENTRIES=(\d+)/) { |
| $param->{'NUM_PATCH_ENTRIES'} = $1; |
| } |
| elsif($arg =~ /^DIRECT_LOAD=(\d)/) { |
| $param->{'direct_load'} = $1; |
| } |
| elsif($arg =~ /^BTP=(.*)/) { |
| $param->{'btp'} = $1; |
| } |
| elsif($arg =~ /^FLASH0_BEGIN_ADDR=(\w+)/) { |
| $param->{'FLASH0_BEGIN_ADDR'} = hex($1); |
| } |
| elsif($arg =~ /^FLASH0_LENGTH=(\w+)/) { |
| $param->{'FLASH0_LENGTH'} = hex($1); |
| } |
| elsif($arg =~ /^XIP_DS_OFFSET=(\w+)/) { |
| $param->{'XIP_DS_OFFSET'} = hex($1); |
| $param->{'xip'} = 1; |
| push @{$mem_lut->{'.app_xip_area'}->{sections}}, @{$xip_extra_in}; |
| } |
| elsif($arg =~ /^XIP_LEN=(\w+)/) { |
| $param->{'XIP_LEN'} = hex($1); |
| } |
| elsif($arg =~ /^XIP_OBJ=(.*)/) { |
| my @xip_obj = split ";", $1; |
| my @xip_o; |
| foreach my $obj (@xip_obj) { |
| $obj =~ s/^\./\*/; |
| $obj .= " (.text.* .gnu.linkonce.t.* .rodata .constdata* .rodata.* .gnu.linkonce.r.*)"; |
| push @xip_o, $obj; |
| } |
| unshift @{$mem_lut->{'.app_xip_area'}->{sections}}, @xip_o; |
| } |
| elsif($arg =~ /^APP_DS2_LEN=(\w+)/) { |
| $param->{'APP_DS2_LEN'} = hex($1); |
| } |
| elsif($arg =~ /^DS_LOCATION=(\w+)/) { |
| $param->{'DS_LOCATION'} = hex($1); |
| } |
| elsif($arg =~ /^OTA_UPGRADE_STORE=(\w+)/) { |
| $param->{'OTA_UPGRADE_STORE'} = $1; |
| } |
| elsif($arg =~ /^overlay=(.*)$/) { |
| $param->{'overlay'} = $1; |
| warn "overlay is $1\n"; |
| } |
| elsif($arg =~ /^out=(.*)/) { |
| $param->{'outfile'} = $1; |
| } |
| } |
| |
| if(defined $param->{btp} && defined $param->{FLASH0_BEGIN_ADDR} && defined $param->{FLASH0_LENGTH}) { |
| open(my $BTP, "<", $param->{btp}) || die "Could not open *.btp file \"$param->{btp}\", $!"; |
| while(defined(my $line = <$BTP>)) { |
| if($line =~ /\s*(\w+)\s*\=\s*(0x[0-9a-fA-F]+)/) { |
| $param->{$1} = hex($2); |
| } |
| elsif($line =~ /\s*(\w+)\s*\=\s*([0-9]+)/) { |
| $param->{$1} = int($2); |
| } |
| } |
| close $BTP; |
| } |
| # override ConfigDSLocation if DS_LOCATION provided on command line |
| if(defined $param->{ConfigDSLocation} && defined $param->{DS_LOCATION}) { |
| $param->{ConfigDSLocation} = $param->{DS_LOCATION}; |
| } |
| |
| my $section_lut = {}; |
| if(defined $param->{elf}) { |
| my $sections = []; |
| my $stringtable = {}; |
| my $sym_str_tbl = {}; |
| my $symbol_entries = []; |
| parse_elf($param->{elf}, $sections, $stringtable, $sym_str_tbl, $symbol_entries, 1); |
| |
| #printf "got %d sections\n", scalar(@{$sections}); |
| foreach my $section (@{$sections}) { |
| if(!defined $section->{name}) { |
| #print "section name index $section->{sh_name}\n"; |
| #printf("%s\n", $stringtable->{$section->{sh_name}}) if defined $section->{sh_name}; |
| $section->{name} = $stringtable->{$section->{sh_name}}; |
| } |
| $section_lut->{$section->{name}} = $section; |
| #printf "section %s: start 0x%x len 0x%x\n", $section->{name}, $section->{sh_addr}, $section->{sh_size}; |
| } |
| } |
| elsif(defined $param->{sym}) { |
| # using sym file, so fake reading section headers from elf |
| open(my $SYM, "<", $param->{sym}) or die "Could not read $param->{sym}, $!\n"; |
| while(defined(my $line = <$SYM>)) { |
| if($line =~ /(\w+)\s*=\s*0x([0-9A-Fa-f]+)/) { |
| last if $1 eq "END_SECTION_INFO"; |
| $section_lut->{$1} = { sh_addr => hex($2) }; |
| } |
| } |
| close $SYM; |
| } |
| $param->{SRAM_START_ADDR} = $section_lut->{first_free_section_in_SRAM}->{sh_addr} |
| if defined $section_lut->{first_free_section_in_SRAM}->{sh_addr}; |
| $param->{SRAM_START_ADDR} = $section_lut->{FIRST_FREE_SECTION_IN_SRAM}->{sh_addr} |
| if defined $section_lut->{FIRST_FREE_SECTION_IN_SRAM}->{sh_addr}; |
| # for DIRECT_LOAD, add app code after init sections (including SlimBoot) |
| $param->{SRAM_START_ADDR} = $section_lut->{POST_INIT_SECTION_IN_SRAM}->{sh_addr} |
| if defined $section_lut->{POST_INIT_SECTION_IN_SRAM}->{sh_addr} && |
| defined $param->{direct_load} && $param->{direct_load}; |
| die "Ram start undefined\n" if !defined $param->{SRAM_START_ADDR}; |
| output_ld($section_lut, $param); |
| } |
| |
| sub output_ld |
| { |
| my ($sections, $param) = @_; |
| my ($ram_start, $ram_begin, $ram_end, $ram_len, |
| $rom_start, $rom_begin, $rom_end, $rom_len, |
| $aon_begin, $aon_end, $aon_len, |
| $xip_start, $xip_len); |
| $rom_start = $sections->{CODE_AREA}->{sh_addr} if defined $sections->{CODE_AREA}; |
| die "Could not locate CODE_AREA in patch elf\n" if !defined $rom_start; |
| |
| $ram_start = $param->{SRAM_START_ADDR}; |
| my $num_patches = $param->{NUM_PATCH_ENTRIES}; |
| $num_patches = 256 if !defined $num_patches; |
| |
| $ram_begin = $param->{SRAM_BEGIN_ADDR}; |
| $ram_end = $ram_begin + $param->{SRAM_LENGTH}; |
| die "Could not locate data ram start in patch elf\n" if !defined $ram_begin; |
| die "Could not locate data ram end in patch elf\n" if !defined $ram_end; |
| if (defined $sections->{FIRST_FREE_SECTION_IN_PROM}) { |
| $rom_begin = $sections->{FIRST_FREE_SECTION_IN_PROM}->{sh_addr}; |
| $rom_end = $sections->{PATCH_CODE_END}->{sh_addr}; |
| die "Could not locate code ram start in patch elf\n" if !defined $rom_begin; |
| die "Could not locate code ram end in patch elf\n" if !defined $rom_end; |
| } |
| |
| if(defined $sections->{FIRST_FREE_SECTION_IN_AON}) { |
| $aon_begin = $sections->{FIRST_FREE_SECTION_IN_AON}->{sh_addr}; |
| $aon_end = $sections->{AON_AREA_END}->{sh_addr}; |
| $aon_end = $param->{AON_AREA_END} if !defined $aon_end; |
| die "Could not locate aon ram start in patch elf\n" if !defined $aon_begin; |
| die "Could not locate aon ram end in patch elf\n" if !defined $aon_end; |
| } |
| |
| my $patch_replace_area = $num_patches * 4; |
| $ram_len = $ram_end - $ram_start - $patch_replace_area; |
| $rom_len = $rom_end - $rom_begin if defined $rom_begin; |
| $aon_len = $aon_end - $aon_begin if defined $aon_begin; |
| |
| # $(eval LINK_LOC_FLAGS += ISTATIC_BEGIN=$(PLATFORM_APP_SPECIFIC_STATIC_DATA) ISTATIC_LEN=$(PLATFORM_APP_SPECIFIC_STATIC_LEN) IRAM_BEGIN=$(IRAM_BEGIN) IRAM_LEN=$(IRAM_LEN) IROM_BEGIN=$(IROM_BEGIN) IROM_LEN=$(IROM_LEN) IAON_BEGIN=$(IAON_BEGIN) IAON_LEN=$(IAON_LEN) ) |
| # $(QUIET)$(XCC) -E -x c -P $(addprefix -D,$(LINK_LOC_FLAGS)) -I $(dir $(ELF_OUT)) -o $@ $< |
| $param->{ISTATIC_BEGIN} = $param->{ISTATIC_BEGIN} if defined $param->{ISTATIC_BEGIN}; |
| $param->{ISTATIC_LEN} = $param->{ISTATIC_LEN} if defined $param->{ISTATIC_LEN}; |
| $param->{'direct_load'} = 0 if !defined $param->{direct_load}; |
| |
| open(my $OUT, ">", $param->{outfile}) || die "ERROR: Cannot open $param->{outfile}, $!"; |
| |
| print $OUT "OUTPUT_FORMAT (\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\n"; |
| print $OUT "SEARCH_DIR(.)\n"; |
| # print $OUT "/* @ARGV */\n"; |
| # print $OUT "/*\n"; |
| # foreach my$key (sort(keys(%{$param}))) { |
| # print $OUT "$key => $param->{$key}\n"; |
| # } |
| # print $OUT "*/\n"; |
| if(defined $rom_start) { |
| print $OUT sprintf "/* pram_patch_begin=0x%06X pram_patch_end=0x%06X pram_end=0x%06X */\n", $rom_start, $rom_begin, $rom_end; |
| } |
| print $OUT sprintf "/* ram_patch_begin=0x%06X ram_patch_end=0x%06X ram_end=0x%06X */\n", $sections->{SRAM_AREA}->{sh_addr}, $ram_start, $ram_end; |
| if(defined $aon_len) { |
| print $OUT sprintf "/* aon_patch_begin=0x%06X aon_patch_end=0x%06X aon_end=0x%06X */\n", $sections->{AON_AREA}->{sh_addr}, $aon_begin, $aon_end; |
| } |
| if(defined $aon_len) { |
| print $OUT sprintf "/* app_ram_begin=0x%06X app_ram_end=0x%06X */\n", $ram_start, $ram_start+$ram_len; |
| } |
| if(defined $param->{FLASH0_BEGIN_ADDR} && defined $param->{FLASH0_LENGTH}) { |
| print $OUT sprintf "/* FLASH0_BEGIN_ADDR=0x%06X FLASH0_LENGTH=0x%06X */\n", $param->{FLASH0_BEGIN_ADDR}, $param->{FLASH0_LENGTH}; |
| } |
| if(defined $param->{DLConfigSSLocation}) { |
| print $OUT sprintf "/* FLASH0_SS=0x%06X */\n", $param->{DLConfigSSLocation}; |
| } |
| if(defined $param->{DLConfigVSLocation}) { |
| print $OUT sprintf "/* FLASH0_VS=0x%06X */\n", $param->{DLConfigVSLocation}; |
| } |
| if(defined $param->{ConfigDSLocation}) { |
| print $OUT sprintf "/* FLASH0_DS=0x%06X */\n", $param->{ConfigDSLocation}; |
| } |
| if(defined $param->{ConfigDS2Location}) { |
| if(defined $param->{APP_DS2_LEN}) { |
| $param->{ConfigDS2Location} = $param->{FLASH0_BEGIN_ADDR} + $param->{FLASH0_LENGTH} - $param->{APP_DS2_LEN}; |
| } |
| print $OUT sprintf "/* FLASH0_DS2=0x%06X */\n", $param->{ConfigDS2Location}; |
| } |
| if(defined $param->{ConfigDSLocation}) { |
| my $store = $param->{ConfigDS2Location} - $param->{ConfigDSLocation}; |
| $param->{'OTA_UPGRADE_STORE'} = 'off_chip_sflash' if !defined $param->{OTA_UPGRADE_STORE}; |
| $store /=2 if $param->{OTA_UPGRADE_STORE} eq 'on_chip_flash'; |
| print $OUT sprintf "/* UPGRADE_STORAGE_LENGTH=0x%06X (%s) */\n", $store, $param->{OTA_UPGRADE_STORE}; |
| } |
| |
| print $OUT "MEMORY\n"; |
| print $OUT "{\n"; |
| print $OUT sprintf "\tram (rwx) : ORIGIN = 0x%X, LENGTH = 0x%X\n", $ram_start, $ram_len; |
| if(defined $aon_len) { |
| print $OUT sprintf "\taon (rwx) : ORIGIN = 0x%X, LENGTH = 0x%X\n", $aon_begin, $aon_len; |
| } |
| if(defined $param->{UNUSED_LEN}) { |
| print $OUT sprintf "\tunused (rwx) : ORIGIN = 0x%X, LENGTH = %d\n", $param->{UNUSED_BEGIN}, $param->{UNUSED_LEN}; |
| } |
| if(defined $param->{ISTATIC_BEGIN}) { |
| print $OUT sprintf "\tstatic_section (r) : ORIGIN = 0x%X, LENGTH = 0x%X\n", $param->{ISTATIC_BEGIN}, $param->{ISTATIC_LEN}; |
| } |
| if(defined $param->{xip}) { |
| $xip_start = $param->{ConfigDSLocation} + $param->{XIP_DS_OFFSET}; |
| $xip_len = $param->{XIP_LEN}; |
| $xip_len = $param->{FLASH0_LENGTH} - ($xip_start - $param->{ConfigDSLocation}) if !defined $xip_len; |
| print $OUT sprintf "\txip_section (rx) : ORIGIN = 0x%X, LENGTH = 0x%X\n", $xip_start, $xip_len; |
| } |
| if(defined $param->{PATCH_RAM_OBJ}) { |
| print $OUT sprintf "\tpram (rwx) : ORIGIN = 0x%X, LENGTH = 0x%X\n", $rom_begin, $rom_end - $rom_begin; |
| } |
| print $OUT sprintf "\tlog_section (r) : ORIGIN = 0x81000004, LENGTH = 0x100000\n"; |
| print $OUT "}\n"; |
| |
| print $OUT "EXTERN(spar_irom_begin spar_irom_end spar_irom_length);\n"; |
| print $OUT "EXTERN(spar_iram_begin spar_iram_end spar_iram_length);\n"; |
| print $OUT "EXTERN(spar_iram_data_begin spar_iram_data_end spar_iram_data_length);\n"; |
| print $OUT "EXTERN(spar_iram_bss_begin spar_iram_bss_end spar_iram_bss_length);\n"; |
| print $OUT "EXTERN(spar_irom_data_begin);\n"; |
| print $OUT "EXTERN(aon_iram_end);\n" if defined $aon_len; |
| print $OUT "EXTERN(xip_area_begin);\n" if defined $xip_start; |
| print $OUT "EXTERN(xip_area_end);\n" if defined $xip_len; |
| |
| print $OUT "PROVIDE(spar_irom_length = spar_irom_end - spar_irom_begin);\n"; |
| print $OUT "PROVIDE(spar_iram_length = spar_iram_end - spar_iram_begin);\n"; |
| print $OUT "PROVIDE(spar_iram_data_length = spar_iram_data_end - spar_iram_data_begin);\n"; |
| print $OUT "PROVIDE(spar_iram_bss_length = spar_iram_bss_end - spar_iram_bss_begin);\n"; |
| |
| print $OUT "SECTIONS\n"; |
| print $OUT "{\n"; |
| printf $OUT sprintf "\tspar_irom_begin = 0x%X;\n", $ram_start; |
| |
| # print "\t#include \"spar_ram_overlays.ld\"\n"; |
| if(defined $param->{overlay}) { |
| open(my $OVER, "<", $param->{overlay}) || die "Could not open overlay *.ld file \"$param->{overlay}\", $!"; |
| while(defined(my $line = <$OVER>)) { |
| print $OUT $line; |
| } |
| close $OVER; |
| } |
| |
| output_section('.text.mbedtls', $mem_lut, $OUT); |
| |
| # if objects are assigned to XIP, match their .text and .rodata |
| output_section('.app_xip_area', $mem_lut, $OUT) if defined $param->{xip}; |
| |
| # When direct loading, don't overlap init code with dynamic allocation. |
| if($param->{direct_load}) |
| { |
| output_section('.setup', $mem_lut, $OUT); |
| } |
| output_section('.pram_rodata', $mem_lut, $OUT) if defined $param->{PATCH_RAM_OBJ}; |
| output_section('.text', $mem_lut, $OUT); |
| output_section('.rodata', $mem_lut, $OUT); |
| output_section('.data', $mem_lut, $OUT); |
| |
| # Nothing to load because it is loaded from EEPROM/SF at boot. |
| print $OUT "\tspar_irom_data_begin = spar_iram_data_begin;\n"; |
| output_section('.bss', $mem_lut, $OUT); |
| |
| if(!$param->{direct_load}) { |
| # Place the setup area after bss so that when dynamic allocation occurs |
| # after spar setup, it will reclaim the RAM taken up by the setup function. |
| output_section('.setup', $mem_lut, $OUT); |
| } |
| output_section('.aon', $mem_lut, $OUT) if defined $aon_len; |
| output_section('.static_area', $mem_lut, $OUT) if defined $param->{ISTATIC_BEGIN}; |
| output_section('.log_section', $mem_lut, $OUT); |
| print $OUT "}\n"; |
| } |
| |
| sub output_section |
| { |
| my ($name, $lut, $fh, $pre, $post) = @_; |
| my $info = $lut->{$name}; |
| die "Could not find ld table entry for $name\n" if !defined $info; |
| |
| my $align = "ALIGN (4)"; |
| $align = "" if $name eq '.text'; |
| |
| print $fh "\t$name : $align\n\t{\n"; |
| print $fh "\t\tCREATE_OBJECT_SYMBOLS\n"; |
| foreach my $sym (@{$info->{pre}}) { |
| print $fh "\t\t$sym = .;\n"; |
| } |
| foreach my $sect (@{$info->{sections}}) { |
| print $fh "\t\t$sect\n"; |
| } |
| foreach my $sym (@{$info->{post}}) { |
| print $fh "\t\t$sym = .;\n"; |
| } |
| print $fh "\t} >$info->{mem_type}\n"; |
| # print "\n"; |
| } |