From ad6ec0c7fe8b5cd80dff619f1d3b6067db85110a Mon Sep 17 00:00:00 2001 From: Rom Lemarchand Date: Tue, 19 May 2015 16:58:40 -0700 Subject: [PATCH] mkbootimg: turn into a python script Turn mkbootimg into a python script instead of a C utility Change-Id: I36d35dfacfbbef2cc16bd6695ab15ee716bb0cdb --- mkbootimg/Android.mk | 10 ++-- mkbootimg/mkbootimg | 136 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 6 deletions(-) create mode 100755 mkbootimg/mkbootimg diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk index 0c9b0c657..8661d7d6b 100644 --- a/mkbootimg/Android.mk +++ b/mkbootimg/Android.mk @@ -2,12 +2,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := mkbootimg.c -LOCAL_STATIC_LIBRARIES := libmincrypt -LOCAL_CFLAGS := -Werror +LOCAL_SRC_FILES := mkbootimg +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_IS_HOST_MODULE := true LOCAL_MODULE := mkbootimg -include $(BUILD_HOST_EXECUTABLE) - -$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) +include $(BUILD_PREBUILT) diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg new file mode 100755 index 000000000..8c27ff795 --- /dev/null +++ b/mkbootimg/mkbootimg @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# Copyright 2015, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +from sys import argv, exit, stderr +from argparse import ArgumentParser, FileType, Action +from os import fstat +from struct import pack +from hashlib import sha1 + +def filesize(f): + if f is None: + return 0 + try: + return fstat(f.fileno()).st_size + except OSError: + return 0 + + +def update_sha(sha, f): + if f: + sha.update(f.read()) + f.seek(0) + sha.update(pack('I', filesize(f))) + else: + sha.update(pack('I', 0)) + + +def pad_file(f, padding): + pad = (padding - (f.tell() & (padding - 1))) & (padding - 1) + f.write(pack(str(pad) + 'x')) + + +def write_header(args): + BOOT_MAGIC = 'ANDROID!'.encode() + args.output.write(pack('8s', BOOT_MAGIC)) + args.output.write(pack('8I', + filesize(args.kernel), # size in bytes + args.base + args.kernel_offset, # physical load addr + filesize(args.ramdisk), # size in bytes + args.base + args.ramdisk_offset, # physical load addr + filesize(args.second), # size in bytes + args.base + args.second_offset, # physical load addr + args.base + args.tags_offset, # physical addr for kernel tags + args.pagesize)) # flash page size we assume + args.output.write(pack('8x')) # future expansion: should be 0 + args.output.write(pack('16s', args.board.encode())) # asciiz product name + args.output.write(pack('512s', args.cmdline[:512].encode())) + + sha = sha1() + update_sha(sha, args.kernel) + update_sha(sha, args.ramdisk) + update_sha(sha, args.second) + img_id = pack('32s', sha.digest()) + + args.output.write(img_id) + args.output.write(pack('1024s', args.cmdline[512:].encode())) + pad_file(args.output, args.pagesize) + return img_id + + +class ValidateStrLenAction(Action): + def __init__(self, option_strings, dest, nargs=None, **kwargs): + if 'maxlen' not in kwargs: + raise ValueError('maxlen must be set') + self.maxlen = int(kwargs['maxlen']) + del kwargs['maxlen'] + super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + if len(values) > self.maxlen: + raise ValueError('String argument too long: max {0:d}, got {1:d}'. + format(self.maxlen, len(values))) + setattr(namespace, self.dest, values) + + +def write_padded_file(f_out, f_in, padding): + if f_in is None: + return + f_out.write(f_in.read()) + pad_file(f_out, padding) + + +def parse_cmdline(): + parser = ArgumentParser() + parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'), + required=True) + parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb')) + parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb')) + parser.add_argument('--cmdline', help='extra arguments to be passed on the ' + 'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536) + parser.add_argument('--base', help='base address', type=int, default=0x10000000) + parser.add_argument('----kernel_offset', help='kernel offset', type=int, default=0x00008000) + parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=int, default=0x01000000) + parser.add_argument('--second_offset', help='2nd bootloader offset', type=int, + default=0x00f00000) + parser.add_argument('--tags_offset', help='tags offset', type=int, default=0x00000100) + parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction, + maxlen=16) + parser.add_argument('--pagesize', help='page size', type=int, + choices=[2**i for i in range(11,15)], default=2048) + parser.add_argument('--id', help='print the image ID on standard output', + action='store_true') + parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'), + required=True) + return parser.parse_args() + + +def write_data(args): + write_padded_file(args.output, args.kernel, args.pagesize) + write_padded_file(args.output, args.ramdisk, args.pagesize) + write_padded_file(args.output, args.second, args.pagesize) + + +def main(): + args = parse_cmdline() + img_id = write_header(args) + write_data(args) + if args.id: + print('0x' + ''.join('{:02x}'.format(ord(c)) for c in img_id)) + + +if __name__ == '__main__': + main()