rjw | 6c1fd8f | 2022-11-30 14:33:01 +0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # **************************************************************************** |
| 3 | # Copyright Statement: |
| 4 | # -------------------- |
| 5 | # This software is protected by Copyright and the information contained |
| 6 | # herein is confidential. The software may not be copied and the information |
| 7 | # contained herein may not be used or disclosed except with the written |
| 8 | # permission of MediaTek Inc. (C) 2018 |
| 9 | # |
| 10 | # BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| 11 | # THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| 12 | # RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON |
| 13 | # AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
| 14 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
| 15 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
| 16 | # NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
| 17 | # SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
| 18 | # SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH |
| 19 | # THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO |
| 20 | # NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S |
| 21 | # SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. |
| 22 | # |
| 23 | # BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE |
| 24 | # LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
| 25 | # AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
| 26 | # OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO |
| 27 | # MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| 28 | # |
| 29 | # THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE |
| 30 | # WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF |
| 31 | # LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND |
| 32 | # RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER |
| 33 | # THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). |
| 34 | # |
| 35 | # **************************************************************************** |
| 36 | # |
| 37 | # **************************************************************************** |
| 38 | # |
| 39 | # Filename: |
| 40 | # --------- |
| 41 | # mer_codegen.py |
| 42 | # |
| 43 | # Project: |
| 44 | # -------- |
| 45 | # MERTOS |
| 46 | # |
| 47 | # Description: |
| 48 | # ------------ |
| 49 | # Generate the codes required by MERTOS. |
| 50 | # |
| 51 | # |
| 52 | # Author: |
| 53 | # ------- |
| 54 | # Ke-Ting Chen (mtk03141) |
| 55 | # |
| 56 | # **************************************************************************** |
| 57 | |
| 58 | import mer_utility |
| 59 | |
| 60 | import os |
| 61 | import sys |
| 62 | |
| 63 | |
| 64 | def extract_task_info(data_extractor): |
| 65 | """ |
| 66 | Transform syscomp data to internal representation |
| 67 | """ |
| 68 | # typedef struct { |
| 69 | # kal_char *comp_name_ptr; |
| 70 | # kal_char *comp_qname_ptr; |
| 71 | # kal_uint32 comp_priority; |
| 72 | # kal_uint32 comp_stack_size; |
| 73 | # kal_create_func_ptr comp_create_func; |
| 74 | # kal_bool comp_internal_ram_stack; |
| 75 | # kal_uint8 comp_ext_qsize; |
| 76 | # kal_uint8 comp_int_qsize; |
| 77 | # kal_uint8 comp_boot_mode; |
| 78 | # kal_affinity_group comp_affinity_attribute; |
| 79 | # kal_bool comp_affinity_dynamic; |
| 80 | # kal_task_group_id comp_affinity_group_id; |
| 81 | # } comptask_info_struct; |
| 82 | |
| 83 | # Get structure size |
| 84 | affinity_group_size = data_extractor.unpack_symbol_data('I', 'cfg_affinity_group_size')[0] |
| 85 | if affinity_group_size == 1: |
| 86 | struct_format_string = 'IIIIIBBBBBBxxI' |
| 87 | elif affinity_group_size == 2: |
| 88 | struct_format_string = 'IIIIIBBBBHBxI' |
| 89 | else: |
| 90 | assert 0 |
| 91 | field_names = ['name', 'mail_queue_name', 'priority', 'stack_size', 'create_func', |
| 92 | 'is_stack_in_internal_ram', 'mail_queue_size', 'internal_queue_size', |
| 93 | 'boot_mode', 'affinity', 'is_dynamic_affinity', 'affinity_group_id'] |
| 94 | |
| 95 | infos = data_extractor.unpack_symbol_data_struct_array('sys_comp_config_tbl', |
| 96 | struct_format_string, field_names) |
| 97 | |
| 98 | # Get VPE number of MIPS |
| 99 | vpe_num = data_extractor.unpack_symbol_data('I', 'cfg_sys_vpe_num')[0] |
| 100 | |
| 101 | # Get ILM struct size |
| 102 | mail_size = data_extractor.unpack_symbol_data('I', 'cfg_ilm_struct')[0] |
| 103 | |
| 104 | # Tweak the format |
| 105 | infos = [info for info in infos if info['create_func'] != 0xF0F0F0F0] |
| 106 | for info in infos: |
| 107 | if info['name'] == 0: |
| 108 | info['name'] = 'UNKNOWN' |
| 109 | else: |
| 110 | info['name'] = data_extractor.get_string_data(info['name'])[:-1] # Remove ending 0 |
| 111 | |
| 112 | info['priority'] = info['priority'] >> 16 |
| 113 | info['mail_size'] = mail_size |
| 114 | info['entry_func'] = 'kal_mer_task_entry_wrapper' |
| 115 | info['init_func'] = 'mer_kernel_task_default_init' |
| 116 | del info['mail_queue_name'] |
| 117 | del info['create_func'] |
| 118 | del info['internal_queue_size'] |
| 119 | del info['boot_mode'] |
| 120 | del info['is_dynamic_affinity'] |
| 121 | del info['affinity_group_id'] |
| 122 | |
| 123 | if info['stack_size'] % 32 != 0: |
| 124 | info['stack_size'] += (32 - info['stack_size'] % 32) |
| 125 | |
| 126 | assert info['stack_size'] >= 96, ('Stack size should not less than 96 bytes: task ' + |
| 127 | info['name']) |
| 128 | for idx in range(vpe_num): |
| 129 | info = dict() |
| 130 | info['name'] = 'DUMMY_IDLE_LOOP%d' % idx |
| 131 | info['priority'] = 1024+idx |
| 132 | info['mail_size'] = 0 |
| 133 | info['entry_func'] = 'mer_kernel_task_dummy_loop' |
| 134 | info['init_func'] = 'mer_kernel_task_default_init' |
| 135 | info['affinity'] = 2**idx |
| 136 | info['mail_queue_size'] = 0 |
| 137 | info['mail_size'] = 0 |
| 138 | info['stack_size'] = 512 |
| 139 | infos.append(info) |
| 140 | |
| 141 | assert len(infos) <= 256, 'The current total tasks number over 256.\n' |
| 142 | |
| 143 | return infos |
| 144 | |
| 145 | |
| 146 | def write_task_config(infos, config_output_path, priority_output_path): |
| 147 | # Sort by priority |
| 148 | infos.sort(key=lambda x: (x['priority'], -x['affinity'])) |
| 149 | |
| 150 | # To reduce the size of TCB size required in MERTOS, we have to pack the priorities |
| 151 | # Also, we have to put the KAL priority to MERTOS priority mapping in another file |
| 152 | original_priorities = [None] * len(infos) |
| 153 | for index in xrange(len(infos)): |
| 154 | if infos[index]['priority'] < 1024: |
| 155 | original_priorities[index] = infos[index]['priority'] |
| 156 | else: |
| 157 | original_priorities[index] = 0 |
| 158 | |
| 159 | infos[index]['priority'] = index |
| 160 | |
| 161 | # Write task config file |
| 162 | output_info_list = ['name', 'affinity', 'stack_size', 'mail_queue_size', 'mail_size', |
| 163 | 'priority', 'entry_func', 'init_func'] |
| 164 | write_config(infos, output_info_list, 'MER_CONFIG_TASK', config_output_path) |
| 165 | |
| 166 | # Write priority mapping |
| 167 | with open(priority_output_path, 'w') as out_file: |
| 168 | out_file.write(', '.join([str(priority) for priority in original_priorities])) |
| 169 | |
| 170 | |
| 171 | def extract_dpc_info(data_extractor): |
| 172 | """ |
| 173 | Transform syscomp data to internal representation |
| 174 | """ |
| 175 | # typedef struct { |
| 176 | # kal_hisr index; |
| 177 | # kal_uint8 priority; |
| 178 | # kal_uint8 options; |
| 179 | # kal_uint32 stack_size; |
| 180 | # kal_hisr_func_ptr entry_func; |
| 181 | # kal_char *hisr_name; |
| 182 | # kal_affinity_group affinity_attribute; |
| 183 | # kal_bool affinity_dynamic; |
| 184 | # } hisr_parameter_s; |
| 185 | |
| 186 | # Get structure size |
| 187 | affinity_group_size = data_extractor.unpack_symbol_data('I', 'cfg_affinity_group_size')[0] |
| 188 | if affinity_group_size == 1: |
| 189 | struct_format_string = 'BBBxIIIBBxx' |
| 190 | elif affinity_group_size == 2: |
| 191 | struct_format_string = 'BBBxIIIHBx' |
| 192 | else: |
| 193 | assert 0 |
| 194 | field_names = ['index', 'priority', 'options', 'stack_size', 'entry_func', 'name', 'affinity', |
| 195 | 'is_dynamic_affinity'] |
| 196 | infos = data_extractor.unpack_symbol_data_struct_array('hisr_info', |
| 197 | struct_format_string, field_names) |
| 198 | |
| 199 | # Tweak the format |
| 200 | for index, info in zip(xrange(len(infos)), infos): |
| 201 | if info['name'] == 0: |
| 202 | info['name'] == 'UNKNOWN' |
| 203 | else: |
| 204 | info['name'] = data_extractor.get_string_data(info['name'])[:-1] # Remove ending 0 |
| 205 | |
| 206 | assert info['entry_func'], ('Entry function should not be NULL: hisr ' + |
| 207 | info['name']) |
| 208 | info['entry_func'] = data_extractor.get_symbol_name(info['entry_func']) |
| 209 | assert info['entry_func'] != 'SYMBOL_NOT_FOUND' |
| 210 | |
| 211 | del info['options'] |
| 212 | del info['is_dynamic_affinity'] |
| 213 | |
| 214 | if info['stack_size'] % 32 != 0: |
| 215 | info['stack_size'] += (32 - info['stack_size'] % 32) |
| 216 | |
| 217 | assert info['stack_size'] >= 96, ('Stack size should not less than 96 bytes: task ' + |
| 218 | info['name']) |
| 219 | |
| 220 | return infos |
| 221 | |
| 222 | |
| 223 | def write_dpc_config(infos, config_output_path, index_output_path): |
| 224 | # Do not sort by index |
| 225 | # infos.sort(key=lambda x: x['index']) |
| 226 | |
| 227 | # Get the information to map from KAL HISR index to MERTOS DPC index |
| 228 | # Also, we have to put the KAL index to MERTOS index mapping in another file |
| 229 | max_index = max(info['index'] for info in infos) |
| 230 | kal_to_mertos_indices = [max_index] * (max_index + 1) |
| 231 | for index in xrange(len(infos)): |
| 232 | kal_to_mertos_indices[infos[index]['index']] = index |
| 233 | |
| 234 | # Write dpc config file |
| 235 | output_info_list = ['name', 'affinity', 'priority', 'stack_size', 'entry_func'] |
| 236 | write_config(infos, output_info_list, 'MER_CONFIG_DPC', config_output_path) |
| 237 | |
| 238 | # Write index mapping |
| 239 | with open(index_output_path, 'w') as out_file: |
| 240 | out_file.write(', '.join([str(index) for index in kal_to_mertos_indices])) |
| 241 | |
| 242 | |
| 243 | def extract_fixmem_info(data_extractor): |
| 244 | """ |
| 245 | Transform syscomp data to internal representation |
| 246 | """ |
| 247 | # First parse control buffer |
| 248 | # typedef struct |
| 249 | # { |
| 250 | # kal_uint32 buf_size; |
| 251 | # kal_uint16 buf_num; |
| 252 | # } buffer_size_s; |
| 253 | struct_format_string = 'IHxx' |
| 254 | field_names = ['size', 'number'] |
| 255 | infos = data_extractor.unpack_symbol_data_struct_array('cfg_ctrl_buff', |
| 256 | struct_format_string, field_names) |
| 257 | |
| 258 | # Get control buffer overhead for each block |
| 259 | control_buffer_total_overhead = data_extractor.unpack_symbol_data('I', 'cfg_ctrl_buff_overhead')[0] |
| 260 | |
| 261 | # Get control buffer OS overhead for each block |
| 262 | control_buffer_os_overhead = data_extractor.unpack_symbol_data('I', 'cfg_os_buff_overhead')[0] |
| 263 | |
| 264 | # Before KAL refactoring cfg_event_buff is controlled by MERTOS |
| 265 | # That is, we don't need to know the certain pool_id of memory buffer from header |
| 266 | # It must be evshed_pool_id |
| 267 | # However, KAL refactoring gather the porting layer from each OS |
| 268 | # and use the common level API(kal_os_allocate_buffer/kal_os_deallocate_buffer) to allocate/free memory |
| 269 | |
| 270 | |
| 271 | # Add the overhead to each control buffer, this buffer is for user, apply total overhead(header/footer) |
| 272 | for entry in infos: |
| 273 | entry['size'] += control_buffer_total_overhead |
| 274 | entry['type'] = 'fixmem' |
| 275 | |
| 276 | # Get event scheduler buffer requirement |
| 277 | event_scheduler_infos = data_extractor.unpack_symbol_data_struct_array( |
| 278 | 'cfg_event_buff', struct_format_string, field_names) |
| 279 | |
| 280 | # Add the overhead to each control buffer, this buffer is for OS, apply only the OS overhead |
| 281 | for entry in event_scheduler_infos: |
| 282 | entry['size'] += control_buffer_os_overhead |
| 283 | entry['type'] = 'event' |
| 284 | |
| 285 | infos.extend(event_scheduler_infos) |
| 286 | |
| 287 | return infos |
| 288 | |
| 289 | |
| 290 | def write_fixmem_config(infos, config_output_path): |
| 291 | # Write dpc config file |
| 292 | output_info_list = ['type', 'size', 'number'] |
| 293 | write_config(infos, output_info_list, 'MER_SERVICE_CONFIG_FIXMEM', config_output_path) |
| 294 | |
| 295 | |
| 296 | def write_mutex_semaphore_config(mutex_number, semaphore_number, config_output_path): |
| 297 | output_info_list = ['name', 'count'] |
| 298 | infos = list({output_info_list[0]: 'M{0}'.format(index), output_info_list[1]: 1} |
| 299 | for index in xrange(mutex_number - 1)) |
| 300 | infos.append({output_info_list[0]: 'LAST_MUTEX', output_info_list[1]: 1}) |
| 301 | infos.extend(list({output_info_list[0]: 'S{0}'.format(index), output_info_list[1]: 1} |
| 302 | for index in xrange(semaphore_number))) |
| 303 | write_config(infos, output_info_list, 'MER_SERVICE_CONFIG_SEMAPHORE', config_output_path) |
| 304 | |
| 305 | |
| 306 | def write_enhmutex_config(number, config_output_path): |
| 307 | output_info_list = ['name'] |
| 308 | infos = list({output_info_list[0]: index} for index in xrange(number)) |
| 309 | write_config(infos, output_info_list, 'MER_SERVICE_CONFIG_SYNC_ENHMUTEX', config_output_path) |
| 310 | |
| 311 | |
| 312 | def write_event_group_config(number, config_output_path): |
| 313 | output_info_list = ['name'] |
| 314 | infos = list({output_info_list[0]: index} for index in xrange(number)) |
| 315 | write_config(infos, output_info_list, 'MER_SERVICE_CONFIG_EVENT_GROUP', config_output_path) |
| 316 | |
| 317 | |
| 318 | def write_config(infos, column_names, row_name, output_path): |
| 319 | def merge_dicts(a, b): |
| 320 | c = a.copy() |
| 321 | c.update(b) |
| 322 | return c |
| 323 | |
| 324 | column_width = {} |
| 325 | for name in column_names: |
| 326 | column_width[name + '_width'] = max(len(name), max(len(str(info[name])) for info in infos)) |
| 327 | output_format = ', '.join('{{{0}:{{{0}_width}}}}'.format(name) for name in column_names) |
| 328 | |
| 329 | # Write config file |
| 330 | with open(output_path, 'w') as out_file: |
| 331 | #Guard header |
| 332 | out_file.write('#if !defined(__MER_CONFIG_MUST_REBUILD__)\n') |
| 333 | out_file.write(' #error "should not include this file since this module is library release or binary release"\n') |
| 334 | out_file.write('#endif\n') |
| 335 | # Write info comment line |
| 336 | column_name_dict = {name: name for name in column_names} |
| 337 | out_file.write('/*' + ' ' * (len(row_name) - 2 + 1) + output_format.format( |
| 338 | **merge_dicts(column_name_dict, column_width)) + '*/\n') |
| 339 | for info in infos: |
| 340 | out_file.write('{0}('.format(row_name) + output_format.format( |
| 341 | **merge_dicts(info, column_width)) + ')\n') |
| 342 | |
| 343 | |
| 344 | def main(argv): |
| 345 | def get_config_output_path(filename): |
| 346 | return os.path.join(task_config_output_folder, filename) |
| 347 | |
| 348 | readelf_exec = argv[1] |
| 349 | elf_path = argv[2] |
| 350 | task_config_output_folder = argv[3] |
| 351 | |
| 352 | data_extractor = mer_utility.ElfDataExtractor(readelf_exec, elf_path) |
| 353 | task_infos = extract_task_info(data_extractor) |
| 354 | dpc_infos = extract_dpc_info(data_extractor) |
| 355 | fixmem_infos = extract_fixmem_info(data_extractor) |
| 356 | |
| 357 | write_task_config(task_infos, |
| 358 | get_config_output_path('kal_mertos_config_task.inc'), |
| 359 | get_config_output_path('kal_mertos_config_task_priority_mapping.inc')) |
| 360 | write_dpc_config(dpc_infos, |
| 361 | get_config_output_path('kal_mertos_config_dpc.inc'), |
| 362 | get_config_output_path('kal_mertos_config_dpc_index_mapping.inc')) |
| 363 | write_fixmem_config(fixmem_infos, |
| 364 | get_config_output_path('kal_mertos_config_fixmem.inc')) |
| 365 | |
| 366 | |
| 367 | if __name__ == '__main__': |
| 368 | main(sys.argv) |