1*4882a593Smuzhiyun#!/usr/bin/env python2 2*4882a593Smuzhiyun""" 3*4882a593SmuzhiyunA script to generate FIT image source for rockchip boards 4*4882a593Smuzhiyunwith ARM Trusted Firmware 5*4882a593Smuzhiyunand multiple device trees (given on the command line) 6*4882a593Smuzhiyun 7*4882a593Smuzhiyunusage: $0 <dt_name> [<dt_name> [<dt_name] ...] 8*4882a593Smuzhiyun""" 9*4882a593Smuzhiyun 10*4882a593Smuzhiyunimport os 11*4882a593Smuzhiyunimport sys 12*4882a593Smuzhiyunimport getopt 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun# pip install pyelftools 15*4882a593Smuzhiyunfrom elftools.elf.elffile import ELFFile 16*4882a593Smuzhiyunfrom elftools.elf.sections import SymbolTableSection 17*4882a593Smuzhiyunfrom elftools.elf.segments import Segment, InterpSegment, NoteSegment 18*4882a593Smuzhiyun 19*4882a593SmuzhiyunELF_SEG_P_TYPE='p_type' 20*4882a593SmuzhiyunELF_SEG_P_PADDR='p_paddr' 21*4882a593SmuzhiyunELF_SEG_P_VADDR='p_vaddr' 22*4882a593SmuzhiyunELF_SEG_P_OFFSET='p_offset' 23*4882a593SmuzhiyunELF_SEG_P_FILESZ='p_filesz' 24*4882a593SmuzhiyunELF_SEG_P_MEMSZ='p_memsz' 25*4882a593Smuzhiyun 26*4882a593SmuzhiyunDT_HEADER="""/* 27*4882a593Smuzhiyun * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd 28*4882a593Smuzhiyun * 29*4882a593Smuzhiyun * Minimal dts for a SPL FIT image payload. 30*4882a593Smuzhiyun * 31*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+ X11 32*4882a593Smuzhiyun */ 33*4882a593Smuzhiyun/dts-v1/; 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun/ { 36*4882a593Smuzhiyun description = "Configuration to load ATF before U-Boot"; 37*4882a593Smuzhiyun #address-cells = <1>; 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun images { 40*4882a593Smuzhiyun uboot { 41*4882a593Smuzhiyun description = "U-Boot (64-bit)"; 42*4882a593Smuzhiyun data = /incbin/("u-boot-nodtb.bin"); 43*4882a593Smuzhiyun type = "standalone"; 44*4882a593Smuzhiyun os = "U-Boot"; 45*4882a593Smuzhiyun arch = "arm64"; 46*4882a593Smuzhiyun compression = "none"; 47*4882a593Smuzhiyun load = <0x%08x>; 48*4882a593Smuzhiyun hash { 49*4882a593Smuzhiyun algo = "sha256"; 50*4882a593Smuzhiyun }; 51*4882a593Smuzhiyun }; 52*4882a593Smuzhiyun""" 53*4882a593Smuzhiyun 54*4882a593SmuzhiyunDT_IMAGES_NODE_END=""" 55*4882a593Smuzhiyun }; 56*4882a593Smuzhiyun""" 57*4882a593Smuzhiyun 58*4882a593SmuzhiyunDT_END=""" 59*4882a593Smuzhiyun}; 60*4882a593Smuzhiyun""" 61*4882a593Smuzhiyun 62*4882a593Smuzhiyundef append_atf_node(file, atf_index, phy_addr): 63*4882a593Smuzhiyun """ 64*4882a593Smuzhiyun Append ATF DT node to input FIT dts file. 65*4882a593Smuzhiyun """ 66*4882a593Smuzhiyun data = 'bl31_0x%08x.bin' % phy_addr 67*4882a593Smuzhiyun print >> file, '\t\tatf@%d {' % atf_index 68*4882a593Smuzhiyun print >> file, '\t\t\tdescription = \"ARM Trusted Firmware\";' 69*4882a593Smuzhiyun print >> file, '\t\t\tdata = /incbin/("%s");' % data 70*4882a593Smuzhiyun print >> file, '\t\t\ttype = "firmware";' 71*4882a593Smuzhiyun print >> file, '\t\t\tarch = "arm64";' 72*4882a593Smuzhiyun print >> file, '\t\t\tos = "arm-trusted-firmware";' 73*4882a593Smuzhiyun print >> file, '\t\t\tcompression = "none";' 74*4882a593Smuzhiyun print >> file, '\t\t\tload = <0x%08x>;' % phy_addr 75*4882a593Smuzhiyun if atf_index == 1: 76*4882a593Smuzhiyun print >> file, '\t\t\tentry = <0x%08x>;' % phy_addr 77*4882a593Smuzhiyun print >> file, '\t\t\thash {' 78*4882a593Smuzhiyun print >> file, '\t\t\t\talgo = "sha256";' 79*4882a593Smuzhiyun print >> file, '\t\t\t};' 80*4882a593Smuzhiyun print >> file, '\t\t};' 81*4882a593Smuzhiyun print >> file, '' 82*4882a593Smuzhiyun 83*4882a593Smuzhiyundef append_fdt_node(file, dtbs): 84*4882a593Smuzhiyun """ 85*4882a593Smuzhiyun Append FDT nodes. 86*4882a593Smuzhiyun """ 87*4882a593Smuzhiyun cnt = 1 88*4882a593Smuzhiyun for dtb in dtbs: 89*4882a593Smuzhiyun dtname = os.path.basename(dtb) 90*4882a593Smuzhiyun print >> file, '\t\tfdt {' 91*4882a593Smuzhiyun print >> file, '\t\t\tdescription = "U-Boot device tree blob";' 92*4882a593Smuzhiyun print >> file, '\t\t\tdata = /incbin/("u-boot.dtb");' 93*4882a593Smuzhiyun print >> file, '\t\t\ttype = "flat_dt";' 94*4882a593Smuzhiyun print >> file, '\t\t\tarch = "arm64";' 95*4882a593Smuzhiyun print >> file, '\t\t\tcompression = "none";' 96*4882a593Smuzhiyun print >> file, '\t\t\thash {' 97*4882a593Smuzhiyun print >> file, '\t\t\t\talgo = "sha256";' 98*4882a593Smuzhiyun print >> file, '\t\t\t};' 99*4882a593Smuzhiyun print >> file, '\t\t};' 100*4882a593Smuzhiyun print >> file, '' 101*4882a593Smuzhiyun cnt = cnt + 1 102*4882a593Smuzhiyun 103*4882a593Smuzhiyundef append_conf_section(file, cnt, dtname, atf_cnt): 104*4882a593Smuzhiyun print >> file, '\t\tconfig {' 105*4882a593Smuzhiyun print >> file, '\t\t\tdescription = "Rockchip armv8 with ATF";' 106*4882a593Smuzhiyun print >> file, '\t\t\trollback-index = <0x0>;' 107*4882a593Smuzhiyun print >> file, '\t\t\tfirmware = "atf@1";' 108*4882a593Smuzhiyun print >> file, '\t\t\tloadables = "uboot",', 109*4882a593Smuzhiyun for i in range(1, atf_cnt): 110*4882a593Smuzhiyun print >> file, '"atf@%d"' % (i+1), 111*4882a593Smuzhiyun if i != (atf_cnt - 1): 112*4882a593Smuzhiyun print >> file, ',', 113*4882a593Smuzhiyun else: 114*4882a593Smuzhiyun print >> file, ';' 115*4882a593Smuzhiyun print >> file, '\t\t\tfdt = "fdt";' 116*4882a593Smuzhiyun print >> file, '\t\t\tsignature {' 117*4882a593Smuzhiyun print >> file, '\t\t\t\talgo = "sha256,rsa2048";' 118*4882a593Smuzhiyun print >> file, '\t\t\t\tpadding = "pss";' 119*4882a593Smuzhiyun print >> file, '\t\t\t\tkey-name-hint = "dev";' 120*4882a593Smuzhiyun print >> file, '\t\t\t\tsign-images = "fdt", "firmware", "loadables";' 121*4882a593Smuzhiyun print >> file, '\t\t\t};' 122*4882a593Smuzhiyun print >> file, '\t\t};' 123*4882a593Smuzhiyun print >> file, '' 124*4882a593Smuzhiyun 125*4882a593Smuzhiyundef append_conf_node(file, dtbs, atf_cnt): 126*4882a593Smuzhiyun """ 127*4882a593Smuzhiyun Append configeration nodes. 128*4882a593Smuzhiyun """ 129*4882a593Smuzhiyun cnt = 1 130*4882a593Smuzhiyun print >> file, '\tconfigurations {' 131*4882a593Smuzhiyun print >> file, '\t\tdefault = "config";' 132*4882a593Smuzhiyun for dtb in dtbs: 133*4882a593Smuzhiyun dtname = os.path.basename(dtb) 134*4882a593Smuzhiyun append_conf_section(file, cnt, dtname, atf_cnt) 135*4882a593Smuzhiyun cnt = cnt + 1 136*4882a593Smuzhiyun print >> file, '\t};' 137*4882a593Smuzhiyun print >> file, '' 138*4882a593Smuzhiyun 139*4882a593Smuzhiyundef generate_atf_fit_dts(fit_file_name, bl31_file_name, uboot_file_name, dtbs_file_name): 140*4882a593Smuzhiyun """ 141*4882a593Smuzhiyun Generate FIT script for ATF image. 142*4882a593Smuzhiyun """ 143*4882a593Smuzhiyun if fit_file_name != sys.stdout: 144*4882a593Smuzhiyun fit_file = open(fit_file_name, "wb") 145*4882a593Smuzhiyun else: 146*4882a593Smuzhiyun fit_file = sys.stdout 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun num_load_seg = 0 149*4882a593Smuzhiyun p_paddr = 0xFFFFFFFF 150*4882a593Smuzhiyun with open(uboot_file_name) as uboot_file: 151*4882a593Smuzhiyun uboot = ELFFile(uboot_file) 152*4882a593Smuzhiyun for i in range(uboot.num_segments()): 153*4882a593Smuzhiyun seg = uboot.get_segment(i) 154*4882a593Smuzhiyun if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)): 155*4882a593Smuzhiyun p_paddr = seg.__getitem__(ELF_SEG_P_PADDR) 156*4882a593Smuzhiyun num_load_seg = num_load_seg + 1 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1) 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun print >> fit_file, DT_HEADER % p_paddr 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun with open(bl31_file_name) as bl31_file: 163*4882a593Smuzhiyun bl31 = ELFFile(bl31_file) 164*4882a593Smuzhiyun for i in range(bl31.num_segments()): 165*4882a593Smuzhiyun seg = bl31.get_segment(i) 166*4882a593Smuzhiyun if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)): 167*4882a593Smuzhiyun paddr = seg.__getitem__(ELF_SEG_P_PADDR) 168*4882a593Smuzhiyun p= seg.__getitem__(ELF_SEG_P_PADDR) 169*4882a593Smuzhiyun append_atf_node(fit_file, i+1, paddr) 170*4882a593Smuzhiyun atf_cnt = i+1 171*4882a593Smuzhiyun append_fdt_node(fit_file, dtbs_file_name) 172*4882a593Smuzhiyun print >> fit_file, '%s' % DT_IMAGES_NODE_END 173*4882a593Smuzhiyun append_conf_node(fit_file, dtbs_file_name, atf_cnt) 174*4882a593Smuzhiyun print >> fit_file, '%s' % DT_END 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun if fit_file_name != sys.stdout: 177*4882a593Smuzhiyun fit_file.close() 178*4882a593Smuzhiyun 179*4882a593Smuzhiyundef generate_atf_binary(bl31_file_name): 180*4882a593Smuzhiyun with open(bl31_file_name) as bl31_file: 181*4882a593Smuzhiyun bl31 = ELFFile(bl31_file) 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun num = bl31.num_segments() 184*4882a593Smuzhiyun for i in range(num): 185*4882a593Smuzhiyun seg = bl31.get_segment(i) 186*4882a593Smuzhiyun if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)): 187*4882a593Smuzhiyun paddr = seg.__getitem__(ELF_SEG_P_PADDR) 188*4882a593Smuzhiyun file_name = 'bl31_0x%08x.bin' % paddr 189*4882a593Smuzhiyun with open(file_name, "wb") as atf: 190*4882a593Smuzhiyun atf.write(seg.data()); 191*4882a593Smuzhiyun 192*4882a593Smuzhiyundef get_bl31_segments_info(bl31_file_name): 193*4882a593Smuzhiyun """ 194*4882a593Smuzhiyun Get load offset, physical offset, file size 195*4882a593Smuzhiyun from bl31 elf file program headers. 196*4882a593Smuzhiyun """ 197*4882a593Smuzhiyun with open(bl31_file_name) as bl31_file: 198*4882a593Smuzhiyun bl31 = ELFFile(bl31_file) 199*4882a593Smuzhiyun 200*4882a593Smuzhiyun num = bl31.num_segments() 201*4882a593Smuzhiyun print 'Number of Segments : %d' % bl31.num_segments() 202*4882a593Smuzhiyun for i in range(num): 203*4882a593Smuzhiyun print 'Segment %d' % i 204*4882a593Smuzhiyun seg = bl31.get_segment(i) 205*4882a593Smuzhiyun ptype = seg[ELF_SEG_P_TYPE] 206*4882a593Smuzhiyun poffset = seg[ELF_SEG_P_OFFSET] 207*4882a593Smuzhiyun pmemsz = seg[ELF_SEG_P_MEMSZ] 208*4882a593Smuzhiyun pfilesz = seg[ELF_SEG_P_FILESZ] 209*4882a593Smuzhiyun print 'type: %s\nfilesz: %08x\nmemsz: %08x\noffset: %08x' % (ptype, pfilesz, pmemsz, poffset) 210*4882a593Smuzhiyun paddr = seg[ELF_SEG_P_PADDR] 211*4882a593Smuzhiyun print 'paddr: %08x' % paddr 212*4882a593Smuzhiyun 213*4882a593Smuzhiyundef main(): 214*4882a593Smuzhiyun uboot_elf="./u-boot" 215*4882a593Smuzhiyun bl31_elf="./bl31.elf" 216*4882a593Smuzhiyun FIT_ITS=sys.stdout 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun opts, args = getopt.getopt(sys.argv[1:], "o:u:b:h") 219*4882a593Smuzhiyun for opt, val in opts: 220*4882a593Smuzhiyun if opt == "-o": 221*4882a593Smuzhiyun FIT_ITS=val 222*4882a593Smuzhiyun elif opt == "-u": 223*4882a593Smuzhiyun uboot_elf=val 224*4882a593Smuzhiyun elif opt == "-b": 225*4882a593Smuzhiyun bl31_elf=val 226*4882a593Smuzhiyun elif opt == "-h": 227*4882a593Smuzhiyun print __doc__ 228*4882a593Smuzhiyun sys.exit(2) 229*4882a593Smuzhiyun 230*4882a593Smuzhiyun dtbs = args 231*4882a593Smuzhiyun #get_bl31_segments_info("u-boot") 232*4882a593Smuzhiyun #get_bl31_segments_info("bl31.elf") 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun generate_atf_fit_dts(FIT_ITS, bl31_elf, uboot_elf, dtbs) 235*4882a593Smuzhiyun generate_atf_binary(bl31_elf); 236*4882a593Smuzhiyun 237*4882a593Smuzhiyunif __name__ == "__main__": 238*4882a593Smuzhiyun main() 239