blob: d09ecabd49a293313eb3f4b397bad0380c41d5d4 [file] [log] [blame]
rjw6c1fd8f2022-11-30 14:33:01 +08001#!/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
58import mer_utility
59
60import os
61import sys
62
63
64def 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
146def 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
171def 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
223def 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
243def 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
290def 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
296def 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
306def 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
312def 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
318def 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
344def 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
367if __name__ == '__main__':
368 main(sys.argv)