1 | # coding: utf-8
|
---|
2 | #
|
---|
3 | # TECS Generator
|
---|
4 | # Generator for TOPPERS Embedded Component System
|
---|
5 | #
|
---|
6 | # Copyright (C) 2008-2018 by TOPPERS Project
|
---|
7 | #--
|
---|
8 | # 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
|
---|
9 | # ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
|
---|
10 | # 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
|
---|
11 | # (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
|
---|
12 | # 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
|
---|
13 | # スコード中に含まれていること.
|
---|
14 | # (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
|
---|
15 | # 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
|
---|
16 | # 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
|
---|
17 | # の無保証規定を掲載すること.
|
---|
18 | # (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
|
---|
19 | # 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
|
---|
20 | # と.
|
---|
21 | # (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
|
---|
22 | # 作権表示,この利用条件および下記の無保証規定を掲載すること.
|
---|
23 | # (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
|
---|
24 | # 報告すること.
|
---|
25 | # (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
|
---|
26 | # 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
|
---|
27 | # また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
|
---|
28 | # 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
|
---|
29 | # 免責すること.
|
---|
30 | #
|
---|
31 | # 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
|
---|
32 | # よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
|
---|
33 | # に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
|
---|
34 | # アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
|
---|
35 | # の責任を負わない.
|
---|
36 | #
|
---|
37 | # $Id$
|
---|
38 | #++
|
---|
39 |
|
---|
40 | # mikan through plugin: namespace が考慮されていない
|
---|
41 | # これを利用する場合、以下のように toppers_jsp.cdl sChannel.cdl を指定する必要がある
|
---|
42 | # tecsgen toppers_jsp.cdl sChannel.cdl your_description.cdl
|
---|
43 |
|
---|
44 | # 以下を仮定(制限事項)
|
---|
45 | # 呼び元、呼び先のエンディアン、char, short, int_t, long_t, intptr_t のサイズが同じ
|
---|
46 | # 有符号、無符号でサイズが同じ
|
---|
47 |
|
---|
48 | class SVCManage
|
---|
49 | #
|
---|
50 | # @@id: TECSのプラグインで生成した拡張サービスコールに割り当てるid
|
---|
51 | # 実際の拡張サービスコールIDは,TFN_TECSGEN_ORIGINで下駄を
|
---|
52 | # 履かせた値となる
|
---|
53 | # TFN_TECSGEN_ORIGINは,hrp3/include/extsvc_fncode.h で定義
|
---|
54 | # される
|
---|
55 | # @@func_ids: 拡張サービスコールの関数名と拡張サービスコールIDを
|
---|
56 | # 対応づけるハッシュ
|
---|
57 | #
|
---|
58 | @@id = 0
|
---|
59 | @@func_ids = {}
|
---|
60 | def initialize()
|
---|
61 | #
|
---|
62 | # 本クラスはインスタンスを持たない仮想的なクラスである
|
---|
63 | #
|
---|
64 | raise "class #{self.class.name} shall not have instances"
|
---|
65 | end
|
---|
66 | def self.get_func_id func_name
|
---|
67 | return @@func_ids[ func_name ]
|
---|
68 | end
|
---|
69 | def self.set_func_id func_name
|
---|
70 | @@func_ids[ func_name ] = self.assign_id
|
---|
71 | # puts @@func_ids[ func_name ]
|
---|
72 | end
|
---|
73 | def self.get_id
|
---|
74 | return @@id
|
---|
75 | end
|
---|
76 | def self.set_id id
|
---|
77 | @@id = id
|
---|
78 | end
|
---|
79 | def self.assign_id
|
---|
80 | assignedId = @@id
|
---|
81 | @@id += 1
|
---|
82 | return assignedId
|
---|
83 | end
|
---|
84 | end
|
---|
85 |
|
---|
86 | #
|
---|
87 | # 拡張サービスコールを用いたドメイン間通信の
|
---|
88 | # throughプラグイン
|
---|
89 | # HRPドメインプラグインによって挿入される
|
---|
90 | # 前提条件: 呼出し先がカーネルオブジェクトかどうかの判定はHRPドメインプラグイン
|
---|
91 | # で実施されるため,ここでは判定しないこととした
|
---|
92 | #
|
---|
93 | class HRPSVCPlugin < ThroughPlugin
|
---|
94 |
|
---|
95 | NUM_SVC_ARG_MAX = 5 # HRP3 の拡張サービスコールで扱うことのできる引数の最大個数
|
---|
96 |
|
---|
97 | @@generated_celltype ={} # セルタイプの重複排除用
|
---|
98 | @@generated_cell = {} # セルの重複排除用
|
---|
99 |
|
---|
100 | def initialize( cell_name, plugin_arg, next_cell, next_cell_port_name, next_cell_port_subscript, signature, celltype, caller_cell )
|
---|
101 | super
|
---|
102 |
|
---|
103 | # 受け口配列の場合、配列添数ごとに別のセルタイプとする
|
---|
104 | # セルタイプをシングルトン化したいため。
|
---|
105 | # さもないと、セルを識別する引数を渡す必要があり、NUM_SVC_ARG_MAX(5) つしか渡せない引数の一つを消費することになるため。
|
---|
106 | if @next_cell_port_subscript then
|
---|
107 | subscript = "__" + @next_cell_port_subscript.to_s
|
---|
108 | else
|
---|
109 | subscript = ""
|
---|
110 | end
|
---|
111 | @ct_name_body = "#{@ct_name}SVCBody_#{@next_cell.get_name}_#{@next_cell_port_name}#{subscript}".to_sym
|
---|
112 | @ct_name = "#{@ct_name}SVCCaller_#{@next_cell.get_name}_#{@next_cell_port_name}#{subscript}".to_sym
|
---|
113 | @cell_name_body = "#{@cell_name}SVCBody".to_sym
|
---|
114 | @cell_name = "#{@cell_name}SVCCaller".to_sym
|
---|
115 | # puts "%%%% "
|
---|
116 | # p @next_cell.get_name
|
---|
117 | # p @caller_cell.get_name
|
---|
118 | @b_printed_include_stdint = false
|
---|
119 | check_signature signature
|
---|
120 | end
|
---|
121 |
|
---|
122 | #=== NamespacePath を得る
|
---|
123 | # 生成するセルの namespace path を生成する
|
---|
124 | def get_cell_namespace_path
|
---|
125 | # nsp = @region.get_namespace.get_namespace_path
|
---|
126 | nsp = @start_region.get_namespace_path
|
---|
127 | return nsp.append( @cell_name )
|
---|
128 | end
|
---|
129 |
|
---|
130 | def gen_plugin_decl_code( file )
|
---|
131 |
|
---|
132 | # このセルタイプ(同じシグニチャ)は既に生成されているか?
|
---|
133 | if @@generated_celltype[ @ct_name_body ] == nil then
|
---|
134 | @@generated_celltype[ @ct_name_body ] = [ self ]
|
---|
135 | file2 = CFile.open( "#{$gen}/#{@ct_name_body}.cdl", "w" )
|
---|
136 | file2.print <<EOT
|
---|
137 | import_C( "t_stdlib.h" );
|
---|
138 |
|
---|
139 | /* HRPSVC0001 */
|
---|
140 | [active,singleton]
|
---|
141 | celltype #{@ct_name_body} {
|
---|
142 | call #{@signature.get_name} #{@call_port_name};
|
---|
143 | FACTORY {
|
---|
144 | write("$ct$_tecsgen.h", "#include \\"kernel_cfg.h\\"");
|
---|
145 | };
|
---|
146 | };
|
---|
147 | EOT
|
---|
148 | file2.close
|
---|
149 | else
|
---|
150 | @@generated_celltype[ @ct_name_body ] << self
|
---|
151 | end
|
---|
152 | file.print "import( \"#{$gen}/#{@ct_name_body}.cdl\" );\n"
|
---|
153 |
|
---|
154 | # このセルタイプ(同じシグニチャ)は既に生成されているか?
|
---|
155 | if @@generated_celltype[ @ct_name ] == nil then
|
---|
156 | @@generated_celltype[ @ct_name ] = [ self ]
|
---|
157 | file2 = CFile.open( "#{$gen}/#{@ct_name}.cdl", "w" )
|
---|
158 | file2.print <<EOT
|
---|
159 | /* HRPSVC0002 */
|
---|
160 | celltype #{@ct_name} {
|
---|
161 | entry #{@signature.get_name} #{@entry_port_name};
|
---|
162 | FACTORY {
|
---|
163 | write("$ct$_tecsgen.h", "#include \\"extsvc_fncode.h\\"");
|
---|
164 | };
|
---|
165 | };
|
---|
166 | EOT
|
---|
167 | file2.close
|
---|
168 | else
|
---|
169 | @@generated_celltype[ @ct_name ] << self
|
---|
170 | end
|
---|
171 | file.print "import( \"#{$gen}/#{@ct_name}.cdl\" );\n"
|
---|
172 |
|
---|
173 | =begin
|
---|
174 | # TODO: send. receive 対応
|
---|
175 | send_receive = []
|
---|
176 | if @signature != nil then
|
---|
177 | @signature.each_param{ |fd,param|
|
---|
178 | dir =param.get_direction
|
---|
179 | case dir
|
---|
180 | when :SEND, :RECEIVE
|
---|
181 | send_receive << [ dir, fd, param ]
|
---|
182 | end
|
---|
183 | }
|
---|
184 | end
|
---|
185 | =end
|
---|
186 |
|
---|
187 | =begin
|
---|
188 | composite #{@ct_name} {
|
---|
189 | entry #{@signature.get_name} #{@entry_port_name};
|
---|
190 | call #{@signature.get_name} #{@call_port_name};
|
---|
191 |
|
---|
192 | cell #{@ct_name}Client #{@cell_name}Client{
|
---|
193 | };
|
---|
194 |
|
---|
195 | [active]
|
---|
196 | cell #{@ct_name}Server #{@cell_name}Server{
|
---|
197 | #{@call_port_name} => composite.#{@call_port_name};
|
---|
198 | };
|
---|
199 |
|
---|
200 | composite.#{@entry_port_name} => #{@cell_name}.#{@entry_port_name};
|
---|
201 | };
|
---|
202 | =end
|
---|
203 |
|
---|
204 | end
|
---|
205 |
|
---|
206 | #=== through cell コードを生成
|
---|
207 | #
|
---|
208 | #
|
---|
209 | def gen_through_cell_code( file )
|
---|
210 |
|
---|
211 | # gen_plugin_decl_code( file ) this is called from super.
|
---|
212 |
|
---|
213 | # セルを探す
|
---|
214 | # path =["::",@next_cell.get_name] # mikan namespace
|
---|
215 | # cell = Namespace.find( path )
|
---|
216 | # cell = Namespace.find( @next_cell.get_namespace_path )
|
---|
217 |
|
---|
218 | ##### クライアント側のセルの生成 #####
|
---|
219 | # file.print "[domain(HRP, \"kernel\")]"
|
---|
220 | nest = @start_region.gen_region_str_pre file
|
---|
221 | nest_str = " " * nest
|
---|
222 |
|
---|
223 | # クライアント側チャンネルの生成
|
---|
224 | # 拡張サービスコール呼出し
|
---|
225 | file.print <<EOT
|
---|
226 | /* HRPSVC0003 */
|
---|
227 | #{nest_str} // Client Side Channel
|
---|
228 | #{nest_str} cell #{@ct_name} #{@cell_name}{
|
---|
229 | #{nest_str} };
|
---|
230 |
|
---|
231 | EOT
|
---|
232 |
|
---|
233 | @start_region.gen_region_str_post file
|
---|
234 | file.print "\n\n"
|
---|
235 |
|
---|
236 | ##### サーバー側のセルの生成 #####
|
---|
237 | # print "###### #{@cell_name_body} ... #{@ct_name_body} #{@@generated_cell[ @ct_name_body ].class} #####\n"
|
---|
238 |
|
---|
239 | if @@generated_cell[ @ct_name_body ] then
|
---|
240 | file.print "/* cell #{@ct_name_body} #{@@generated_cell[ @ct_name_body ]}: already generated. */\n"
|
---|
241 | else
|
---|
242 | @@generated_cell[ @ct_name_body ] = @cell_name_body
|
---|
243 | nest = @end_region.gen_region_str_pre file
|
---|
244 | nest_str = " " * nest
|
---|
245 | if @next_cell_port_subscript then
|
---|
246 | subscript = '[' + @next_cell_port_subscript.to_s + ']'
|
---|
247 | else
|
---|
248 | subscript = ""
|
---|
249 | end
|
---|
250 |
|
---|
251 | # サーバー側チャンネルの生成
|
---|
252 | # 拡張サービスコール本体
|
---|
253 | file.print <<EOT
|
---|
254 |
|
---|
255 | /* HRPSVC0004 */
|
---|
256 | #{nest_str} // Server Side Channel
|
---|
257 | #{nest_str} cell #{@ct_name_body} #{@cell_name_body}{
|
---|
258 | #{nest_str} #{@call_port_name} = #{@next_cell.get_namespace_path.get_path_str}.#{@next_cell_port_name}#{subscript};
|
---|
259 | #{nest_str} };
|
---|
260 | EOT
|
---|
261 |
|
---|
262 | @end_region.gen_region_str_post file
|
---|
263 |
|
---|
264 | file2 = AppFile.open( "#{$gen}/tecsgen.cfg" )
|
---|
265 | file2.print "\n/* Generated by HRPSVCPlugin */\n\n"
|
---|
266 | file2.print <<EOT
|
---|
267 | /* HRPSVC0005 */
|
---|
268 | #include "#{@ct_name_body}_factory.h"
|
---|
269 | EOT
|
---|
270 | file2.close
|
---|
271 |
|
---|
272 | # callee_cell のget_restricted_regions を呼び出しておく
|
---|
273 | # restrict が参照された印をつけるため
|
---|
274 | @callee_cell.get_restricted_regions( :dummy_entry_name, :dummy_func_name )
|
---|
275 | end
|
---|
276 | end
|
---|
277 |
|
---|
278 | #=== 受け口関数の本体(C言語)を生成する
|
---|
279 | # 通常であれば、ジェネレータは受け口関数のテンプレートを生成する
|
---|
280 | # プラグインの場合、変更する必要のないセルタイプコードを生成する
|
---|
281 | #file:: FILE 出力先ファイル
|
---|
282 | #b_singleton:: bool true if singleton
|
---|
283 | #ct_name:: Symbol
|
---|
284 | #global_ct_name:: string
|
---|
285 | #sig_name:: string
|
---|
286 | #ep_name:: string
|
---|
287 | #func_name:: string
|
---|
288 | #func_global_name:: string
|
---|
289 | #func_type:: class derived from Type
|
---|
290 | def gen_ep_func_body( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
|
---|
291 | # puts "generate ep_func for #{ct_name}"
|
---|
292 |
|
---|
293 | #
|
---|
294 | # 拡張サービスコール呼出し側の関数生成
|
---|
295 | #
|
---|
296 | # 完成形のイメージ
|
---|
297 | #
|
---|
298 | # ER_UINT
|
---|
299 | # eThroughEntry_write(CELLIDX idx, const char* buffer, uint_t length)
|
---|
300 | # {
|
---|
301 | # ER_UINT retval;
|
---|
302 | # tHRPSVCPlugin_<Sig>SVCCaller_<Cell>_<Entry>_CB *p_cellcb;
|
---|
303 | # if( VALID_IDX( idx ) ){
|
---|
304 | # p_cellcb = tHRPSVCPlugin_<Sig>SVCBody_<Cell>_<Entry>_GET_CELLCB(idx);
|
---|
305 | # }else{
|
---|
306 | # /* エラー処理コードをここに記述 */
|
---|
307 | # }
|
---|
308 | #
|
---|
309 | # retval = (ER_UINT)cal_svc( TFN_TECSGEN_ORIGIN + svcid,
|
---|
310 | # (intptr_t)par1, (intptr_t)par2, 0, 0, 0 );
|
---|
311 | #
|
---|
312 | # return retval;
|
---|
313 | # }
|
---|
314 |
|
---|
315 | if ! func_type.get_type.kind_of?( VoidType ) then
|
---|
316 | file.print( " #{func_type.get_type_str} retval;\n" )
|
---|
317 | end
|
---|
318 |
|
---|
319 | # p "celltype_name, sig_name, func_name, func_global_name"
|
---|
320 | # p "#{ct_name}, #{sig_name}, #{func_name}, #{func_global_name}"
|
---|
321 |
|
---|
322 | delim = ""
|
---|
323 | if ! func_type.get_type.kind_of?( VoidType ) then
|
---|
324 | file.print( " retval = (#{func_type.get_type_str})" )
|
---|
325 | else
|
---|
326 | file.print( " " )
|
---|
327 | end
|
---|
328 |
|
---|
329 | #file.print( "#{@call_port_name}_#{func_name}(" )
|
---|
330 | SVCManage.set_func_id( "#{@ct_name_body}_#{func_name}" )
|
---|
331 | svcid = SVCManage.get_func_id( "#{@ct_name_body}_#{func_name}" )
|
---|
332 | #file.print( "cal_svc( #{@ct_name_body}_#{func_name}" )
|
---|
333 | file.print( "cal_svc( TFN_TECSGEN_ORIGIN + #{svcid.to_s}" )
|
---|
334 |
|
---|
335 | # if ( ! b_singleton ) then
|
---|
336 | # file.print( " tecs_this" )
|
---|
337 | # delim = ","
|
---|
338 | # end
|
---|
339 |
|
---|
340 | i = 0
|
---|
341 | passed_param = {}
|
---|
342 | params.each{ |param|
|
---|
343 | delim = ","
|
---|
344 | file.printf( "#{delim} (intptr_t)#{param.get_name}" )
|
---|
345 | passed_param[i] = param.get_name
|
---|
346 | i += 1
|
---|
347 | }
|
---|
348 |
|
---|
349 | while(i < NUM_SVC_ARG_MAX) do
|
---|
350 | delim = ","
|
---|
351 | file.printf( "#{delim} 0" )
|
---|
352 | passed_param[i] = "par#{i+1}"
|
---|
353 | i += 1
|
---|
354 | end
|
---|
355 |
|
---|
356 | file.print( " );\n\n" )
|
---|
357 |
|
---|
358 | if ! func_type.get_type.kind_of?( VoidType ) then
|
---|
359 | file.print( " return retval;\n" )
|
---|
360 | end
|
---|
361 |
|
---|
362 | #
|
---|
363 | # 拡張サービスコール本体側の関数生成
|
---|
364 | #
|
---|
365 | # 完成形のイメージ
|
---|
366 | #
|
---|
367 | # ER_UINT
|
---|
368 | # eThroughEntry_write(CELLIDX idx, const char* buffer, uint_t length)
|
---|
369 | # {
|
---|
370 | # ER_UINT retval;
|
---|
371 | # tHRPSVCPlugin_<Sig>SVCBody_<Cell>_<Entry>_CB *p_cellcb;
|
---|
372 | # if( VALID_IDX( idx ) ){
|
---|
373 | # p_cellcb = tHRPSVCPlugin_<Sig>SVCBody_<Cell>_<Entry>_GET_CELLCB(idx);
|
---|
374 | # }else{
|
---|
375 | # /* エラー処理コードをここに記述 */
|
---|
376 | # }
|
---|
377 | #
|
---|
378 | # retval = (ER_UINT)cal_svc( TFN_TECSGEN_ORIGIN + svcid,
|
---|
379 | # (intptr_t)par1, (intptr_t)par2, 0, 0, 0 );
|
---|
380 | #
|
---|
381 | # return retval;
|
---|
382 | # }
|
---|
383 | file2 = AppFile.open( "#{$gen}/#{@ct_name_body}.c" )
|
---|
384 | if @b_printed_include_stdint == false then
|
---|
385 | file2.print <<EOT
|
---|
386 | #ifndef SIZE_MAX
|
---|
387 | #define SIZE_MAX (~0UL)
|
---|
388 | #endif
|
---|
389 |
|
---|
390 | EOT
|
---|
391 | @b_printed_include_stdint = true
|
---|
392 | end
|
---|
393 |
|
---|
394 | if func_type.get_type.kind_of?( VoidType ) then
|
---|
395 | retval_assign = ""
|
---|
396 | else
|
---|
397 | retval_assign = "retval = (ER_UINT)"
|
---|
398 | end
|
---|
399 |
|
---|
400 | file2.print <<EOT
|
---|
401 | /* HRPSVC0006 */
|
---|
402 | ER_UINT
|
---|
403 | #{@ct_name_body}_#{func_name}(intptr_t #{passed_param[0]}, intptr_t #{passed_param[1]}, intptr_t #{passed_param[2]}, intptr_t #{passed_param[3]}, intptr_t #{passed_param[4]}, ID cdmid)
|
---|
404 | {
|
---|
405 | ER_UINT retval = E_OK;
|
---|
406 |
|
---|
407 | EOT
|
---|
408 |
|
---|
409 | #
|
---|
410 | # エラーチェック処理の生成
|
---|
411 | #
|
---|
412 |
|
---|
413 | #
|
---|
414 | # 呼出し元ドメインのチェック
|
---|
415 | # * private method: gen_caller_check_code参照
|
---|
416 | #
|
---|
417 | generated_check_code = gen_caller_check_code(func_name)
|
---|
418 | check_code = generated_check_code["check_code"]
|
---|
419 | user_cannot_callable = generated_check_code["user_cannot_callable"]
|
---|
420 |
|
---|
421 | #
|
---|
422 | # パラメータにポインタが存在する場合,呼出し元タスクに対する
|
---|
423 | # アクセス権のチェック処理を出力する
|
---|
424 | # ※ cdmidがカーネルドメイン(拡張サービスコール呼出し中のユーザ
|
---|
425 | # ドメインを含む)であればprb_memの処理をスキップし,初段の
|
---|
426 | # 拡張サービスコールのみprb_memを呼出し元タスクに発行する
|
---|
427 | #
|
---|
428 | num = 0
|
---|
429 | params.each{ |param|
|
---|
430 | if param.get_declarator.get_ptr_level > 0 then
|
---|
431 | align_check_str = "!ALIGN_TYPE(#{passed_param[num]}, #{param.get_type.get_referto.get_type_str}) || "
|
---|
432 |
|
---|
433 | if param.get_type.get_referto.kind_of?(IntType) then
|
---|
434 | case param.get_type.get_referto.get_bit_size
|
---|
435 | when -11, -1, 8 # char, char_t, int8_t (無符号含む)
|
---|
436 | #
|
---|
437 | # charデータの場合,ALIGN_TYPEは必ずTRUE
|
---|
438 | # となるので,エラーチェックを省略
|
---|
439 | # char型の@bit_sizeは-11
|
---|
440 | # tecsgen/tecslib/core/types.rbを参照
|
---|
441 | #
|
---|
442 | align_check_str = ""
|
---|
443 | end
|
---|
444 | end
|
---|
445 | if param.get_direction == :IN then
|
---|
446 | #
|
---|
447 | # 入力([in])のポインタパラメータは,呼出し元タスクに
|
---|
448 | # TPM_READ(読出し可能)のアクセス権が必要
|
---|
449 | #
|
---|
450 | # 二重ポインタが不可のため、size_is と string が同時に設定されることはない
|
---|
451 | prb_func = "prb_mem"
|
---|
452 | if param.get_size then
|
---|
453 | size_str = param.get_size.to_s
|
---|
454 | elsif param.get_string == -1 then
|
---|
455 | size_str = "SIZE_MAX"
|
---|
456 | prb_func = "prb_str"
|
---|
457 | elsif param.get_string then
|
---|
458 | size_str = param.get_string.to_s
|
---|
459 | prb_func = "prb_str"
|
---|
460 | else
|
---|
461 | size_str = "1"
|
---|
462 | end
|
---|
463 | check_code.concat <<EOT
|
---|
464 | /* HRPSVC0007 */
|
---|
465 | if (#{align_check_str}#{prb_func}((void *)#{passed_param[num]}, sizeof(#{param.get_type.get_referto.get_type_str}) * (#{size_str}), TSK_SELF, TPM_READ) != E_OK) {
|
---|
466 | return E_MACV;
|
---|
467 | }
|
---|
468 | EOT
|
---|
469 |
|
---|
470 | elsif param.get_direction == :OUT || param.get_direction == :INOUT then
|
---|
471 | #
|
---|
472 | # 出力([out])のポインタパラメータは,呼出し元タスクに
|
---|
473 | # TPM_WRITE(書込み可能)のアクセス権が必要
|
---|
474 | #
|
---|
475 | prb_func = "prb_mem"
|
---|
476 | if param.get_size then
|
---|
477 | size_str = param.get_size.to_s
|
---|
478 | elsif param.get_string then # 引数なしの string はない
|
---|
479 | size_str = param.get_string.to_s
|
---|
480 | # prb_func = "prb_str" # out, inout の場合、必ず領域を確保する. prb_mem を用いる
|
---|
481 | else
|
---|
482 | size_str = "1"
|
---|
483 | end
|
---|
484 | check_code.concat <<EOT
|
---|
485 | /* HRPSVC0008 */
|
---|
486 | if (#{align_check_str}#{prb_func}((void *)#{passed_param[num]}, sizeof(#{param.get_type.get_referto.get_type_str}) * (#{size_str}), TSK_SELF, TPM_WRITE) != E_OK) {
|
---|
487 | return E_MACV;
|
---|
488 | }
|
---|
489 | EOT
|
---|
490 |
|
---|
491 | end
|
---|
492 | end
|
---|
493 | num += 1
|
---|
494 | }
|
---|
495 |
|
---|
496 | #
|
---|
497 | # 呼出し元がカーネルドメインのみ許可されている場合,
|
---|
498 | # すべてのユーザドメインからの呼出しに対し,E_OACVを返す
|
---|
499 | #
|
---|
500 | if user_cannot_callable
|
---|
501 | check_code = "\t\treturn E_OACV;"
|
---|
502 | end
|
---|
503 |
|
---|
504 | if check_code != ""
|
---|
505 | #
|
---|
506 | # 呼出し元がカーネルドメインの場合,アクセス権のチェック
|
---|
507 | # 処理をスキップさせる
|
---|
508 | #
|
---|
509 | file2.print <<eot
|
---|
510 | if (cdmid != TDOM_KERNEL) {
|
---|
511 | #{check_code}
|
---|
512 | }
|
---|
513 | eot
|
---|
514 | end
|
---|
515 |
|
---|
516 | #
|
---|
517 | # 拡張サービスコール本体(本来の受け口関数)を呼び出す
|
---|
518 | #
|
---|
519 | file2.print" #{retval_assign}#{@call_port_name}_#{func_name}("
|
---|
520 |
|
---|
521 | delim = ""
|
---|
522 | num = 0
|
---|
523 | params.each{ |param|
|
---|
524 | file2.print "#{delim}"
|
---|
525 | delim = ", "
|
---|
526 | file2.print "(#{param.get_type.get_type_str})"
|
---|
527 | file2.print passed_param[num]
|
---|
528 | file2.print param.get_type.get_type_str_post
|
---|
529 | num += 1
|
---|
530 | }
|
---|
531 |
|
---|
532 | file2.print ");\n"
|
---|
533 |
|
---|
534 | file2.print "\n return retval;\n"
|
---|
535 | file2.print "}\n\n"
|
---|
536 |
|
---|
537 | file2.close
|
---|
538 |
|
---|
539 | #
|
---|
540 | # 拡張サービスコールの登録
|
---|
541 | #
|
---|
542 | file2 = AppFile.open( "#{$gen}/tecsgen.cfg" )
|
---|
543 | file2.print "\n/* Generated by HRPSVCPlugin */\n\n"
|
---|
544 | file2.print <<EOT
|
---|
545 | /* HRPSVC0009 */
|
---|
546 | KERNEL_DOMAIN{
|
---|
547 | DEF_SVC( TFN_TECSGEN_ORIGIN + #{svcid.to_s}, { TA_NULL, #{@ct_name_body}_#{func_name}, SSZ_#{func_global_name} } );
|
---|
548 | }
|
---|
549 | EOT
|
---|
550 | file2.close
|
---|
551 |
|
---|
552 | #
|
---|
553 | # 拡張サービスコール登録に必要な情報をヘッダに出力
|
---|
554 | # - 拡張サービスコール呼出し時のチェックで使用するスタックサイズを出力
|
---|
555 | # - 拡張サービスコールとして登録する関数名のextern宣言を出力
|
---|
556 | #
|
---|
557 | file2 = AppFile.open( "#{$gen}/#{@ct_name_body}_factory.h" )
|
---|
558 | file2.print "\n/* Generated by HRPSVCPlugin */\n\n"
|
---|
559 | file2.print <<EOT
|
---|
560 | /* HRPSVC0010 */
|
---|
561 | #ifndef SSZ_#{func_global_name}
|
---|
562 | #define SSZ_#{func_global_name} DefaultExtsvcStackSize
|
---|
563 | #endif /* SSZ_#{func_global_name} */
|
---|
564 |
|
---|
565 | /* HRPSVC0011 */
|
---|
566 | extern ER_UINT #{@ct_name_body}_#{func_name}(intptr_t par1, intptr_t par2, intptr_t par3, intptr_t par4, intptr_t par5, ID cdmid);
|
---|
567 | EOT
|
---|
568 | file2.close
|
---|
569 | end
|
---|
570 |
|
---|
571 | def get_callee_cell
|
---|
572 | return @callee_cell
|
---|
573 | end
|
---|
574 |
|
---|
575 | def get_caller_cell
|
---|
576 | return @caller_cell
|
---|
577 | end
|
---|
578 |
|
---|
579 | def get_callee_ep_name
|
---|
580 | return @join.get_port_name
|
---|
581 | end
|
---|
582 |
|
---|
583 | private
|
---|
584 | #
|
---|
585 | # 拡張サービスコール本体における,呼出し元チェックのコードを
|
---|
586 | # 出力する
|
---|
587 | # gen_ep_func_body からのみ呼び出される
|
---|
588 | # 引数: 対象の関数名
|
---|
589 | # 返り値: 下記のハッシュ
|
---|
590 | # {"check_code"=>出力するエラーチェックコード,
|
---|
591 | # "user_cannot_callable"=>ユーザドメインが呼出し不可能かどうかのフラグ}
|
---|
592 | #
|
---|
593 | def gen_caller_check_code(func_name)
|
---|
594 | dbgPrint "gen_caller_check_code(func_name): #{@callee_cell.get_name}\n"
|
---|
595 | #
|
---|
596 | # エラーチェック処理
|
---|
597 | #
|
---|
598 | check_code = ""
|
---|
599 | user_cannot_callable = false
|
---|
600 | all_domain_callable = false
|
---|
601 | caller_unrestricted = false
|
---|
602 |
|
---|
603 | #
|
---|
604 | # 呼出し元ドメインのチェック処理
|
---|
605 | # callable_domains: 拡張サービスコールを呼出し可能なドメインのリスト
|
---|
606 | # - 無所属のセルから結合されている場合,すべてのセルに対して,
|
---|
607 | # callable?をチェックし,呼出し可能なすべてのドメインを返す
|
---|
608 | # - 無所属以外のセルから結合されている場合,そのセルに対して
|
---|
609 | # callable?をチェックし,呼出し可能であれば,そのドメインを返す
|
---|
610 | #
|
---|
611 | callable_domains = []
|
---|
612 | @@generated_celltype[ @ct_name_body ].each { |svcplugin|
|
---|
613 | if svcplugin.get_caller_cell.get_region.get_domain_root.get_domain_type.get_option == "OutOfDomain"
|
---|
614 | # 無所属かつ active な場合も、restrict に従う
|
---|
615 | # if svcplugin.get_caller_cell.get_celltype.is_active?
|
---|
616 | # #
|
---|
617 | # # 無所属かつactiveなセルは、TECSから存在が認識されていないのを
|
---|
618 | # # 含む任意のドメインから呼び出される可能性も存在する
|
---|
619 | # #
|
---|
620 | # caller_unrestricted = true
|
---|
621 | # else
|
---|
622 | # #
|
---|
623 | # # 無所属から接続されている場合は,すべてのセルの
|
---|
624 | # # restrictをチェック
|
---|
625 | # #
|
---|
626 | # Cell.get_cell_list2.each { |cell|
|
---|
627 | # if cell.callable?(svcplugin.get_callee_cell, svcplugin.get_callee_ep_name, func_name)
|
---|
628 | # callable_domains << cell.get_region.get_domain_root
|
---|
629 | # end
|
---|
630 | # }
|
---|
631 | # print "callable_domains: "
|
---|
632 | # callable_domains.each{ |dm| print dm.get_name, " " }
|
---|
633 | # print "\n"
|
---|
634 | # end
|
---|
635 |
|
---|
636 | # restrict 指定がある場合には、それに従う。さもなければ、チェックしない
|
---|
637 | callable_domains = @callee_cell.get_restricted_regions( get_callee_ep_name, func_name )
|
---|
638 | if callable_domains == nil then
|
---|
639 | caller_unrestricted = true
|
---|
640 | end
|
---|
641 | # print "restrict_list: "
|
---|
642 | # delim = ""
|
---|
643 | # callable_domains.each{ |domain|
|
---|
644 | # print delim, domain
|
---|
645 | # delim = ", "
|
---|
646 | # }
|
---|
647 | # print "\n"
|
---|
648 |
|
---|
649 | elsif svcplugin.get_caller_cell.callable?( svcplugin.get_callee_cell, svcplugin.get_callee_ep_name, func_name )
|
---|
650 | #
|
---|
651 | # 特定のドメインから接続されている場合は,呼出し元セルの
|
---|
652 | # restrictをチェック
|
---|
653 | #
|
---|
654 | callable_domains << svcplugin.get_caller_cell.get_region.get_domain_root
|
---|
655 | else
|
---|
656 | #
|
---|
657 | # 無所属から結合されておらず,特定の呼出し元ドメインにアクセス権
|
---|
658 | # がない場合,callable_domainsは空となる
|
---|
659 | #
|
---|
660 | # pp "#{svcplugin.get_caller_cell.get_name} cannot call #{svcplugin.get_callee_cell.get_name}_#{svcplugin.get_callee_ep_name}_#{func_name}"
|
---|
661 | end
|
---|
662 | }
|
---|
663 |
|
---|
664 | if caller_unrestricted
|
---|
665 | # pp "caller_unrestricted: #{@ct_name_body}"
|
---|
666 | return {"check_code"=>"", "user_cannot_callable"=>false}
|
---|
667 | end
|
---|
668 |
|
---|
669 | #
|
---|
670 | # 重複を削除
|
---|
671 | #
|
---|
672 | callable_domains.uniq!
|
---|
673 | #
|
---|
674 | # 無所属に対するドメインチェックは実施しない
|
---|
675 | # カーネルドメインに対するドメインチェックは実施しない
|
---|
676 | #
|
---|
677 | callable_domains = callable_domains.select { |domain|
|
---|
678 | ((domain.get_domain_type.get_option != "OutOfDomain") && \
|
---|
679 | (domain.get_domain_type.get_option != "kernel"))
|
---|
680 | }
|
---|
681 | # pp "callable_domains"
|
---|
682 | # pp callable_domains.map{|domain| domain.get_name }
|
---|
683 | #
|
---|
684 | # すべてのユーザドメインから呼出し可能な場合,ドメインチェックは
|
---|
685 | # 実施しない
|
---|
686 | #
|
---|
687 | all_domain_regions = DomainType.get_domain_regions[:HRP].select { |reg|
|
---|
688 | ((reg.get_domain_type.get_option != "OutOfDomain") && \
|
---|
689 | (reg.get_domain_type.get_option != "kernel"))
|
---|
690 |
|
---|
691 | }
|
---|
692 | # pp "all domains"
|
---|
693 | # pp all_domain_regions.map {|reg| reg.get_name}
|
---|
694 | if all_domain_regions.all? {|reg| callable_domains.include?(reg)}
|
---|
695 | all_domain_callable = true
|
---|
696 | end
|
---|
697 |
|
---|
698 | #
|
---|
699 | # 呼出し元ドメインのチェック処理本体の生成
|
---|
700 | #
|
---|
701 | if callable_domains.length == 0
|
---|
702 | dbgPrint "callable_domain.length = 0\n"
|
---|
703 | #
|
---|
704 | # ユーザドメインから呼出し不可能な場合は
|
---|
705 | # 個別のエラーチェックはせず,問答無用でE_OACVを返す
|
---|
706 | #
|
---|
707 | user_cannot_callable = true
|
---|
708 | elsif callable_domains.length == 1
|
---|
709 | dbgPrint "callable_domain.length = 1\n"
|
---|
710 | #
|
---|
711 | # 呼出し可能なユーザドメインが単一の場合は
|
---|
712 | # cdmid != <domain名> の形式でチェックする
|
---|
713 | #
|
---|
714 | check_code += "\t/* HRPSVC0012.1 */\n"
|
---|
715 | check_code += "\tif (cdmid != #{callable_domains[0].get_name}) {\n"
|
---|
716 | elsif callable_domains.length > 1 && !all_domain_callable
|
---|
717 | dbgPrint "callable_domain.length > 1 && not all_domains \n"
|
---|
718 | #
|
---|
719 | # 呼出し可能なユーザドメインが複数の場合は
|
---|
720 | # TACP(cdmid) & (TACP(<domain名>) | ...) != 0U
|
---|
721 | # の形式でチェックする
|
---|
722 | #
|
---|
723 | check_code += "\t/* HRPSVC0012.2 */\n"
|
---|
724 | check_code += "\tif((TACP(cdmid) & ("
|
---|
725 | check_code += (callable_domains.map { |domain| "TACP(#{domain.get_name})"}).join("|")
|
---|
726 | check_code += ")) != 0U) {\n"
|
---|
727 | else
|
---|
728 | dbgPrint "callable_all_domains\n"
|
---|
729 | end
|
---|
730 | if check_code != ""
|
---|
731 | #
|
---|
732 | # 呼出し可能なユーザドメインのチェックがある場合は
|
---|
733 | # エラーコードを返すためのコードを出力する
|
---|
734 | #
|
---|
735 | check_code += <<EOS
|
---|
736 | /* HRPSVC0013 */
|
---|
737 | return E_OACV;
|
---|
738 | }
|
---|
739 | EOS
|
---|
740 | end
|
---|
741 |
|
---|
742 | return {"check_code"=>check_code, "user_cannot_callable"=>user_cannot_callable}
|
---|
743 | end
|
---|
744 |
|
---|
745 | #---------------------------------------------------------#
|
---|
746 | #=== シグニチャのチェック
|
---|
747 | def check_signature signature
|
---|
748 | signature.get_function_head_array.each{ |fh|
|
---|
749 | type = fh.get_return_type
|
---|
750 | check_return_type signature, fh, type
|
---|
751 | if fh.get_paramlist.get_items.length > NUM_SVC_ARG_MAX then
|
---|
752 | cdl_error( "HSV0005 $1.$2: # of parameter more than #{NUM_SVC_ARG_MAX}", signature.get_name, fh.get_name )
|
---|
753 | end
|
---|
754 | fh.get_paramlist.get_items.each{ |param|
|
---|
755 | check_param signature, fh, param
|
---|
756 | }
|
---|
757 | }
|
---|
758 | end
|
---|
759 | #=== 戻り値の型のチェック
|
---|
760 | # ER, ER_UINT は推奨される型
|
---|
761 | # 整数、ブール、void は可能、他は不可
|
---|
762 | def check_return_type signature, fh, type
|
---|
763 | ot = type.get_original_type
|
---|
764 | if( type.get_type_str == "ER" || type.get_type_str == "ER_UINT" ) then
|
---|
765 | # OK!
|
---|
766 | elsif ot.kind_of?( IntType ) || ot.kind_of?( VoidType ) || ot.kind_of?( BoolType ) then
|
---|
767 | cdl_warning( "HSW0001 $1.$2: $3 return type cannot get access violation error", signature.get_name, fh.get_name, type.get_type_str.downcase )
|
---|
768 | check_intptr "#{signature.get_name}.#{fh.get_name} return type", type
|
---|
769 | else
|
---|
770 | cdl_error( "HSV0001 $1.$2 return type $3 cannot be used", signature.get_name, fh.get_name, type.get_type_str.to_s+type.get_type_str_post.to_s )
|
---|
771 | end
|
---|
772 | end
|
---|
773 | #=== 引数の型のチェック
|
---|
774 | def check_param signature, fh, param
|
---|
775 | type = param.get_type
|
---|
776 | ot = type.get_original_type
|
---|
777 | dir = param.get_direction
|
---|
778 | case dir
|
---|
779 | when :IN
|
---|
780 | if ot.kind_of?( IntType ) || ot.kind_of?( BoolType ) then
|
---|
781 | # OK!
|
---|
782 | check_intptr "#{signature.get_name}.#{fh.get_name}.#{param.get_name}", type
|
---|
783 | elsif ot.kind_of? PtrType then
|
---|
784 | check_ptr signature, fh, param, dir
|
---|
785 | else
|
---|
786 | cdl_error( "HSV0002 $1.$2.$3 $4 param type cannot be used", signature.get_name, fh.get_name, param.get_name, type.get_type_str.to_s+type.get_type_str_post.to_s )
|
---|
787 | end
|
---|
788 | when :OUT, :INOUT
|
---|
789 | if ot.kind_of? PtrType then
|
---|
790 | check_ptr signature, fh, param, dir
|
---|
791 | else
|
---|
792 | # error
|
---|
793 | end
|
---|
794 | when :SEND, :RECEIVE
|
---|
795 | cdl_error( "HSV0008 $1.$2.$3 param direction '$4' cannot be used", signature.get_name, fh.get_name, param.get_name, param.get_direction.to_s.downcase )
|
---|
796 | end
|
---|
797 | end
|
---|
798 | def check_ptr signature, fh, param, dir
|
---|
799 | type = param.get_type.get_referto
|
---|
800 | ot = type.get_original_type
|
---|
801 | if ot.kind_of?( IntType ) || ot.kind_of?( BoolType ) || ot.kind_of?( FloatType ) then
|
---|
802 | # OK!
|
---|
803 | check_intptr "#{signature.get_name}.#{fh.get_name}.#{param.get_name}", type
|
---|
804 | elsif ot.kind_of? PtrType then
|
---|
805 | cdl_error( "HSV0003 $1.$2.$3 multi-pointer type cannot be used", signature.get_name, fh.get_name, param.get_name, type.get_type_str.to_s+type.get_type_str_post.to_s )
|
---|
806 | elsif ot.kind_of? StructType then
|
---|
807 | check_struct signature, fh, param
|
---|
808 | else
|
---|
809 | cdl_error( "HSV0004 $1.$2.$3 $4 type cannot be used", signature.get_name, fh.get_name, param.get_name, type.get_type_str.to_s+type.get_type_str_post.to_s )
|
---|
810 | end
|
---|
811 | if ( dir == :OUT || dir == :INOUT) && param.get_string == -1 then
|
---|
812 | cdl_error( "HSV0009 $1.$2.$3 string argment is necessary for out/inout parameter", signature.get_name, fh.get_name, param.get_name )
|
---|
813 | end
|
---|
814 | end
|
---|
815 | def check_struct signature, fh, param
|
---|
816 | type = param.get_type.get_referto
|
---|
817 | ot = type.get_original_type
|
---|
818 | ot.get_members_decl.get_items.each{ |decl|
|
---|
819 | type = decl.get_type
|
---|
820 | ot = type.get_original_type
|
---|
821 | if ot.kind_of?( IntType ) || ot.kind_of?( BoolType ) || ot.kind_of?( FloatType ) then
|
---|
822 | # OK!
|
---|
823 | check_intptr "#{signature.get_name}.#{fh.get_name}.#{param.get_name}.#{decl.get_name} member", type
|
---|
824 | else
|
---|
825 | dbgPrint "struct member #{decl.get_name} #{type} #{decl.get_type} #{decl.get_type.get_original_type}\n"
|
---|
826 | if( decl.get_type.get_original_type.kind_of? ArrayType ) then
|
---|
827 | dbgPrint "member array type #{decl.get_type.get_original_type.get_type} #{decl.get_type.get_original_type.get_type.get_original_type}\n"
|
---|
828 | check_struct_member_array signature, fh, param, decl
|
---|
829 | else
|
---|
830 | cdl_error( "HSV0006 $1.$2.$3 $4 type cannot be used as struct member", signature.get_name, fh.get_name, param.get_name, type.get_type_str.to_s+type.get_type_str_post.to_s )
|
---|
831 | end
|
---|
832 | end
|
---|
833 | }
|
---|
834 | end
|
---|
835 | def check_struct_member_array signature, fh, param, member_decl
|
---|
836 | # p "check_struct_member_array: #{member_decl.get_type.get_type_str}"
|
---|
837 | type = member_decl.get_type.get_type
|
---|
838 | ot = type.get_original_type
|
---|
839 | if ot.kind_of?( IntType ) || ot.kind_of?( BoolType ) || ot.kind_of?( FloatType ) then
|
---|
840 | # OK!
|
---|
841 | check_intptr "#{signature.get_name}.#{fh.get_name}.#{param.get_name}.#{member_decl.get_name} member", type
|
---|
842 | else
|
---|
843 | cdl_error( "HSV0007 $1.$2.$3 $4 type cannot be used as struct member", signature.get_name, fh.get_name, param.get_name, type.get_type_str.to_s+type.get_type_str_post )
|
---|
844 | end
|
---|
845 | end
|
---|
846 | def check_intptr msg, type
|
---|
847 | dbgPrint "check_intptr IN\n"
|
---|
848 | t = type
|
---|
849 | while( t.kind_of? DefinedType )
|
---|
850 | dbgPrint "check_intptr #{msg} #{t.get_type_str} #{t.get_original_type.get_type_str}\n"
|
---|
851 | tstr = t.get_type_str
|
---|
852 | tstr.sub!( /const /, "" )
|
---|
853 | tstr.sub!( /volatile /, "" )
|
---|
854 | if tstr == "intptr_t" || tstr == "uintptr_t" then
|
---|
855 | cdl_info( "HSI0001 $1 type '$2' not checked by plugin", msg, type.get_type_str )
|
---|
856 | end
|
---|
857 | t = t.get_type
|
---|
858 | end
|
---|
859 | end
|
---|
860 | end
|
---|
861 |
|
---|